neo3 1.3.0

Production-ready Rust SDK for Neo N3 blockchain with high-level API, unified error handling, and enterprise features
Documentation
use ethers::providers::Middleware;
use ethers::signers::{LocalWallet, Signer, WalletError};
use ethers::types::{TransactionRequest, H160 as EthersH160, U256};
use std::str::FromStr;

use crate::neo_clients::JsonRpcProvider;
use crate::neo_x::evm::provider::NeoXProvider;
use crate::neo_x::evm::transaction::NeoXTransaction;

/// Neo X EVM Wallet for managing accounts and signing transactions on Neo X.
/// This wraps an ethers-rs `LocalWallet` to provide seamless integration.
#[derive(Debug, Clone)]
pub struct NeoXWallet {
	inner: LocalWallet,
}

impl NeoXWallet {
	/// Creates a new Neo X wallet from a hex-encoded private key string
	pub fn from_private_key(hex_key: &str) -> Result<Self, WalletError> {
		let wallet = LocalWallet::from_str(hex_key)?;
		Ok(Self { inner: wallet })
	}

	/// Creates a new Neo X wallet from randomly generated bytes
	pub fn create_random() -> Self {
		// Use ethers-rs's bundled rand instance to avoid version conflicts
		let mut rng = ethers::core::rand::thread_rng();
		let wallet = LocalWallet::new(&mut rng);
		Self { inner: wallet }
	}

	/// Gets the EVM address associated with this wallet
	pub fn address(&self) -> EthersH160 {
		self.inner.address()
	}

	/// Returns the underlying ethers-rs wallet
	pub fn inner_wallet(&self) -> &LocalWallet {
		&self.inner
	}
}

/// A wrapper to easily send EVM transactions on Neo X using a NeoXWallet and NeoXProvider.
pub struct NeoXClient<'a, P: JsonRpcProvider> {
	pub wallet: NeoXWallet,
	pub provider: NeoXProvider<'a, P>,
}

impl<'a, P: JsonRpcProvider + 'static> NeoXClient<'a, P> {
	/// Creates a new Neo X EVM client
	pub fn new(wallet: NeoXWallet, provider: NeoXProvider<'a, P>) -> Self {
		Self { wallet, provider }
	}

	/// Gets the balance of the wallet's address on Neo X
	pub async fn get_balance(&self) -> Result<U256, String> {
		let evm = self.provider.evm_provider().ok_or("No EVM provider configured")?;
		let address = self.wallet.address();
		evm.get_balance(address, None).await.map_err(|e| e.to_string())
	}

	/// Sends a `NeoXTransaction` using the configured wallet and provider
	pub async fn send_transaction(
		&self,
		tx: NeoXTransaction,
	) -> Result<ethers::types::TransactionReceipt, String> {
		let evm = self.provider.evm_provider().ok_or("No EVM provider configured")?;

		// Create a SignerMiddleware combining the provider and the wallet
		let chain_id = self.provider.chain_id().await.map_err(|e| e.to_string())?;
		let signer = self.wallet.inner.clone().with_chain_id(chain_id);

		let client = ethers::middleware::SignerMiddleware::new(evm, signer);

		let req: TransactionRequest = tx.into();

		let pending_tx = client.send_transaction(req, None).await.map_err(|e| e.to_string())?;

		let receipt = pending_tx
			.await
			.map_err(|e| e.to_string())?
			.ok_or("Transaction dropped from mempool")?;

		Ok(receipt)
	}
}