Skip to content

Commit

Permalink
payable features interactor - initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
andrei-marinica committed Dec 27, 2024
1 parent af6e5ff commit ecca7b9
Show file tree
Hide file tree
Showing 15 changed files with 297 additions and 3 deletions.
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ members = [
"contracts/feature-tests/panic-message-features",
"contracts/feature-tests/panic-message-features/meta",
"contracts/feature-tests/payable-features",
"contracts/feature-tests/payable-features/interactor",
"contracts/feature-tests/payable-features/meta",
"contracts/feature-tests/rust-snippets-generator-test",
"contracts/feature-tests/rust-snippets-generator-test/meta",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Pem files are used for interactions, but shouldn't be committed
*.pem

# Temporary storage of deployed contract address, so we can preserve the context between executions.
state.toml
30 changes: 30 additions & 0 deletions contracts/feature-tests/payable-features/interactor/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
name = "payable-interactor"
version = "0.0.0"
authors = ["MultiversX <[email protected]>"]
edition = "2021"
publish = false

[[bin]]
name = "payable-interactor"
path = "src/payable_interactor_main.rs"

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

[dependencies.payable-features]
path = ".."

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

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

[features]
chain-simulator-tests = []
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'

Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
mod payable_interactor_cli;
mod payable_interactor_config;

Check warning on line 2 in contracts/feature-tests/payable-features/interactor/src/payable_interactor.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/mx-sdk-rs/mx-sdk-rs/contracts/feature-tests/payable-features/interactor/src/payable_interactor.rs
mod payable_interactor_state;

use payable_features::payable_features_proxy;
pub use payable_interactor_config::Config;
use payable_interactor_state::State;
use clap::Parser;

Check warning on line 8 in contracts/feature-tests/payable-features/interactor/src/payable_interactor.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/mx-sdk-rs/mx-sdk-rs/contracts/feature-tests/payable-features/interactor/src/payable_interactor.rs

use multiversx_sc_snippets::imports::*;

const CODE_PATH: MxscPath = MxscPath::new("../output/payable-features.mxsc.json");

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

let config = Config::load_config();

let mut basic_interact = PayableInteract::new(config).await;

let cli = payable_interactor_cli::InteractCli::parse();
match &cli.command {
Some(payable_interactor_cli::InteractCliCommand::Deploy) => {
basic_interact.deploy().await;
},
Some(payable_interactor_cli::InteractCliCommand::AllTransfers) => {
basic_interact.check_all_transfers().await;
},
None => {},
}
}

pub struct PayableInteract {
pub interactor: Interactor,
pub sc_owner_address: Bech32Address,
pub wallet_address: Bech32Address,
pub state: State,
}

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

let sc_owner_address = interactor.register_wallet(test_wallets::heidi()).await;
let wallet_address = interactor.register_wallet(test_wallets::ivan()).await;

interactor.generate_blocks(30u64).await.unwrap();

PayableInteract {
interactor,
sc_owner_address: sc_owner_address.into(),
wallet_address: wallet_address.into(),
state: State::load_state(),
}
}

pub async fn deploy(&mut self) {
let new_address = self
.interactor
.tx()
.from(&self.sc_owner_address.clone())
.gas(30_000_000)
.typed(payable_features_proxy::PayableFeaturesProxy)
.init()
.code(CODE_PATH)
.returns(ReturnsNewBech32Address)
.run()
.await;

println!("new address: {new_address}");
self.state.set_adder_address(new_address);
}

