Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Paymaster SC #24

Merged
merged 13 commits into from
Oct 3, 2023
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ members = [
"contracts/order-book/factory/meta",
"contracts/order-book/pair",
"contracts/order-book/pair/meta",
"contracts/paymaster",
"contracts/paymaster/meta",
"contracts/ping-pong-egld",
"contracts/ping-pong-egld/meta",
"contracts/proxy-pause",
Expand Down
7 changes: 7 additions & 0 deletions contracts/paymaster/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Generated by Cargo
# will have compiled files and executables
/target/
*/target/

# The mxpy output
/output*/
18 changes: 18 additions & 0 deletions contracts/paymaster/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "paymaster"
version = "0.0.0"
authors = [ "you",]
edition = "2018"
publish = false

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

[dev-dependencies]
num-bigint = "0.4.2"

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

[dev-dependencies.multiversx-sc-scenario]
version = "0.41.1"
14 changes: 14 additions & 0 deletions contracts/paymaster/meta/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "paymaster-meta"
version = "0.0.0"
edition = "2018"
publish = false
authors = [ "you",]

[dev-dependencies]

[dependencies.paymaster]
path = ".."

[dependencies.multiversx-sc-meta]
version = "0.43.4"
3 changes: 3 additions & 0 deletions contracts/paymaster/meta/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
multiversx_sc_meta::cli_main::<paymaster::AbiProvider>();
}
3 changes: 3 additions & 0 deletions contracts/paymaster/multiversx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"language": "rust"
}
18 changes: 18 additions & 0 deletions contracts/paymaster/mxsc-template.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name = "empty"
contract_trait = "EmptyContract"
src_file = "empty.rs"
rename_pairs = [
[
"blockchain.set_current_dir_from_workspace(\"contracts/examples/empty\");",
"// blockchain.set_current_dir_from_workspace(\"relative path to your workspace, if applicable\");",
],
]
files_include = [
"meta",
"scenarios",
"src",
"tests",
"wasm/Cargo.toml",
"Cargo.toml",
"multiversx.json",
]
39 changes: 39 additions & 0 deletions contracts/paymaster/scenarios/empty.scen.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "paymaster",
"steps": [
{
"step": "setState",
"accounts": {
"address:owner": {
"nonce": "1",
"balance": "0"
}
},
"newAddresses": [
{
"creatorAddress": "address:owner",
"creatorNonce": "1",
"newAddress": "sc:empty"
}
]
},
{
"step": "scDeploy",
"id": "deploy",
"tx": {
"from": "address:owner",
"contractCode": "file:../output/paymaster.wasm",
"arguments": [],
"gasLimit": "5,000,000",
"gasPrice": "0"
},
"expect": {
"out": [],
"status": "",
"logs": [],
"gas": "*",
"refund": "*"
}
}
]
}
61 changes: 61 additions & 0 deletions contracts/paymaster/src/forward_call.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
multiversx_sc::imports!();

pub type PaymentsVec<M> = ManagedVec<M, EsdtTokenPayment<M>>;

static ERR_CALLBACK_MSG: &[u8] = b"Error received in callback:";

#[multiversx_sc::module]
pub trait ForwardCall {
fn forward_call(
&self,
dest: ManagedAddress,
endpoint_name: ManagedBuffer,
endpoint_args: MultiValueEncoded<ManagedBuffer>,
payments: PaymentsVec<Self::Api>,
) {
let original_caller = self.blockchain().get_caller();

if !self.blockchain().is_smart_contract(&dest) {
self.send().direct_multi(&dest, &payments);
CostinCarabas marked this conversation as resolved.
Show resolved Hide resolved
} else {
let mut args_buffer = ManagedArgBuffer::new();
for arg in endpoint_args {
args_buffer.push_arg(arg);
}

ContractCallWithMultiEsdt::<Self::Api, ()>::new(dest, endpoint_name, payments.clone())
.with_raw_arguments(args_buffer)
.async_call()
.with_callback(
self.callbacks()
.transfer_callback(original_caller, payments),
)
.call_and_exit();
}
}
#[callback]
fn transfer_callback(
&self,
original_caller: ManagedAddress,
initial_payments: ManagedVec<EsdtTokenPayment<Self::Api>>,
#[call_result] result: ManagedAsyncCallResult<MultiValueEncoded<ManagedBuffer>>,
) -> MultiValueEncoded<ManagedBuffer> {
match result {
ManagedAsyncCallResult::Ok(return_values) => return_values,
ManagedAsyncCallResult::Err(err) => {
if !initial_payments.is_empty() {
self.send()
.direct_multi(&original_caller, &initial_payments);
}

let mut err_result = MultiValueEncoded::new();
err_result.push(ManagedBuffer::new_from_bytes(ERR_CALLBACK_MSG));
err_result.push(err.err_msg.clone());

sc_print!("{}", err.err_msg);

err_result
}
}
}
}
49 changes: 49 additions & 0 deletions contracts/paymaster/src/paymaster.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#![no_std]

