481 lines
19 KiB
Rust
481 lines
19 KiB
Rust
// 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"
|
||
}))
|
||
}
|