neo3/neo_x/bridge/
bridge_contract.rs

1use async_trait::async_trait;
2use primitive_types::H160;
3use serde::{Deserialize, Serialize};
4use std::str::FromStr;
5
6use crate::{
7	neo_builder::{AccountSigner, TransactionBuilder},
8	neo_clients::{JsonRpcProvider, RpcClient},
9	neo_contract::{ContractError, SmartContractTrait},
10	neo_protocol::Account,
11	neo_types::{
12		serde_with_utils::{deserialize_script_hash, serialize_script_hash},
13		ScriptHash,
14	},
15	ContractParameter,
16};
17
18/// Neo X Bridge contract interface for token transfers between Neo N3 and Neo X
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct NeoXBridgeContract<'a, P: JsonRpcProvider> {
21	#[serde(deserialize_with = "deserialize_script_hash")]
22	#[serde(serialize_with = "serialize_script_hash")]
23	script_hash: ScriptHash,
24	#[serde(skip)]
25	provider: Option<&'a RpcClient<P>>,
26}
27
28impl<'a, P: JsonRpcProvider + 'static> NeoXBridgeContract<'a, P> {
29	/// The script hash of the Neo X Bridge contract on Neo N3 MainNet
30	/// Professional bridge contract configuration for production deployment
31	/// This constant represents the deployed Neo X bridge contract address
32	/// Update this value to match the actual deployed contract hash for your target network
33	pub const CONTRACT_HASH: &'static str = "74f2dc36a68fdc4682034178eb2220729231db76";
34
35	// Method constants
36	/// Method name for depositing tokens from Neo N3 to Neo X
37	pub const DEPOSIT: &'static str = "deposit";
38	/// Method name for withdrawing tokens from Neo X to Neo N3
39	pub const WITHDRAW: &'static str = "withdraw";
40	/// Method name for getting the bridge fee
41	pub const GET_FEE: &'static str = "getFee";
42	/// Method name for getting the bridge cap
43	pub const GET_CAP: &'static str = "getCap";
44
45	/// Creates a new NeoXBridgeContract instance with the default contract hash
46	///
47	/// # Arguments
48	///
49	/// * `provider` - An optional reference to an RPC client
50	///
51	/// # Returns
52	///
53	/// A Result containing a new NeoXBridgeContract instance or an error
54	pub fn new(provider: Option<&'a RpcClient<P>>) -> Result<Self, ContractError> {
55		Ok(Self {
56			script_hash: ScriptHash::from_str(Self::CONTRACT_HASH).map_err(|e| {
57				ContractError::InvalidScriptHash(format!("Invalid contract hash: {}", e))
58			})?,
59			provider,
60		})
61	}
62
63	/// Creates a new NeoXBridgeContract instance with a custom script hash
64	///
65	/// # Arguments
66	///
67	/// * `script_hash` - The script hash of the Neo X Bridge contract
68	/// * `provider` - An optional reference to an RPC client
69	///
70	/// # Returns
71	///
72	/// A new NeoXBridgeContract instance
73	pub fn with_script_hash(script_hash: ScriptHash, provider: Option<&'a RpcClient<P>>) -> Self {
74		Self { script_hash, provider }
75	}
76
77	/// Deposits tokens from Neo N3 to Neo X
78	///
79	/// # Arguments
80	///
81	/// * `token` - The script hash of the token to deposit (currently only GAS is supported)
82	/// * `amount` - The amount of tokens to deposit
83	/// * `destination` - The destination address on Neo X
84	/// * `account` - The account that will sign the transaction
85	///
86	/// # Returns
87	///
88	/// A transaction builder that can be used to build and sign the transaction
89	pub async fn deposit(
90		&self,
91		token: &ScriptHash,
92		amount: i64,
93		destination: &str,
94		account: &Account,
95	) -> Result<TransactionBuilder<P>, ContractError> {
96		let params = vec![
97			token.into(),
98			ContractParameter::integer(amount),
99			ContractParameter::string(destination.to_string()),
100		];
101
102		let mut builder = self.invoke_function(Self::DEPOSIT, params).await?;
103		builder.set_signers(vec![AccountSigner::called_by_entry(account)
104			.map_err(|e| {
105				ContractError::InvalidAccount(format!("Failed to create account signer: {}", e))
106			})?
107			.into()]);
108
109		Ok(builder)
110	}
111
112	/// Withdraws tokens from Neo X to Neo N3
113	///
114	/// # Arguments
115	///
116	/// * `token` - The script hash of the token to withdraw (currently only GAS is supported)
117	/// * `amount` - The amount of tokens to withdraw
118	/// * `destination` - The destination address on Neo N3
119	/// * `account` - The account that will sign the transaction
120	///
121	/// # Returns
122	///
123	/// A transaction builder that can be used to build and sign the transaction
124	pub async fn withdraw(
125		&self,
126		token: &ScriptHash,
127		amount: i64,
128		destination: &str,
129		account: &Account,
130	) -> Result<TransactionBuilder<P>, ContractError> {
131		let params = vec![
132			token.into(),
133			ContractParameter::integer(amount),
134			ContractParameter::string(destination.to_string()),
135		];
136
137		let mut builder = self.invoke_function(Self::WITHDRAW, params).await?;
138		builder.set_signers(vec![AccountSigner::called_by_entry(account)
139			.map_err(|e| {
140				ContractError::InvalidAccount(format!("Failed to create account signer: {}", e))
141			})?
142			.into()]);
143
144		Ok(builder)
145	}
146
147	/// Gets the bridge fee for a specific token
148	///
149	/// # Arguments
150	///
151	/// * `token` - The script hash of the token to get the fee for
152	///
153	/// # Returns
154	///
155	/// The bridge fee as a u64
156	pub async fn get_fee(&self, token: &ScriptHash) -> Result<u64, ContractError> {
157		let result = self.call_function_returning_int(Self::GET_FEE, vec![token.into()]).await?;
158		Ok(result as u64)
159	}
160
161	/// Gets the bridge cap for a specific token
162	///
163	/// # Arguments
164	///
165	/// * `token` - The script hash of the token to get the cap for
166	///
167	/// # Returns
168	///
169	/// The bridge cap as a u64
170	pub async fn get_cap(&self, token: &ScriptHash) -> Result<u64, ContractError> {
171		let result = self.call_function_returning_int(Self::GET_CAP, vec![token.into()]).await?;
172		Ok(result as u64)
173	}
174}
175
176#[async_trait]
177impl<'a, P: JsonRpcProvider> SmartContractTrait<'a> for NeoXBridgeContract<'a, P> {
178	type P = P;
179
180	fn script_hash(&self) -> H160 {
181		self.script_hash
182	}
183
184	fn set_script_hash(&mut self, script_hash: H160) {
185		self.script_hash = script_hash;
186	}
187
188	fn provider(&self) -> Option<&RpcClient<P>> {
189		self.provider
190	}
191}