OpenPay (1 crate, 2174 LOC, 14 tests)
op-payouts Multi-rail payout engine. Visa Direct, Mastercard Send,
ACH credits (NACHA), Fedwire + SWIFT MT103 + ISO 20022
pacs.008, SEPA SCT + SCT Inst (mod-97 IBAN), UK FPS,
FedNow, RTP, PayPal, Wise. Crypto: USDC/USDT on
ETH/Polygon/Base/Solana + BTC + Lightning with real
ERC-20 transfer(address,uint256) calldata. Offline-pure
drivers (emit wire payloads — operators transmit).
Smart Byte (1 crate, 2605 LOC, 38 tests)
smart-byte-nostr Nostr adapter. NIP-01 canonical event id + BIP-340
Schnorr sign/verify; from-scratch bech32 + NIP-19 TLV
(npub/nsec/note/nprofile/nevent/nrelay); NIP-04 legacy
AES-256-CBC DMs; NIP-44 v2 HKDF-SHA256→ChaCha20+HMAC
with bucketed padding; NIP-17 gift-wrap (kind 1059) +
seal (kind 13) + rumor (kind 14); NIP-05/11/13/26/65.
Relay client message vocabulary (REQ/EVENT/CLOSE/AUTH/
EOSE/OK/NOTICE/CLOSED) + in-memory router.
EOC (1 crate, 2024 LOC, 30 tests)
eoc-streaming Token-by-token + tool-call streaming primitives.
SSE framing (data: lines); Anthropic event mapper
(message_start/content_block_*/message_delta/stop/ping);
OpenAI delta mapper; Vercel AI SDK mapper. Bounded-channel
backpressure with watermarks; CancelToken propagation;
Last-Event-ID resumable streams; per-stream joule meter.
Co-Authored-By: Claude Opus 4.7 <[email protected]>
88 lines
2.8 KiB
Rust
88 lines
2.8 KiB
Rust
//! Wise Platform API driver.
|
|
//!
|
|
//! Wise's payout flow is three calls:
|
|
//! 1. `POST /v3/profiles/{profile}/quotes` — quote the FX.
|
|
//! 2. `POST /v1/transfers` — create the transfer against a recipient
|
|
//! id.
|
|
//! 3. `POST /v3/profiles/{profile}/transfers/{id}/payments` — fund.
|
|
//!
|
|
//! The orchestrator only needs the transfer creation body offline; the
|
|
//! quote and funding calls are operator-driven.
|
|
|
|
use serde::Serialize;
|
|
use uuid::Uuid;
|
|
|
|
use crate::error::{Error, Result};
|
|
use crate::payout::{
|
|
BeneficiaryAccount, Payout, PayoutRequest, PayoutResult, PayoutStatus,
|
|
};
|
|
|
|
/// Wise Platform driver.
|
|
#[derive(Clone, Debug, Default)]
|
|
pub struct WiseDriver {
|
|
/// Operator's Wise profile id (numeric, opaque).
|
|
pub profile_id: u64,
|
|
/// Quote id obtained from a prior `POST /v3/profiles/.../quotes`.
|
|
pub quote_uuid: String,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
struct TransferBody<'a> {
|
|
#[serde(rename = "targetAccount")]
|
|
target_account: u64,
|
|
#[serde(rename = "quoteUuid")]
|
|
quote_uuid: &'a str,
|
|
#[serde(rename = "customerTransactionId")]
|
|
customer_transaction_id: &'a str,
|
|
details: TransferDetails<'a>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
struct TransferDetails<'a> {
|
|
reference: &'a str,
|
|
}
|
|
|
|
impl Payout for WiseDriver {
|
|
fn rail(&self) -> &'static str {
|
|
"wise"
|
|
}
|
|
|
|
fn submit(&self, req: &PayoutRequest) -> Result<PayoutResult> {
|
|
let recipient_id = match &req.beneficiary.account {
|
|
BeneficiaryAccount::WiseRecipientId(id) => *id,
|
|
_ => return Err(Error::UnsupportedMethod { rail: "wise" }),
|
|
};
|
|
if !req.amount.is_positive() {
|
|
return Err(Error::LimitViolation {
|
|
rail: "wise",
|
|
detail: "amount must be positive".to_string(),
|
|
});
|
|
}
|
|
let body = TransferBody {
|
|
target_account: recipient_id,
|
|
quote_uuid: &self.quote_uuid,
|
|
customer_transaction_id: &req.idempotency_key,
|
|
details: TransferDetails {
|
|
reference: req.memo.as_deref().unwrap_or(&req.idempotency_key),
|
|
},
|
|
};
|
|
let json = serde_json::to_vec(&body).map_err(|e| Error::DriverValidation(e.to_string()))?;
|
|
Ok(PayoutResult {
|
|
idempotency_key: req.idempotency_key.clone(),
|
|
payout_id: Uuid::now_v7().to_string(),
|
|
status: PayoutStatus::PreparedOffline,
|
|
raw_status: None,
|
|
reason_code: None,
|
|
reason_text: None,
|
|
rail_txn_id: None,
|
|
settled_amount: Some(req.amount),
|
|
wire_payload: Some(json),
|
|
})
|
|
}
|
|
|
|
fn status(&self, _payout_id: &str) -> Result<PayoutResult> {
|
|
Err(Error::DriverValidation(
|
|
"Wise status query requires GET /v1/transfers/{id} via live client".to_string(),
|
|
))
|
|
}
|
|
}
|