use async_trait::async_trait;
use hex_literal::hex;
use primitive_types::H160;
use serde::{Deserialize, Serialize};
use crate::{
builder::{AccountSigner, TransactionBuilder},
neo_clients::{JsonRpcProvider, RpcClient},
neo_contract::{ContractError, SmartContractTrait},
neo_protocol::Account,
};
use neo3::prelude::*;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FlamingoContract<'a, P: JsonRpcProvider> {
#[serde(deserialize_with = "deserialize_script_hash")]
#[serde(serialize_with = "serialize_script_hash")]
script_hash: ScriptHash,
#[serde(skip)]
provider: Option<&'a RpcClient<P>>,
}
impl<'a, P: JsonRpcProvider + 'static> FlamingoContract<'a, P> {
pub const CONTRACT_HASH: &'static str = "f970f4cddcd087ab5d8a5697a32b3cfd32c8b465";
pub const SWAP: &'static str = "swap";
pub const ADD_LIQUIDITY: &'static str = "addLiquidity";
pub const REMOVE_LIQUIDITY: &'static str = "removeLiquidity";
pub const STAKE: &'static str = "stake";
pub const CLAIM_REWARDS: &'static str = "claimRewards";
pub fn new(provider: Option<&'a RpcClient<P>>) -> Self {
Self {
script_hash: ScriptHash::from(hex!("f970f4cddcd087ab5d8a5697a32b3cfd32c8b465")),
provider,
}
}
pub fn with_script_hash(script_hash: ScriptHash, provider: Option<&'a RpcClient<P>>) -> Self {
Self { script_hash, provider }
}
pub async fn swap(
&self,
from_token: &ScriptHash,
to_token: &ScriptHash,
amount: i64,
min_return: i64,
account: &Account,
) -> Result<TransactionBuilder<'_, P>, ContractError> {
let params = vec![
from_token.into(),
to_token.into(),
ContractParameter::integer(amount),
ContractParameter::integer(min_return),
];
let mut builder = self.invoke_function(Self::SWAP, params).await?;
let signer = AccountSigner::called_by_entry(account)
.map_err(|err| ContractError::RuntimeError(err.to_string()))?;
builder
.set_signers(vec![signer.into()])
.map_err(|err| ContractError::RuntimeError(err.to_string()))?;
Ok(builder)
}
pub async fn add_liquidity(
&self,
token_a: &ScriptHash,
token_b: &ScriptHash,
amount_a: i64,
amount_b: i64,
account: &Account,
) -> Result<TransactionBuilder<'_, P>, ContractError> {
let params = vec![
token_a.into(),
token_b.into(),
ContractParameter::integer(amount_a),
ContractParameter::integer(amount_b),
];
let mut builder = self.invoke_function(Self::ADD_LIQUIDITY, params).await?;
let signer = AccountSigner::called_by_entry(account)
.map_err(|err| ContractError::RuntimeError(err.to_string()))?;
builder
.set_signers(vec![signer.into()])
.map_err(|err| ContractError::RuntimeError(err.to_string()))?;
Ok(builder)
}
pub async fn remove_liquidity(
&self,
token_a: &ScriptHash,
token_b: &ScriptHash,
liquidity: i64,
account: &Account,
) -> Result<TransactionBuilder<'_, P>, ContractError> {
let params = vec![token_a.into(), token_b.into(), ContractParameter::integer(liquidity)];
let mut builder = self.invoke_function(Self::REMOVE_LIQUIDITY, params).await?;
let signer = AccountSigner::called_by_entry(account)
.map_err(|err| ContractError::RuntimeError(err.to_string()))?;
builder
.set_signers(vec![signer.into()])
.map_err(|err| ContractError::RuntimeError(err.to_string()))?;
Ok(builder)
}
pub async fn stake(
&self,
token: &ScriptHash,
amount: i64,
account: &Account,
) -> Result<TransactionBuilder<'_, P>, ContractError> {
let params = vec![token.into(), ContractParameter::integer(amount)];
let mut builder = self.invoke_function(Self::STAKE, params).await?;
let signer = AccountSigner::called_by_entry(account)
.map_err(|err| ContractError::RuntimeError(err.to_string()))?;
builder
.set_signers(vec![signer.into()])
.map_err(|err| ContractError::RuntimeError(err.to_string()))?;
Ok(builder)
}
pub async fn claim_rewards(
&self,
account: &Account,
) -> Result<TransactionBuilder<'_, P>, ContractError> {
let params = vec![];
let mut builder = self.invoke_function(Self::CLAIM_REWARDS, params).await?;
let signer = AccountSigner::called_by_entry(account)
.map_err(|err| ContractError::RuntimeError(err.to_string()))?;
builder
.set_signers(vec![signer.into()])
.map_err(|err| ContractError::RuntimeError(err.to_string()))?;
Ok(builder)
}
}
#[async_trait]
impl<'a, P: JsonRpcProvider> SmartContractTrait<'a> for FlamingoContract<'a, P> {
type P = P;
fn script_hash(&self) -> H160 {
self.script_hash
}
fn set_script_hash(&mut self, script_hash: H160) {
self.script_hash = script_hash;
}
fn provider(&self) -> Option<&RpcClient<P>> {
self.provider
}
}