Skip to content

Commit

Permalink
interactor
Browse files Browse the repository at this point in the history
  • Loading branch information
BiancaIalangi committed Dec 9, 2024
1 parent 0021cd6 commit 22250c4
Show file tree
Hide file tree
Showing 12 changed files with 826 additions and 0 deletions.
2 changes: 2 additions & 0 deletions ping-pong/interactor/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Pem files are used for interactions, but shouldn't be committed
*.pem
32 changes: 32 additions & 0 deletions ping-pong/interactor/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[package]
name = "ping-pong-interact"
version = "0.0.0"
authors = ["you"]
edition = "2021"
publish = false

[[bin]]
name = "ping-pong-interact"
path = "src/interactor_main.rs"

[lib]
path = "src/interact.rs"

[dependencies.ping-pong]
path = ".."

[dependencies.multiversx-sc-snippets]
version = "0.54.6"

[dependencies.multiversx-sc]
version = "0.54.6"

[dependencies]
clap = { version = "4.4.7", features = ["derive"] }
serde = { version = "1.0", features = ["derive"] }
toml = "0.8.6"
tokio = { version = "1.24" }


[features]
chain-simulator-tests = []
7 changes: 7 additions & 0 deletions ping-pong/interactor/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

# chain_type = 'simulator'
# gateway_uri = 'http://localhost:8085'

chain_type = 'real'
gateway_uri = 'https://devnet-gateway.multiversx.com'

326 changes: 326 additions & 0 deletions ping-pong/interactor/src/interact.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,326 @@
mod interact_cli;
mod interact_config;
mod interact_state;
mod ping_pong_proxy;

use clap::Parser;
pub use interact_config::Config;
use interact_state::State;
use multiversx_sc_snippets::imports::*;

const PING_PONG_CODE: MxscPath = MxscPath::new("output/ping-pong.mxsc.json");

pub async fn ping_pong_cli() {
env_logger::init();

let config = Config::load_config();

let mut interact = PingPongInteract::new(config).await;
let cli = interact_cli::InteractCli::parse();

match &cli.command {
Some(interact_cli::InteractCliCommand::Deploy(args)) => {
interact
.deploy(
args.ping_amount.clone(),
args.duration_in_seconds,
args.token_id.clone(),
)
.await;
}
Some(interact_cli::InteractCliCommand::Upgrade(args)) => {
interact
.upgrade(args.ping_amount.clone(), args.duration_in_seconds)
.await;
}
Some(interact_cli::InteractCliCommand::Ping(args)) => {
interact
.ping(
&args.token,
args.nonce,
args.amount,
&interact.alice_wallet_address.clone(),
None,
)
.await;
}
Some(interact_cli::InteractCliCommand::Pong) => {
interact
.pong(&interact.alice_wallet_address.clone(), None)
.await;
}
Some(interact_cli::InteractCliCommand::DidUserPing(args)) => {
let address = Bech32Address::from_bech32_string(args.address.clone());
interact.did_user_ping(address).await;
}
Some(interact_cli::InteractCliCommand::GetPongEnableTimestamp(args)) => {
let address = Bech32Address::from_bech32_string(args.address.clone());
interact.get_pong_enable_timestamp(address).await;
}
Some(interact_cli::InteractCliCommand::GetTimeToPong(args)) => {
let address = Bech32Address::from_bech32_string(args.address.clone());
interact.get_time_to_pong(address).await;
}
Some(interact_cli::InteractCliCommand::GetAcceptedPaymentToken) => {
interact.accepted_payment_token_id().await;
}
Some(interact_cli::InteractCliCommand::GetPingAmount) => {
interact.ping_amount().await;
}
Some(interact_cli::InteractCliCommand::GetDurationTimestamp) => {
interact.duration_in_seconds().await;
}
Some(interact_cli::InteractCliCommand::GetUserPingTimestamp(args)) => {
let address = Bech32Address::from_bech32_string(args.address.clone());
interact.user_ping_timestamp(address).await;
}
None => {}
}
}

pub struct PingPongInteract {
pub interactor: Interactor,
pub alice_wallet_address: Bech32Address,
pub mike_wallet_address: Bech32Address,
pub state: State,
}