use forward_call::PaymentsVec;

multiversx_sc::imports!();

pub mod forward_call;
const FEE_PAYMENT: usize = 0;

/// An empty contract. To be used as a template when starting a new contract from scratch.
#[multiversx_sc::contract]
pub trait PaymasterContract: forward_call::ForwardCall {
#[init]
fn init(&self) {}

#[endpoint(forwardExecution)]
#[payable("*")]
fn forward_execution(
&self,
relayer_addr: ManagedAddress,
dest: ManagedAddress,
endpoint_name: ManagedBuffer,
endpoint_args: MultiValueEncoded<ManagedBuffer>,
) {
let payments = self.call_value().all_esdt_transfers();

self.pay_fee_to_relayer(relayer_addr, payments.clone_value());
CostinCarabas marked this conversation as resolved.
Show resolved Hide resolved

let mut payments_without_fee = payments.clone_value();
payments_without_fee.remove(FEE_PAYMENT);

self.forward_call(dest, endpoint_name, endpoint_args, payments_without_fee);
}

fn pay_fee_to_relayer(&self, relayer_addr: ManagedAddress, payments: PaymentsVec<Self::Api>) {
let mut payments_iter = payments.iter();
let fee_payment = match payments_iter.next() {
Some(fee) => fee,
None => sc_panic!("Fee payment is missing!"),
};

self.send().direct_esdt(
&relayer_addr,
&fee_payment.token_identifier,
0,
&fee_payment.amount,
);
}
}
10 changes: 10 additions & 0 deletions contracts/paymaster/tests/empty_scenario_go_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use multiversx_sc_scenario::*;

fn world() -> ScenarioWorld {
ScenarioWorld::vm_go()

Check failure on line 4 in contracts/paymaster/tests/empty_scenario_go_test.rs

View workflow job for this annotation

GitHub Actions / Contracts / Wasm tests

no function or associated item named `vm_go` found for struct `multiversx_sc_scenario::ScenarioWorld` in the current scope

Check failure on line 4 in contracts/paymaster/tests/empty_scenario_go_test.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] contracts/paymaster/tests/empty_scenario_go_test.rs#L4

error[E0599]: no function or associated item named `vm_go` found for struct `multiversx_sc_scenario::ScenarioWorld` in the current scope --> contracts/paymaster/tests/empty_scenario_go_test.rs:4:20 | 4 | ScenarioWorld::vm_go() | ^^^^^ function or associated item not found in `ScenarioWorld`
Raw output
contracts/paymaster/tests/empty_scenario_go_test.rs:4:20:e:error[E0599]: no function or associated item named `vm_go` found for struct `multiversx_sc_scenario::ScenarioWorld` in the current scope
 --> contracts/paymaster/tests/empty_scenario_go_test.rs:4:20
  |
4 |     ScenarioWorld::vm_go()
  |                    ^^^^^ function or associated item not found in `ScenarioWorld`


__END__
}

#[test]
fn empty_go() {
world().run("scenarios/empty.scen.json");

Check failure on line 9 in contracts/paymaster/tests/empty_scenario_go_test.rs

View workflow job for this annotation

GitHub Actions / Contracts / Wasm tests

no method named `run` found for struct `multiversx_sc_scenario::ScenarioWorld` in the current scope

Check failure on line 9 in contracts/paymaster/tests/empty_scenario_go_test.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] contracts/paymaster/tests/empty_scenario_go_test.rs#L9

error[E0599]: no method named `run` found for struct `multiversx_sc_scenario::ScenarioWorld` in the current scope --> contracts/paymaster/tests/empty_scenario_go_test.rs:9:13 | 9 | world().run("scenarios/empty.scen.json"); | ^^^ method not found in `ScenarioWorld`
Raw output
contracts/paymaster/tests/empty_scenario_go_test.rs:9:13:e:error[E0599]: no method named `run` found for struct `multiversx_sc_scenario::ScenarioWorld` in the current scope
 --> contracts/paymaster/tests/empty_scenario_go_test.rs:9:13
  |
