use std::cell::RefCell;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
pub struct X402Challenge {
pub to: [u8; 20],
pub value_wei: u128,
pub valid_after: u64,
pub valid_before: u64,
pub nonce: [u8; 32],
}
pub struct X402Payment {
pub from: [u8; 20],
pub signature: [u8; 65],
}
type SignerFut = Pin<Box<dyn Future<Output = Result<X402Payment, String>>>>;
type Signer = Rc<dyn Fn(X402Challenge) -> SignerFut>;
thread_local! {
static SIGNER: RefCell<Option<Signer>> = const { RefCell::new(None) };
}
pub fn install(signer: Signer) {
SIGNER.with(|s| *s.borrow_mut() = Some(signer));
}
pub async fn sign(challenge: X402Challenge) -> Result<X402Payment, String> {
let signer = SIGNER.with(|s| s.borrow().clone());
match signer {
Some(f) => f(challenge).await,
None => Err("no x402 signer installed".into()),
}
}
type RemoteFut = Pin<Box<dyn Future<Output = Result<String, String>>>>;
type RemoteCall = Rc<dyn Fn(String, String) -> RemoteFut>;
thread_local! {
static REMOTE: RefCell<Option<RemoteCall>> = const { RefCell::new(None) };
}
pub fn install_remote_call(route: RemoteCall) {
REMOTE.with(|r| *r.borrow_mut() = Some(route));
}
pub async fn remote_call(target: &str, message: &str) -> Result<String, String> {
let route = REMOTE.with(|r| r.borrow().clone());
match route {
Some(f) => f(target.to_string(), message.to_string()).await,
None => Err("no remote agent route installed".into()),
}
}