impl PingPongInteract {
pub async fn new(config: Config) -> Self {
let mut interactor = Interactor::new(config.gateway_uri())
.await
.use_chain_simulator(config.use_chain_simulator());

interactor.set_current_dir_from_workspace("ping-pong");
let alice_wallet_address = interactor.register_wallet(test_wallets::alice()).await;
let mike_wallet_address = interactor.register_wallet(test_wallets::mike()).await;

// Useful in the chain simulator setting
// generate blocks until ESDTSystemSCAddress is enabled
interactor.generate_blocks_until_epoch(1).await.unwrap();

PingPongInteract {
interactor,
alice_wallet_address: alice_wallet_address.into(),
mike_wallet_address: mike_wallet_address.into(),
state: State::load_state(),
}
}

pub async fn deploy(
&mut self,
ping_amount: RustBigUint,
duration_in_seconds: u64,
token_id: String,
) {
let token = if token_id.to_uppercase() == "EGLD" {
EgldOrEsdtTokenIdentifier::egld()
} else {
EgldOrEsdtTokenIdentifier::esdt(&token_id)
};

let new_address = self
.interactor
.tx()
.from(&self.alice_wallet_address)
.gas(30_000_000u64)
.typed(ping_pong_proxy::PingPongProxy)
.init(ping_amount, duration_in_seconds, OptionalValue::Some(token))
.code(PING_PONG_CODE)
.returns(ReturnsNewAddress)
.run()
.await;
let new_address_bech32 = bech32::encode(&new_address);
self.state
.set_ping_pong_address(Bech32Address::from_bech32_string(
new_address_bech32.clone(),
));

println!("new address: {new_address_bech32}");
}

pub async fn upgrade(&mut self, ping_amount: RustBigUint, duration_in_seconds: u64) {
let upgrade_address = self
.interactor
.tx()
.from(&self.alice_wallet_address)
.to(self.state.current_ping_pong_address())
.gas(30_000_000u64)
.typed(ping_pong_proxy::PingPongProxy)
.upgrade(ping_amount, duration_in_seconds)
.code(PING_PONG_CODE)
.returns(ReturnsNewAddress)
.run()
.await;

let upgrade_address_bech32 = bech32::encode(&upgrade_address);
self.state
.set_ping_pong_address(Bech32Address::from_bech32_string(
upgrade_address_bech32.clone(),
));

println!("new upgrade address: {upgrade_address_bech32}");
}

pub async fn ping(
&mut self,
token_id: &str,
nonce: Option<u64>,
amount: u64,
sender: &Bech32Address,
message: Option<&str>,
) {
let response = if token_id.to_ascii_uppercase() == "EGLD" {
self.interactor
.tx()
.from(sender)
.to(self.state.current_ping_pong_address())
.gas(30_000_000u64)
.typed(ping_pong_proxy::PingPongProxy)
.ping()
.egld(amount)
.returns(ReturnsHandledOrError::new())
.run()
.await
} else {
self.interactor
.tx()
.from(sender)
.to(self.state.current_ping_pong_address())
.gas(30_000_000u64)
.typed(ping_pong_proxy::PingPongProxy)
.ping()
.payment((
TokenIdentifier::from(&token_id.to_uppercase()),
nonce.unwrap(),
BigUint::from(amount),
))
.returns(ReturnsHandledOrError::new())
.run()
.await
};

match response {
Ok(_) => println!("Ping successfully executed"),
Err(err) => {
println!("Ping failed with message: {}", err.message);
assert_eq!(message.unwrap_or_default(), err.message);
}
}
}

pub async fn pong(&mut self, sender: &Bech32Address, message: Option<&str>) {
let response = self
.interactor
.tx()
.from(sender)
.to(self.state.current_ping_pong_address())
.gas(30_000_000u64)
.typed(ping_pong_proxy::PingPongProxy)
.pong()
.returns(ReturnsHandledOrError::new())
.run()
.await;

match response {
Ok(_) => println!("Pong successfully executed"),
Err(err) => {
println!("Pong failed with message: {}", err.message);
assert_eq!(message.unwrap_or_default(), err.message);
}
}
}

pub async fn did_user_ping(&mut self, address: Bech32Address) -> bool {
self.interactor
.query()
.to(self.state.current_ping_pong_address())
.typed(ping_pong_proxy::PingPongProxy)
.did_user_ping(address)
.returns(ReturnsResultUnmanaged)
.run()
.await
}

pub async fn get_pong_enable_timestamp(&mut self, address: Bech32Address) -> u64 {
self.interactor
.query()
.to(self.state.current_ping_pong_address())
.typed(ping_pong_proxy::PingPongProxy)
.get_pong_enable_timestamp(address)
.returns(ReturnsResultUnmanaged)
.run()
.await
}

pub async fn get_time_to_pong(&mut self, address: Bech32Address) -> Option<u64> {
let result_value = self
.interactor
.query()
.to(self.state.current_ping_pong_address())
.typed(ping_pong_proxy::PingPongProxy)
.get_time_to_pong(address)
.returns(ReturnsResultUnmanaged)
.run()
.await;

match result_value {
OptionalValue::Some(time) => Some(time),
OptionalValue::None => {
println!("Address unavailable");
None
}
}
}

pub async fn accepted_payment_token_id(&mut self) -> String {
let result_value = self
.interactor
.query()
.to(self.state.current_ping_pong_address())
.typed(ping_pong_proxy::PingPongProxy)
.accepted_payment_token_id()
.returns(ReturnsResultUnmanaged)
.run()
.await;

if result_value.is_egld() {
return "EGLD".to_owned();
}

result_value.into_esdt_option().unwrap().to_string()
}

pub async fn ping_amount(&mut self) -> RustBigUint {
self.interactor
.query()
.to(self.state.current_ping_pong_address())
.typed(ping_pong_proxy::PingPongProxy)
.ping_amount()
.returns(ReturnsResultUnmanaged)
.run()
.await
}

pub async fn duration_in_seconds(&mut self) -> u64 {
self.interactor
.query()
.to(self.state.current_ping_pong_address())
.typed(ping_pong_proxy::PingPongProxy)
.duration_in_seconds()
.returns(ReturnsResultUnmanaged)
.run()
.await
}

pub async fn user_ping_timestamp(&mut self, address: Bech32Address) -> u64 {
self.interactor
.query()
.to(self.state.current_ping_pong_address())
.typed(ping_pong_proxy::PingPongProxy)
.user_ping_timestamp(address)
.returns(ReturnsResultUnmanaged)
.run()
.await
}
}
Loading

0 comments on commit 22250c4

Please sign in to comment.