9 |     world().run("scenarios/empty.scen.json");
  |             ^^^ method not found in `ScenarioWorld`


__END__
}
14 changes: 14 additions & 0 deletions contracts/paymaster/tests/empty_scenario_rs_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use multiversx_sc_scenario::*;

fn world() -> ScenarioWorld {
let mut blockchain = ScenarioWorld::new();
blockchain.set_current_dir_from_workspace("contracts/examples/empty");

blockchain.register_contract("file:output/paymaster.wasm", paymaster::ContractBuilder);

Check failure on line 7 in contracts/paymaster/tests/empty_scenario_rs_test.rs

View workflow job for this annotation

GitHub Actions / Contracts / Rust tests

the trait bound `paymaster::ContractBuilder: CallableContractBuilder` is not satisfied

Check failure on line 7 in contracts/paymaster/tests/empty_scenario_rs_test.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] contracts/paymaster/tests/empty_scenario_rs_test.rs#L7

error[E0277]: the trait bound `paymaster::ContractBuilder: multiversx_sc_scenario::multiversx_sc::contract_base::CallableContractBuilder` is not satisfied --> contracts/paymaster/tests/empty_scenario_rs_test.rs:7:64 | 7 | blockchain.register_contract("file:output/paymaster.wasm", paymaster::ContractBuilder); | ----------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `multiversx_sc_scenario::multiversx_sc::contract_base::CallableContractBuilder` is not implemented for `paymaster::ContractBuilder` | | | required by a bound introduced by this call | note: required by a bound in `multiversx_sc_scenario::ScenarioWorld::register_contract` --> /home/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/multiversx-sc-scenario-0.41.3/src/facade/scenario_world.rs:53:33 | 53 | pub fn register_contract<B: CallableContractBuilder>( | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `ScenarioWorld::register_contract`
Raw output
contracts/paymaster/tests/empty_scenario_rs_test.rs:7:64:e:error[E0277]: the trait bound `paymaster::ContractBuilder: multiversx_sc_scenario::multiversx_sc::contract_base::CallableContractBuilder` is not satisfied
  --> contracts/paymaster/tests/empty_scenario_rs_test.rs:7:64
   |
7  |     blockchain.register_contract("file:output/paymaster.wasm", paymaster::ContractBuilder);
   |                -----------------                               ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `multiversx_sc_scenario::multiversx_sc::contract_base::CallableContractBuilder` is not implemented for `paymaster::ContractBuilder`
   |                |
   |                required by a bound introduced by this call
   |
note: required by a bound in `multiversx_sc_scenario::ScenarioWorld::register_contract`
  --> /home/runner/.cargo/registry/src/index.crates.io-6f17d22bba15001f/multiversx-sc-scenario-0.41.3/src/facade/scenario_world.rs:53:33
   |
53 |     pub fn register_contract<B: CallableContractBuilder>(
   |                                 ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `ScenarioWorld::register_contract`


__END__
blockchain
}

#[test]
fn empty_rs() {
world().run("scenarios/empty.scen.json");

Check failure on line 13 in contracts/paymaster/tests/empty_scenario_rs_test.rs

View workflow job for this annotation

GitHub Actions / Contracts / Rust tests

no method named `run` found for struct `multiversx_sc_scenario::ScenarioWorld` in the current scope

Check failure on line 13 in contracts/paymaster/tests/empty_scenario_rs_test.rs

View workflow job for this annotation

GitHub Actions / clippy

[clippy] contracts/paymaster/tests/empty_scenario_rs_test.rs#L13

error[E0599]: no method named `run` found for struct `multiversx_sc_scenario::ScenarioWorld` in the current scope --> contracts/paymaster/tests/empty_scenario_rs_test.rs:13:13 | 13 | world().run("scenarios/empty.scen.json"); | ^^^ method not found in `ScenarioWorld`
Raw output
contracts/paymaster/tests/empty_scenario_rs_test.rs:13:13:e:error[E0599]: no method named `run` found for struct `multiversx_sc_scenario::ScenarioWorld` in the current scope
  --> contracts/paymaster/tests/empty_scenario_rs_test.rs:13:13
   |
13 |     world().run("scenarios/empty.scen.json");
   |             ^^^ method not found in `ScenarioWorld`


__END__
}
Loading
Loading