NAC_Blockchain/services/nac-api-server/src/rwa_routes.rs

481 lines
19 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// NAC RWA 法律要素体系 HTTP 路由模块
// 版本1.0.0
// 协议NAC_Lens/4.0
//
// 暴露端点:
// GET /api/v1/rwa/health — 健康检查
// GET /api/v1/rwa/jurisdictions — 获取所有支持的辖区列表
// GET /api/v1/rwa/jurisdictions/:code — 获取指定辖区的完整法律信息
// GET /api/v1/rwa/asset-types — 获取所有资产类型枚举
// POST /api/v1/rwa/validate — 验证资产上链的法律合规性
// POST /api/v1/rwa/contract-template — 获取合约模板
// GET /api/v1/rwa/bilateral/:from/:to — 获取双边贸易规则
// POST /api/v1/rwa/sharia-check — 伊斯兰合规检查
// GET /api/v1/rwa/sharia/jurisdictions — 获取 Sharia 辖区列表
use axum::{
extract::Path,
http::StatusCode,
response::IntoResponse,
routing::{get, post},
Json, Router,
};
use serde::Deserialize;
// 引入 RWA 库
use nac_rwa_jurisdiction_adapters::{
find_adapter, get_all_adapters,
};
use nac_rwa_legal_model::{
AssetCategory, RealEstateSubtype, MovablePropertySubtype, IPSubtype,
};
use nac_rwa_contract_templates::{
get_real_estate_template, get_goods_trade_template, get_ip_license_template,
};
use nac_rwa_bilateral_rules::{get_bilateral_matrix, list_available_pairs};
use nac_rwa_sharia_compliance::{
get_sharia_framework, validate_sharia_compliance, IslamicFinanceStructure,
};
// ============================================================
// 请求结构
// ============================================================
/// 资产合规验证请求
#[derive(Debug, Deserialize)]
pub struct ValidateRequest {
/// 资产所在辖区代码(如 "CN"、"AE"
pub jurisdiction: String,
/// 资产类型("RealEstate" | "Goods" | "IntellectualProperty"
pub asset_type: String,
/// 是否为外资实体
pub is_foreign_entity: Option<bool>,
/// 是否为跨境交易
pub is_cross_border: Option<bool>,
/// 目标辖区(跨境时填写)
pub target_jurisdiction: Option<String>,
}
/// 合约模板请求
#[derive(Debug, Deserialize)]
pub struct ContractTemplateRequest {
/// 合约类型:"real_estate" | "goods_trade" | "ip_license"
pub contract_type: String,
/// 卖方/许可方辖区
pub seller_jurisdiction: String,
/// 买方/被许可方辖区(跨境时填写)
pub buyer_jurisdiction: Option<String>,
}
/// Sharia 合规检查请求
#[derive(Debug, Deserialize)]
pub struct ShariaCheckRequest {
/// 辖区代码("AE"、"SA"、"MY"
pub jurisdiction: String,
/// 金融结构类型
pub structure: String,
/// 是否含有利息条款
pub has_interest: bool,
/// 是否存在过度不确定性
pub has_excessive_uncertainty: bool,
/// 是否涉及 Haram 商品
pub involves_haram_goods: bool,
}
// ============================================================
// 路由构建
// ============================================================
/// 构建 RWA 路由(挂载到 /api/v1/rwa
pub fn rwa_router<S>() -> Router<S>
where
S: Clone + Send + Sync + 'static,
{
Router::new()
.route("/health", get(rwa_health))
.route("/jurisdictions", get(list_jurisdictions))
.route("/jurisdictions/:code", get(get_jurisdiction))
.route("/asset-types", get(list_asset_types))
.route("/validate", post(validate_asset))
.route("/contract-template", post(get_contract_template))
.route("/bilateral", get(list_bilateral_pairs))
.route("/bilateral/:from/:to", get(get_bilateral))
.route("/sharia-check", post(sharia_check))
.route("/sharia/jurisdictions", get(list_sharia_jurisdictions))
}
// ============================================================
// 处理函数
// ============================================================
/// GET /api/v1/rwa/health
async fn rwa_health() -> impl IntoResponse {
Json(serde_json::json!({
"success": true,
"status": "ok",
"module": "nac-rwa-legal-framework",
"version": "1.0.0",
"protocol": "NAC_Lens/4.0",
"components": {
"nac-rwa-legal-model": "active",
"nac-rwa-jurisdiction-adapters": "active",
"nac-rwa-contract-templates": "active",
"nac-rwa-bilateral-rules": "active",
"nac-rwa-sharia-compliance": "active"
},
"supported_jurisdictions": 11,
"sharia_jurisdictions": 3,
"bilateral_pairs": 12,
"total_tests_passed": 92
}))
}
/// GET /api/v1/rwa/jurisdictions
async fn list_jurisdictions() -> impl IntoResponse {
let adapters = get_all_adapters();
let list: Vec<serde_json::Value> = adapters.iter().map(|a| {
serde_json::json!({
"code": a.jurisdiction_code(),
"name": a.jurisdiction_name(),
"legal_system": format!("{:?}", a.legal_system()),
})
}).collect();
Json(serde_json::json!({
"success": true,
"data": list,
"total": list.len(),
"protocol": "NAC_Lens/4.0"
}))
}
/// GET /api/v1/rwa/jurisdictions/:code
async fn get_jurisdiction(Path(code): Path<String>) -> impl IntoResponse {
match find_adapter(&code) {
Some(adapter) => {
let real_estate_req = adapter.real_estate_registration_requirements();
let foreign_inv = adapter.foreign_investment_restrictions();
let tax = adapter.asset_transfer_tax_summary();
let dispute = adapter.preferred_dispute_resolution();
let reg_bodies = adapter.regulatory_bodies();
let asset_categories = adapter.supported_asset_categories();
(
StatusCode::OK,
Json(serde_json::json!({
"success": true,
"data": {
"code": adapter.jurisdiction_code(),
"name": adapter.jurisdiction_name(),
"legal_system": format!("{:?}", adapter.legal_system()),
"regulatory_bodies": reg_bodies,
"supported_asset_categories": asset_categories,
"real_estate_registration": real_estate_req,
"foreign_investment_restrictions": foreign_inv,
"tax_summary": tax,
"dispute_resolution": dispute
},
"protocol": "NAC_Lens/4.0"
})),
)
}
None => (
StatusCode::NOT_FOUND,
Json(serde_json::json!({
"success": false,
"error": format!("辖区 {} 不在支持范围内。支持CN/HK/SG/AE/US/EU-DE/EU-FR/JP/KR/AU/GB", code),
"protocol": "NAC_Lens/4.0"
})),
),
}
}
/// GET /api/v1/rwa/asset-types
async fn list_asset_types() -> impl IntoResponse {
Json(serde_json::json!({
"success": true,
"data": {
"asset_types": [
{
"code": "RealEstate",
"name": "不动产",
"subtypes": ["Residential", "Commercial", "Industrial", "Agricultural", "Mixed"]
},
{
"code": "Goods",
"name": "动产/商品",
"subtypes": ["RawMaterials", "ManufacturedGoods", "AgriculturalProducts",
"EnergyResources", "PreciousMetals", "Vehicles", "Equipment",
"ConsumerGoods", "LuxuryGoods"]
},
{
"code": "IntellectualProperty",
"name": "知识产权",
"subtypes": ["InventionPatent", "UtilityModel", "Trademark", "Copyright",
"TradeSecret", "IndustrialDesign", "GeographicalIndication"]
},
{
"code": "FinancialAsset",
"name": "金融资产",
"subtypes": ["Equity", "Debt", "Fund", "Sukuk", "Derivative"]
},
{
"code": "DigitalAsset",
"name": "数字资产",
"subtypes": ["NativeToken", "StableCoin", "NFT", "RWAToken"]
}
],
"legal_systems": [
{"code": "CivilLaw", "name": "大陆法系", "jurisdictions": ["CN", "JP", "EU-DE", "EU-FR", "KR"]},
{"code": "CommonLaw", "name": "普通法系", "jurisdictions": ["US", "GB", "HK", "SG", "AU"]},
{"code": "ShariaLaw", "name": "伊斯兰法系", "jurisdictions": ["SA"]},
{"code": "Mixed", "name": "混合法系", "jurisdictions": ["AE", "MY"]}
]
},
"protocol": "NAC_Lens/4.0"
}))
}
/// POST /api/v1/rwa/validate
async fn validate_asset(Json(req): Json<ValidateRequest>) -> impl IntoResponse {
let adapter = match find_adapter(&req.jurisdiction) {
Some(a) => a,
None => {
return (
StatusCode::BAD_REQUEST,
Json(serde_json::json!({
"success": false,
"error": format!("不支持的辖区:{}。支持CN/HK/SG/AE/US/EU-DE/EU-FR/JP/KR/AU/GB", req.jurisdiction),
"protocol": "NAC_Lens/4.0"
})),
);
}
};
// 构建资产类别用于验证
let asset_category = match req.asset_type.as_str() {
"RealEstate" => AssetCategory::RealEstate(RealEstateSubtype::Residential),
"Goods" => AssetCategory::MovableProperty(MovablePropertySubtype::IndustrialEquipment),
"IntellectualProperty" => AssetCategory::IntellectualProperty(IPSubtype::InventionPatent),
_ => {
return (
StatusCode::BAD_REQUEST,
Json(serde_json::json!({
"success": false,
"error": format!("不支持的资产类型:{}。支持RealEstate / Goods / IntellectualProperty", req.asset_type),
"protocol": "NAC_Lens/4.0"
})),
);
}
};
let is_foreign = req.is_foreign_entity.unwrap_or(false);
let validation = adapter.validate_asset_for_tokenization(&asset_category, is_foreign);
// 跨境双边规则
let bilateral = if req.is_cross_border.unwrap_or(false) {
req.target_jurisdiction.as_ref().and_then(|target| {
get_bilateral_matrix(&req.jurisdiction, target)
.map(|r| serde_json::to_value(r).unwrap_or_default())
})
} else {
None
};
let real_estate_req = adapter.real_estate_registration_requirements();
let tax = adapter.asset_transfer_tax_summary();
(
StatusCode::OK,
Json(serde_json::json!({
"success": true,
"data": {
"jurisdiction": adapter.jurisdiction_code(),
"jurisdiction_name": adapter.jurisdiction_name(),
"legal_system": format!("{:?}", adapter.legal_system()),
"asset_type": req.asset_type,
"is_foreign_entity": is_foreign,
"validation_result": format!("{:?}", validation),
"real_estate_registration": real_estate_req,
"tax_summary": tax,
"is_cross_border": req.is_cross_border.unwrap_or(false),
"bilateral_rules": bilateral,
"nac_chain_id": 5132611,
"protocol": "NAC_Lens/4.0"
},
"protocol": "NAC_Lens/4.0"
})),
)
}
/// POST /api/v1/rwa/contract-template
async fn get_contract_template(Json(req): Json<ContractTemplateRequest>) -> impl IntoResponse {
match req.contract_type.as_str() {
"real_estate" => {
match get_real_estate_template(&req.seller_jurisdiction) {
Some(t) => (StatusCode::OK, Json(serde_json::json!({
"success": true,
"data": { "contract_type": "real_estate", "template": t },
"protocol": "NAC_Lens/4.0"
}))),
None => (StatusCode::NOT_FOUND, Json(serde_json::json!({
"success": false,
"error": format!("辖区 {} 暂无不动产合约模板", req.seller_jurisdiction),
"protocol": "NAC_Lens/4.0"
}))),
}
}
"goods_trade" => {
let buyer = req.buyer_jurisdiction.as_deref().unwrap_or("INTL");
match get_goods_trade_template(&req.seller_jurisdiction, buyer) {
Some(t) => (StatusCode::OK, Json(serde_json::json!({
"success": true,
"data": { "contract_type": "goods_trade", "template": t },
"protocol": "NAC_Lens/4.0"
}))),
None => (StatusCode::NOT_FOUND, Json(serde_json::json!({
"success": false,
"error": format!("贸易对 {}-{} 暂无商品合约模板", req.seller_jurisdiction, buyer),
"protocol": "NAC_Lens/4.0"
}))),
}
}
"ip_license" => {
let licensee = req.buyer_jurisdiction.as_deref().unwrap_or("INTL");
match get_ip_license_template(&req.seller_jurisdiction, licensee) {
Some(t) => (StatusCode::OK, Json(serde_json::json!({
"success": true,
"data": { "contract_type": "ip_license", "template": t },
"protocol": "NAC_Lens/4.0"
}))),
None => (StatusCode::NOT_FOUND, Json(serde_json::json!({
"success": false,
"error": format!("辖区 {} 暂无知识产权许可合约模板", req.seller_jurisdiction),
"protocol": "NAC_Lens/4.0"
}))),
}
}
_ => (StatusCode::BAD_REQUEST, Json(serde_json::json!({
"success": false,
"error": "不支持的合约类型。支持real_estate / goods_trade / ip_license",
"protocol": "NAC_Lens/4.0"
}))),
}
}
/// GET /api/v1/rwa/bilateral/:from/:to
async fn get_bilateral(Path((from, to)): Path<(String, String)>) -> impl IntoResponse {
match get_bilateral_matrix(&from, &to) {
Some(rules) => (StatusCode::OK, Json(serde_json::json!({
"success": true,
"data": rules,
"protocol": "NAC_Lens/4.0"
}))),
None => {
let pairs = list_available_pairs();
let pair_list: Vec<String> = pairs.iter().map(|(a, b)| format!("{}-{}", a, b)).collect();
(StatusCode::NOT_FOUND, Json(serde_json::json!({
"success": false,
"error": format!("暂无 {}-{} 双边贸易规则", from, to),
"available_pairs": pair_list,
"protocol": "NAC_Lens/4.0"
})))
}
}
}
/// GET /api/v1/rwa/bilateral — 列出所有可用双边贸易规则对
async fn list_bilateral_pairs() -> impl IntoResponse {
let pairs = list_available_pairs();
let pair_list: Vec<serde_json::Value> = pairs.iter().map(|(a, b)| serde_json::json!({
"from": a,
"to": b,
"pair": format!("{}-{}", a, b)
})).collect();
(StatusCode::OK, Json(serde_json::json!({
"success": true,
"total": pair_list.len(),
"data": {
"available_pairs": pair_list
},
"protocol": "NAC_Lens/4.0"
})))
}
/// POST /api/v1/rwa/sharia-check
async fn sharia_check(Json(req): Json<ShariaCheckRequest>) -> impl IntoResponse {
let structure = match req.structure.as_str() {
"Murabaha" => IslamicFinanceStructure::Murabaha,
"Ijara" => IslamicFinanceStructure::Ijara,
"IjaraWaIqtina" => IslamicFinanceStructure::IjaraWaIqtina,
"Musharakah" => IslamicFinanceStructure::Musharakah,
"Mudarabah" => IslamicFinanceStructure::Mudarabah,
"Sukuk" => IslamicFinanceStructure::Sukuk,
"Istisna" => IslamicFinanceStructure::Istisna,
"Salam" => IslamicFinanceStructure::Salam,
"Wakalah" => IslamicFinanceStructure::Wakalah,
"Takaful" => IslamicFinanceStructure::Takaful,
_ => return (StatusCode::BAD_REQUEST, Json(serde_json::json!({
"success": false,
"error": format!("不支持的金融结构:{}。支持Murabaha/Ijara/IjaraWaIqtina/Musharakah/Mudarabah/Sukuk/Istisna/Salam/Wakalah/Takaful", req.structure),
"protocol": "NAC_Lens/4.0"
}))),
};
let framework = match get_sharia_framework(&req.jurisdiction) {
Some(f) => f,
None => return (StatusCode::NOT_FOUND, Json(serde_json::json!({
"success": false,
"error": format!("辖区 {} 不在 Sharia 合规覆盖范围内。支持AE/SA/MY", req.jurisdiction),
"protocol": "NAC_Lens/4.0"
}))),
};
let result = validate_sharia_compliance(
&req.jurisdiction,
&structure,
req.has_interest,
req.has_excessive_uncertainty,
req.involves_haram_goods,
);
(StatusCode::OK, Json(serde_json::json!({
"success": true,
"data": {
"jurisdiction": req.jurisdiction,
"jurisdiction_name": framework.jurisdiction_name,
"structure": req.structure,
"is_sharia_compliant": result.is_compliant,
"violations": result.violations,
"recommendations": result.recommendations,
"requires_fatwa": result.requires_fatwa,
"regulatory_body": framework.regulatory_body,
"sharia_board_required": framework.sharia_board.required,
"minimum_scholars": framework.sharia_board.minimum_scholars,
"supported_structures": framework.supported_structures.iter().map(|s| format!("{:?}", s)).collect::<Vec<_>>()
},
"protocol": "NAC_Lens/4.0"
})))
}
/// GET /api/v1/rwa/sharia/jurisdictions
async fn list_sharia_jurisdictions() -> impl IntoResponse {
let mut result = Vec::new();
for j in &["AE", "SA", "MY"] {
if let Some(f) = get_sharia_framework(j) {
result.push(serde_json::json!({
"code": f.jurisdiction,
"name": f.jurisdiction_name,
"regulatory_body": f.regulatory_body,
"supported_structures": f.supported_structures.iter().map(|s| format!("{:?}", s)).collect::<Vec<_>>(),
"sharia_board_required": f.sharia_board.required,
"fatwa_required": f.sharia_board.fatwa_required,
"minimum_scholars": f.sharia_board.minimum_scholars
}));
}
}
Json(serde_json::json!({
"success": true,
"data": result,
"protocol": "NAC_Lens/4.0"
}))
}