Check warning on line 75 in contracts/feature-tests/payable-features/interactor/src/payable_interactor.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/mx-sdk-rs/mx-sdk-rs/contracts/feature-tests/payable-features/interactor/src/payable_interactor.rs
pub async fn check_all_transfers(&mut self) {
let mut payment = MultiEsdtPayment::new();
payment.push(EsdtTokenPayment::new("EGLD-000000".into(), 0, 1_0000u64.into()));
payment.push(EsdtTokenPayment::new("EGLD-000000".into(), 0, 2_0000u64.into()));

let result = self.interactor
.tx()
.from(&self.wallet_address)
.to(self.state.current_adder_address())
.gas(6_000_000u64)
.typed(payable_features_proxy::PayableFeaturesProxy)
.payable_all_transfers()
.multi_esdt(payment)
.returns(ReturnsResult)

Check warning on line 89 in contracts/feature-tests/payable-features/interactor/src/payable_interactor.rs

View workflow job for this annotation

GitHub Actions / cargo fmt

Diff in /home/runner/work/mx-sdk-rs/mx-sdk-rs/contracts/feature-tests/payable-features/interactor/src/payable_interactor.rs
.run()
.await;

println!("Result: {result:?}");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use clap::{Parser, Subcommand};

/// Adder Interact CLI
#[derive(Default, PartialEq, Eq, Debug, Parser)]
#[command(version, about)]
#[command(propagate_version = true)]
pub struct InteractCli {
#[command(subcommand)]
pub command: Option<InteractCliCommand>,
}

/// Adder Interact CLI Commands
#[derive(Clone, PartialEq, Eq, Debug, Subcommand)]
pub enum InteractCliCommand {
#[command(name = "deploy", about = "Deploy contract")]
Deploy,
#[command(name = "at", about = "Check all transfers")]
AllTransfers,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use serde::Deserialize;
use std::io::Read;

/// Config file
const CONFIG_FILE: &str = "config.toml";

#[derive(Debug, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ChainType {
Real,
Simulator,
}

/// Adder Interact configuration
#[derive(Debug, Deserialize)]
pub struct Config {
pub gateway_uri: String,
pub chain_type: ChainType,
}

impl Config {
// Deserializes config from file
pub fn load_config() -> Self {
let mut file = std::fs::File::open(CONFIG_FILE).unwrap();
let mut content = String::new();
file.read_to_string(&mut content).unwrap();
toml::from_str(&content).unwrap()
}

pub fn chain_simulator_config() -> Self {
Config {
gateway_uri: "http://localhost:8085".to_owned(),
chain_type: ChainType::Simulator,
}
}

// Returns the gateway URI
pub fn gateway_uri(&self) -> &str {
&self.gateway_uri
}

// Returns if chain type is chain simulator
pub fn use_chain_simulator(&self) -> bool {
match self.chain_type {
ChainType::Real => false,
ChainType::Simulator => true,
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
extern crate payable_interactor;

#[tokio::main]
pub async fn main() {
payable_interactor::adder_cli().await;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use multiversx_sc_snippets::imports::*;
use serde::{Deserialize, Serialize};
use std::{
io::{Read, Write},
path::Path,
};

/// State file
const STATE_FILE: &str = "state.toml";

/// Adder Interact state
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct State {
adder_address: Option<Bech32Address>,
}

impl State {
// Deserializes state from file
pub fn load_state() -> Self {
if Path::new(STATE_FILE).exists() {
let mut file = std::fs::File::open(STATE_FILE).unwrap();
let mut content = String::new();
file.read_to_string(&mut content).unwrap();
toml::from_str(&content).unwrap()
} else {
Self::default()
}
}

/// Sets the adder address
pub fn set_adder_address(&mut self, address: Bech32Address) {
self.adder_address = Some(address);
}

/// Returns the adder contract
pub fn current_adder_address(&self) -> &Bech32Address {
self.adder_address
.as_ref()
.expect("no known adder contract, deploy first")
}
}

impl Drop for State {
// Serializes state to file
fn drop(&mut self) {
let mut file = std::fs::File::create(STATE_FILE).unwrap();
file.write_all(toml::to_string(self).unwrap().as_bytes())
.unwrap();
}
}
4 changes: 4 additions & 0 deletions contracts/feature-tests/payable-features/sc-config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[settings]

[[proxy]]
path = "src/payable_features_proxy.rs"
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,10 @@ pub trait PayableFeatures {
let token = self.call_value().single_esdt().token_identifier.clone();
(payment, token).into()
}

#[endpoint]
#[payable("*")]
fn payable_all_transfers(&self) -> ManagedVec<EgldOrEsdtTokenPayment> {
self.call_value().all_transfers().clone()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,12 @@ where
.raw_call("payable_token_4")
.original_result()
}

pub fn payable_all_transfers(
self,
) -> TxTypedCall<Env, From, To, (), Gas, ManagedVec<Env::Api, EgldOrEsdtTokenPayment<Env::Api>>> {
self.wrapped_tx
.raw_call("payable_all_transfers")
.original_result()
}
}
5 changes: 3 additions & 2 deletions contracts/feature-tests/payable-features/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
////////////////////////////////////////////////////

// Init: 1
// Endpoints: 15
// Endpoints: 16
// Async Callback (empty): 1
// Total number of exported functions: 17
// Total number of exported functions: 18

#![no_std]

Expand All @@ -33,6 +33,7 @@ multiversx_sc_wasm_adapter::endpoints! {
payable_token_2 => payable_token_2
payable_token_3 => payable_token_3
payable_token_4 => payable_token_4
payable_all_transfers => payable_all_transfers
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ where
} else {
// clone all_esdt_transfers_unchecked -> all_transfers
let all_transfers_unchecked_handle = self.all_esdt_transfers_unchecked();
let _ = A::managed_type_impl().mb_set_slice(all_transfers_handle.clone(), 0, &[]);
let _ = A::managed_type_impl().mb_overwrite(all_transfers_handle.clone(), &[]);

Check warning on line 159 in framework/base/src/contract_base/wrappers/call_value_wrapper.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] framework/base/src/contract_base/wrappers/call_value_wrapper.rs#L159

warning: this let-binding has unit value --> framework/base/src/contract_base/wrappers/call_value_wrapper.rs:159:17 | 159 | let _ = A::managed_type_impl().mb_overwrite(all_transfers_handle.clone(), &[]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `A::managed_type_impl().mb_overwrite(all_transfers_handle.clone(), &[]);` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value = note: `#[warn(clippy::let_unit_value)]` on by default
Raw output
framework/base/src/contract_base/wrappers/call_value_wrapper.rs:159:17:w:warning: this let-binding has unit value
   --> framework/base/src/contract_base/wrappers/call_value_wrapper.rs:159:17
    |
159 |                 let _ = A::managed_type_impl().mb_overwrite(all_transfers_handle.clone(), &[]);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `A::managed_type_impl().mb_overwrite(all_transfers_handle.clone(), &[]);`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
    = note: `#[warn(clippy::let_unit_value)]` on by default


__END__

Check warning on line 159 in framework/base/src/contract_base/wrappers/call_value_wrapper.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] framework/base/src/contract_base/wrappers/call_value_wrapper.rs#L159

warning: this let-binding has unit value --> framework/base/src/contract_base/wrappers/call_value_wrapper.rs:159:17 | 159 | let _ = A::managed_type_impl().mb_overwrite(all_transfers_handle.clone(), &[]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `A::managed_type_impl().mb_overwrite(all_transfers_handle.clone(), &[]);` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value = note: `#[warn(clippy::let_unit_value)]` on by default
Raw output
framework/base/src/contract_base/wrappers/call_value_wrapper.rs:159:17:w:warning: this let-binding has unit value
   --> framework/base/src/contract_base/wrappers/call_value_wrapper.rs:159:17
    |
159 |                 let _ = A::managed_type_impl().mb_overwrite(all_transfers_handle.clone(), &[]);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `A::managed_type_impl().mb_overwrite(all_transfers_handle.clone(), &[]);`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
    = note: `#[warn(clippy::let_unit_value)]` on by default


__END__
A::managed_type_impl()
.mb_append(all_transfers_handle.clone(), all_transfers_unchecked_handle);
}
Expand Down

0 comments on commit ecca7b9

Please sign in to comment.