neo3/neo_contract/famous/
neoburger.rs

1use async_trait::async_trait;
2use primitive_types::H160;
3use serde::{Deserialize, Serialize};
4use std::str::FromStr;
5
6use crate::{
7	builder::{AccountSigner, TransactionBuilder},
8	neo_clients::{APITrait, JsonRpcProvider, RpcClient},
9	neo_contract::{ContractError, SmartContractTrait, TokenTrait},
10	neo_protocol::Account,
11};
12use neo3::prelude::*;
13
14/// NeoburgerNeo contract interface for Neo N3
15///
16/// NeoburgerNeo (bNEO) is a wrapped NEO token that allows users to earn GAS while using their NEO in DeFi.
17/// This contract interface provides methods to interact with the NeoburgerNeo smart contract.
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct NeoburgerContract<'a, P: JsonRpcProvider> {
20	#[serde(deserialize_with = "deserialize_script_hash")]
21	#[serde(serialize_with = "serialize_script_hash")]
22	script_hash: ScriptHash,
23	#[serde(skip_serializing_if = "Option::is_none")]
24	total_supply: Option<u64>,
25	#[serde(skip_serializing_if = "Option::is_none")]
26	decimals: Option<u8>,
27	#[serde(skip_serializing_if = "Option::is_none")]
28	symbol: Option<String>,
29	#[serde(skip)]
30	provider: Option<&'a RpcClient<P>>,
31}
32
33impl<'a, P: JsonRpcProvider + 'static> NeoburgerContract<'a, P> {
34	/// The script hash of the NeoburgerNeo contract on Neo N3 MainNet
35	pub const CONTRACT_HASH: &'static str = "48c40d4666f93408be1bef038b6722404f5c4a5a";
36	/// The symbol of the NeoburgerNeo token
37	pub const SYMBOL: &'static str = "bNEO";
38	/// The number of decimals for the NeoburgerNeo token
39	pub const DECIMALS: u8 = 8;
40
41	// Method constants
42	/// Method name for wrapping NEO to bNEO
43	pub const WRAP: &'static str = "wrap";
44	/// Method name for unwrapping bNEO to NEO
45	pub const UNWRAP: &'static str = "unwrap";
46	/// Method name for claiming GAS
47	pub const CLAIM_GAS: &'static str = "claimGas";
48	/// Method name for getting the exchange rate
49	pub const GET_RATE: &'static str = "getRate";
50
51	/// Creates a new NeoburgerContract instance with the default contract hash
52	///
53	/// # Arguments
54	///
55	/// * `provider` - An optional reference to an RPC client
56	///
57	/// # Returns
58	///
59	/// A new NeoburgerContract instance
60	pub fn new(provider: Option<&'a RpcClient<P>>) -> Self {
61		Self {
62			script_hash: ScriptHash::from_str(Self::CONTRACT_HASH).unwrap(),
63			total_supply: None,
64			decimals: Some(Self::DECIMALS),
65			symbol: Some(Self::SYMBOL.to_string()),
66			provider,
67		}
68	}
69
70	/// Creates a new NeoburgerContract instance with a custom script hash
71	///
72	/// # Arguments
73	///
74	/// * `script_hash` - The script hash of the NeoburgerNeo contract
75	/// * `provider` - An optional reference to an RPC client
76	///
77	/// # Returns
78	///
79	/// A new NeoburgerContract instance
80	pub fn with_script_hash(script_hash: ScriptHash, provider: Option<&'a RpcClient<P>>) -> Self {
81		Self {
82			script_hash,
83			total_supply: None,
84			decimals: Some(Self::DECIMALS),
85			symbol: Some(Self::SYMBOL.to_string()),
86			provider,
87		}
88	}
89
90	/// Wraps NEO to bNEO
91	///
92	/// # Arguments
93	///
94	/// * `amount` - The amount of NEO to wrap
95	/// * `account` - The account that will sign the transaction
96	///
97	/// # Returns
98	///
99	/// A transaction builder that can be used to build and sign the transaction
100	pub async fn wrap(
101		&self,
102		amount: i64,
103		account: &Account,
104	) -> Result<TransactionBuilder<P>, ContractError> {
105		let params = vec![ContractParameter::integer(amount)];
106
107		let mut builder = self.invoke_function(Self::WRAP, params).await?;
108		builder.set_signers(vec![AccountSigner::called_by_entry(account).unwrap().into()]);
109
110		Ok(builder)
111	}
112
113	/// Unwraps bNEO to NEO
114	///
115	/// # Arguments
116	///
117	/// * `amount` - The amount of bNEO to unwrap
118	/// * `account` - The account that will sign the transaction
119	///
120	/// # Returns
121	///
122	/// A transaction builder that can be used to build and sign the transaction
123	pub async fn unwrap(
124		&self,
125		amount: i64,
126		account: &Account,
127	) -> Result<TransactionBuilder<P>, ContractError> {
128		let params = vec![ContractParameter::integer(amount)];
129
130		let mut builder = self.invoke_function(Self::UNWRAP, params).await?;
131		builder.set_signers(vec![AccountSigner::called_by_entry(account).unwrap().into()]);
132
133		Ok(builder)
134	}
135
136	/// Claims GAS rewards from holding bNEO
137	///
138	/// # Arguments
139	///
140	/// * `account` - The account that will sign the transaction
141	///
142	/// # Returns
143	///
144	/// A transaction builder that can be used to build and sign the transaction
145	pub async fn claim_gas(
146		&self,
147		account: &Account,
148	) -> Result<TransactionBuilder<P>, ContractError> {
149		let params = vec![];
150
151		let mut builder = self.invoke_function(Self::CLAIM_GAS, params).await?;
152		builder.set_signers(vec![AccountSigner::called_by_entry(account).unwrap().into()]);
153
154		Ok(builder)
155	}
156
157	/// Gets the current exchange rate between NEO and bNEO
158	///
159	/// # Returns
160	///
161	/// The exchange rate as a floating-point number
162	pub async fn get_rate(&self) -> Result<f64, ContractError> {
163		let result = self.call_function_returning_int(Self::GET_RATE, vec![]).await?;
164		// Convert the integer result to a floating-point rate (assuming rate is stored as an integer with a fixed decimal point)
165		Ok(result as f64 / 100_000_000.0) // Assuming 8 decimal places
166	}
167}
168
169#[async_trait]
170impl<'a, P: JsonRpcProvider> SmartContractTrait<'a> for NeoburgerContract<'a, P> {
171	type P = P;
172
173	fn script_hash(&self) -> H160 {
174		self.script_hash
175	}
176
177	fn set_script_hash(&mut self, script_hash: H160) {
178		self.script_hash = script_hash;
179	}
180
181	fn provider(&self) -> Option<&RpcClient<P>> {
182		self.provider
183	}
184}
185
186#[async_trait]
187impl<'a, P: JsonRpcProvider> TokenTrait<'a, P> for NeoburgerContract<'a, P> {
188	fn total_supply(&self) -> Option<u64> {
189		self.total_supply
190	}
191
192	fn set_total_supply(&mut self, total_supply: u64) {
193		self.total_supply = Some(total_supply);
194	}
195
196	fn decimals(&self) -> Option<u8> {
197		self.decimals
198	}
199
200	fn set_decimals(&mut self, decimals: u8) {
201		self.decimals = Some(decimals);
202	}
203
204	fn symbol(&self) -> Option<String> {
205		self.symbol.clone()
206	}
207
208	fn set_symbol(&mut self, symbol: String) {
209		self.symbol = Some(symbol);
210	}
211
212	async fn resolve_nns_text_record(&self, _name: &NNSName) -> Result<H160, ContractError> {
213		Err(ContractError::InvalidNeoName(
214			"NeoburgerNeo does not support NNS resolution".to_string(),
215		))
216	}
217}