diff --git a/Cargo.toml b/Cargo.toml index b4adfcb4..4950b7e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,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", diff --git a/contracts/adder/src/adder.rs b/contracts/adder/src/adder.rs index f7c47ab0..7357ddb1 100644 --- a/contracts/adder/src/adder.rs +++ b/contracts/adder/src/adder.rs @@ -16,6 +16,7 @@ pub trait Adder { } /// Add desired amount to the storage variable. + #[payable("*")] #[endpoint] fn add(&self, value: BigUint) { self.sum().update(|sum| *sum += value); diff --git a/contracts/paymaster/.gitignore b/contracts/paymaster/.gitignore new file mode 100644 index 00000000..2c76bc98 --- /dev/null +++ b/contracts/paymaster/.gitignore @@ -0,0 +1,7 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +*/target/ + +# The mxpy output +/output*/ diff --git a/contracts/paymaster/Cargo.toml b/contracts/paymaster/Cargo.toml new file mode 100644 index 00000000..0db9c936 --- /dev/null +++ b/contracts/paymaster/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "paymaster" +version = "0.0.0" +authors = [ "MultiversX " ] +edition = "2018" +publish = false +readme = "README.md" + + +[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.43.4" + +[dev-dependencies.adder] +path = "../adder" diff --git a/contracts/paymaster/README.md b/contracts/paymaster/README.md new file mode 100644 index 00000000..af4fb248 --- /dev/null +++ b/contracts/paymaster/README.md @@ -0,0 +1,40 @@ +# Paymaster SC + +## Overview + +**Definition of problem**: the user needs to have a gas token (eGLD in case of MultiversX) to be able to do anything on the blockchain. +This is a hard concept to explain to non-crypto users. +Also gives some headaches for crypto users as well for the first steps of onboarding. +Imagine those people who bridge their NFTs or those who bridge USDC to a new account. +The new account can’t do anything until it does not have some eGLD to pay for the transactions. + +In order for users to onboard faster to xPortal we introduced the concept of relayed transactions (we have v1, v2 and soon v3 of it). +This means a relayer can wrap the user transaction inside a relayedTX and in this case the relayer pays for the gas, but the user’s transaction is getting executed. +Right now, the relayers we use are free of charge, thus they do this service for new users for free, but they actually need eGLD to do the transactions. +When we speak about a few hundred users, this is not an issue, but when you want to scale up relaying transactions to thousands/millions of users, it becomes unsustainable. + +## Implementation + +Paymaster is a SC that makes relayed transactions sustainable. +This means that a user who doesn't own EGLD (native token) can make transactions by paying a fee in another token. + +The Paymaster's objective is twofold: +- take a fee and send it to the Relayers; +- execute what the user wants to be executed. + + +The contract has only one endpoint: `forward_execution` and can be called by anyone. +The user will use `MultiESDTNFTTransfer` support to send multiple payments: +- first payment is always the fee that will be sent to the Relayer; +- rest of the payments will be what users want to send. + +One example of userTX is: +``` +MultiESDTNFTTransfer@paymasterSCAddr@feeTokenID@nonce@value@listofOther(tokenID,nonce,value)@forwardExecution@relayerAddr@destination@endpoint@extraArguments + +``` + +After sending the Relayer the fee, `forward_execution` endpoint will make an *asynchronous call* to the destination. +The destionation can be a user or a smart contract. + +We register a callback to the *asynchronous call*. In case of failure the paymaster SC sends the tokens back to the user. \ No newline at end of file diff --git a/contracts/paymaster/meta/Cargo.toml b/contracts/paymaster/meta/Cargo.toml new file mode 100644 index 00000000..20157c88 --- /dev/null +++ b/contracts/paymaster/meta/Cargo.toml @@ -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" diff --git a/contracts/paymaster/meta/src/main.rs b/contracts/paymaster/meta/src/main.rs new file mode 100644 index 00000000..275bd693 --- /dev/null +++ b/contracts/paymaster/meta/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + multiversx_sc_meta::cli_main::(); +} diff --git a/contracts/paymaster/multiversx.json b/contracts/paymaster/multiversx.json new file mode 100644 index 00000000..73655396 --- /dev/null +++ b/contracts/paymaster/multiversx.json @@ -0,0 +1,3 @@ +{ + "language": "rust" +} \ No newline at end of file diff --git a/contracts/paymaster/mxsc-template.toml b/contracts/paymaster/mxsc-template.toml new file mode 100644 index 00000000..441addd7 --- /dev/null +++ b/contracts/paymaster/mxsc-template.toml @@ -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", +] diff --git a/contracts/paymaster/scenarios/empty.scen.json b/contracts/paymaster/scenarios/empty.scen.json new file mode 100644 index 00000000..b44fde46 --- /dev/null +++ b/contracts/paymaster/scenarios/empty.scen.json @@ -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": "*" + } + } + ] +} \ No newline at end of file diff --git a/contracts/paymaster/src/forward_call.rs b/contracts/paymaster/src/forward_call.rs new file mode 100644 index 00000000..5c29b644 --- /dev/null +++ b/contracts/paymaster/src/forward_call.rs @@ -0,0 +1,53 @@ +multiversx_sc::imports!(); + +pub type PaymentsVec = ManagedVec>; + +static ERR_CALLBACK_MSG: &[u8] = b"Error received in callback:"; +pub const ESDT_TRANSFER_FUNC_NAME: &str = "ESDTTransfer"; +#[multiversx_sc::module] +pub trait ForwardCall { + fn forward_call( + &self, + dest: ManagedAddress, + endpoint_name: ManagedBuffer, + endpoint_args: MultiValueEncoded, + payments: PaymentsVec, + ) { + let original_caller = self.blockchain().get_caller(); + + self.send() + .contract_call::<()>(dest, endpoint_name) + .with_raw_arguments(endpoint_args.to_arg_buffer()) + .with_multi_token_transfer(payments) + .async_call() + .with_callback(self.callbacks().transfer_callback(original_caller)) + .call_and_exit(); + } + + #[callback] + fn transfer_callback( + &self, + original_caller: ManagedAddress, + #[call_result] result: ManagedAsyncCallResult>, + ) -> MultiValueEncoded { + let initial_payments = self.call_value().all_esdt_transfers(); + + 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 + } + } + } +} diff --git a/contracts/paymaster/src/paymaster.rs b/contracts/paymaster/src/paymaster.rs new file mode 100644 index 00000000..e989f204 --- /dev/null +++ b/contracts/paymaster/src/paymaster.rs @@ -0,0 +1,39 @@ +#![no_std] + +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, + ) { + let payments = self.call_value().all_esdt_transfers(); + require!(!payments.is_empty(), "There is no fee for payment!"); + + let fee_payment = payments.get(FEE_PAYMENT); + self.send().direct_esdt( + &relayer_addr, + &fee_payment.token_identifier, + 0, + &fee_payment.amount, + ); + + 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); + } +} diff --git a/contracts/paymaster/tests/paymaster_blackbox_test.rs b/contracts/paymaster/tests/paymaster_blackbox_test.rs new file mode 100644 index 00000000..65b3f0b6 --- /dev/null +++ b/contracts/paymaster/tests/paymaster_blackbox_test.rs @@ -0,0 +1,275 @@ +use multiversx_sc::{ + codec::{multi_types::MultiValueVec, top_encode_to_vec_u8_or_panic}, + storage::mappers::SingleValue, + types::{Address, BigUint}, +}; +use multiversx_sc_scenario::{ + api::StaticApi, + scenario_model::{ + Account, AddressValue, CheckAccount, CheckStateStep, ScCallStep, ScDeployStep, ScQueryStep, + SetStateStep, TxExpect, + }, + *, +}; + +use adder::ProxyTrait as _; +use paymaster::ProxyTrait as _; + +const PAYMASTER_ADDRESS_EXPR: &str = "sc:paymaster"; +const RELAYER_ADDRESS_EXPR: &str = "address:relayer"; +const CALLEE_SC_ADDER_ADDRESS_EXPR: &str = "sc:adder"; +const PAYMASTER_PATH_EXPR: &str = "file:output/paymaster.wasm"; +const ADDER_PATH_EXPR: &str = "file:tests/test-contracts/adder.wasm"; +const CALLER_ADDRESS_EXPR: &str = "address:caller"; +const CALLEE_USER_ADDRESS_EXPR: &str = "address:callee_user"; +const OWNER_ADDRESS_EXPR: &str = "address:owner"; +const BALANCE: &str = "100,000,000"; +const PAYMASTER_TOKEN_ID_EXPR: &str = "str:PAYMSTR-123456"; +const FEE_TOKEN_ID_EXPR: &str = "str:FEE-123456"; +const ADDITIONAL_TOKEN_ID_EXPR: &str = "str:ADDIT-123456"; +const FEE_AMOUNT: &str = "20,000"; +const INITIAL_ADD_VALUE: u64 = 5; +const ADDITIONAL_ADD_VALUE: u64 = 5; + + + +type PaymasterContract = ContractInfo>; +type AdderContract = ContractInfo>; + +fn world() -> ScenarioWorld { + let mut blockchain = ScenarioWorld::new(); + blockchain.set_current_dir_from_workspace("contracts/paymaster"); + + blockchain.register_contract(PAYMASTER_PATH_EXPR, paymaster::ContractBuilder); + blockchain.register_contract(ADDER_PATH_EXPR, adder::ContractBuilder); + + blockchain +} + +struct PaymasterTestState { + world: ScenarioWorld, + callee_user_address: Address, + paymaster_contract: PaymasterContract, + relayer_address: Address, + callee_sc_adder_contract: AdderContract, +} + +impl PaymasterTestState { + fn new() -> Self { + let mut world = world(); + world.start_trace().set_state_step( + SetStateStep::new() + .put_account(OWNER_ADDRESS_EXPR, Account::new().nonce(1)) + .put_account( + CALLER_ADDRESS_EXPR, + Account::new() + .nonce(1) + .balance(BALANCE) + .esdt_balance(PAYMASTER_TOKEN_ID_EXPR, BALANCE) + .esdt_balance(FEE_TOKEN_ID_EXPR, BALANCE) + .esdt_balance(ADDITIONAL_TOKEN_ID_EXPR, BALANCE), + ) + .put_account( + CALLEE_USER_ADDRESS_EXPR, + Account::new().nonce(1).balance(BALANCE), + ) + .put_account(RELAYER_ADDRESS_EXPR, Account::new().nonce(1).balance(0u32)), + ); + + let callee_user_address = AddressValue::from(CALLEE_USER_ADDRESS_EXPR).to_address(); + + let relayer_address = AddressValue::from(RELAYER_ADDRESS_EXPR).to_address(); + let paymaster_contract = PaymasterContract::new(PAYMASTER_ADDRESS_EXPR); + let callee_sc_adder_contract = AdderContract::new(CALLEE_SC_ADDER_ADDRESS_EXPR); + // let callee_sc_adder_address = AddressValue::from(CALLEE_SC_ADDER_ADDRESS_EXPR).to_address(); + + Self { + world, + callee_user_address, + paymaster_contract, + relayer_address, + callee_sc_adder_contract, + } + } + + fn deploy_paymaster_contract(&mut self) -> &mut Self { + let paymaster_code = self.world.code_expression(PAYMASTER_PATH_EXPR); + + self.world + .set_state_step(SetStateStep::new().new_address( + OWNER_ADDRESS_EXPR, + 1, + PAYMASTER_ADDRESS_EXPR, + )) + .sc_deploy( + ScDeployStep::new() + .from(OWNER_ADDRESS_EXPR) + .code(paymaster_code) + .call(self.paymaster_contract.init()), + ); + + self + } + + fn deploy_adder_contract(&mut self) -> &mut Self { + let adder_code = self.world.code_expression(ADDER_PATH_EXPR); + + self.world + .set_state_step(SetStateStep::new().new_address( + OWNER_ADDRESS_EXPR, + 2, + CALLEE_SC_ADDER_ADDRESS_EXPR, + )) + .sc_deploy( + ScDeployStep::new() + .from(OWNER_ADDRESS_EXPR) + .code(adder_code) + .call(self.callee_sc_adder_contract.init(INITIAL_ADD_VALUE)), + ); + + self + } + + fn check_esdt_balance( + &mut self, + address_expr: &str, + token_id_expr: &str, + balance_expr: &str, + ) -> &mut Self { + self.world + .check_state_step(CheckStateStep::new().put_account( + address_expr, + CheckAccount::new().esdt_balance(token_id_expr, balance_expr), + )); + + self + } +} + +#[test] +fn test_deploy_paymasters() { + let mut state = PaymasterTestState::new(); + state.deploy_paymaster_contract(); + state.deploy_adder_contract(); +} + +#[test] +fn test_forward_call_no_fee_payment() { + let mut state = PaymasterTestState::new(); + state.deploy_paymaster_contract(); + + state.world.sc_call( + ScCallStep::new() + .from(CALLER_ADDRESS_EXPR) + .call(state.paymaster_contract.forward_execution( + state.relayer_address.clone(), + state.callee_user_address.clone(), + b"add" , + MultiValueVec::>::new(), + )) + .expect(TxExpect::user_error("str:There is no fee for payment!")), + ); +} + +#[test] +fn test_forward_call_user() { + let mut state = PaymasterTestState::new(); + state.deploy_paymaster_contract(); + + state + .world + .sc_call( + ScCallStep::new() + .from(CALLER_ADDRESS_EXPR) + .call(state.paymaster_contract.forward_execution( + state.relayer_address.clone(), + state.callee_user_address.clone(), + b"add", + MultiValueVec::>::new(), + )) + .esdt_transfer(FEE_TOKEN_ID_EXPR, 0, FEE_AMOUNT) + ) + .check_state_step(CheckStateStep::new().put_account( + RELAYER_ADDRESS_EXPR, + CheckAccount::new().esdt_balance(FEE_TOKEN_ID_EXPR, FEE_AMOUNT), + )); +} + +#[test] +fn test_forward_call_sc_adder() { + let mut state = PaymasterTestState::new(); + state.deploy_paymaster_contract(); + state.deploy_adder_contract(); + + state.check_esdt_balance(CALLER_ADDRESS_EXPR, FEE_TOKEN_ID_EXPR, BALANCE); + state.check_esdt_balance(CALLER_ADDRESS_EXPR, PAYMASTER_TOKEN_ID_EXPR, BALANCE); + + state.world.sc_call( + ScCallStep::new() + .from(CALLER_ADDRESS_EXPR) + .esdt_transfer(FEE_TOKEN_ID_EXPR, 0, FEE_AMOUNT) + .esdt_transfer(PAYMASTER_TOKEN_ID_EXPR, 0, FEE_AMOUNT) + .call(state.paymaster_contract.forward_execution( + state.relayer_address.clone(), + state.callee_sc_adder_contract.to_address(), + b"add", + MultiValueVec::from([top_encode_to_vec_u8_or_panic(&ADDITIONAL_ADD_VALUE)]), + )) + ); + + let expected_adder_sum = INITIAL_ADD_VALUE + ADDITIONAL_ADD_VALUE; + state.world.sc_query( + ScQueryStep::new() + .call(state.callee_sc_adder_contract.sum()) + .expect_value(SingleValue::from(BigUint::from(expected_adder_sum))), + ); + state.check_esdt_balance(RELAYER_ADDRESS_EXPR, FEE_TOKEN_ID_EXPR, FEE_AMOUNT); + state.check_esdt_balance( + CALLEE_SC_ADDER_ADDRESS_EXPR, + PAYMASTER_TOKEN_ID_EXPR, + FEE_AMOUNT, + ); +} + + +#[test] +fn test_forward_call_sc_adder_multiple_payments() { + let mut state = PaymasterTestState::new(); + state.deploy_paymaster_contract(); + state.deploy_adder_contract(); + + state.check_esdt_balance(CALLER_ADDRESS_EXPR, FEE_TOKEN_ID_EXPR, BALANCE); + state.check_esdt_balance(CALLER_ADDRESS_EXPR, PAYMASTER_TOKEN_ID_EXPR, BALANCE); + + state.world.sc_call( + ScCallStep::new() + .from(CALLER_ADDRESS_EXPR) + .esdt_transfer(FEE_TOKEN_ID_EXPR, 0, FEE_AMOUNT) + .esdt_transfer(PAYMASTER_TOKEN_ID_EXPR, 0, FEE_AMOUNT) + .esdt_transfer(ADDITIONAL_TOKEN_ID_EXPR, 0, FEE_AMOUNT) + .call(state.paymaster_contract.forward_execution( + state.relayer_address.clone(), + state.callee_sc_adder_contract.to_address(), + b"add", + MultiValueVec::from([top_encode_to_vec_u8_or_panic(&ADDITIONAL_ADD_VALUE)]), + )) + ); + + let expected_adder_sum = INITIAL_ADD_VALUE + ADDITIONAL_ADD_VALUE; + state.world.sc_query( + ScQueryStep::new() + .call(state.callee_sc_adder_contract.sum()) + .expect_value(SingleValue::from(BigUint::from(expected_adder_sum))), + ); + state.check_esdt_balance(RELAYER_ADDRESS_EXPR, FEE_TOKEN_ID_EXPR, FEE_AMOUNT); + state.check_esdt_balance( + CALLEE_SC_ADDER_ADDRESS_EXPR, + PAYMASTER_TOKEN_ID_EXPR, + FEE_AMOUNT, + ); + state.check_esdt_balance( + CALLEE_SC_ADDER_ADDRESS_EXPR, + ADDITIONAL_TOKEN_ID_EXPR, + FEE_AMOUNT, + ); +} diff --git a/contracts/paymaster/tests/test-contracts/adder.wasm b/contracts/paymaster/tests/test-contracts/adder.wasm new file mode 100755 index 00000000..6e7ea023 Binary files /dev/null and b/contracts/paymaster/tests/test-contracts/adder.wasm differ diff --git a/contracts/paymaster/wasm/Cargo.lock b/contracts/paymaster/wasm/Cargo.lock new file mode 100644 index 00000000..7f67dc92 --- /dev/null +++ b/contracts/paymaster/wasm/Cargo.lock @@ -0,0 +1,219 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "multiversx-sc" +version = "0.43.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "406939660d0c79dd191c6677f4b048df873a95f4531d8abafc9cdbe282bf1725" +dependencies = [ + "bitflags", + "hashbrown", + "hex-literal", + "multiversx-sc-codec", + "multiversx-sc-derive", + "num-traits", +] + +[[package]] +name = "multiversx-sc-codec" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1e15b46c17b87c0c7cdd79b041a4abd7f3a2b45f3c993f6ce38c0f233e82b6" +dependencies = [ + "arrayvec", + "multiversx-sc-codec-derive", +] + +[[package]] +name = "multiversx-sc-codec-derive" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7bc0762cd6d88f8bc54805bc652b042a61cd7fbc2d0a325010f088b78fb2ac" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "multiversx-sc-derive" +version = "0.43.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e006240993963b482fe0682ae49b2d07255495e3c86706925d119137376cdfc" +dependencies = [ + "hex", + "proc-macro2", + "quote", + "radix_trie", + "syn", +] + +[[package]] +name = "multiversx-sc-wasm-adapter" +version = "0.43.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40e721d1bc80de2ede4099a9040519486c3c1139cb0287d8fc4f9fc3e8a3f19e" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "paymaster" +version = "0.0.0" +dependencies = [ + "multiversx-sc", +] + +[[package]] +name = "paymaster-wasm" +version = "0.0.0" +dependencies = [ + "multiversx-sc-wasm-adapter", + "paymaster", +] + +[[package]] +name = "proc-macro2" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "smallvec" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" diff --git a/contracts/paymaster/wasm/Cargo.toml b/contracts/paymaster/wasm/Cargo.toml new file mode 100644 index 00000000..065dc288 --- /dev/null +++ b/contracts/paymaster/wasm/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "paymaster-wasm" +version = "0.0.0" +edition = "2018" +publish = false +authors = [ "you",] + +[lib] +crate-type = [ "cdylib",] + +[workspace] +members = [ ".",] + +[dev-dependencies] + +[profile.release] +codegen-units = 1 +opt-level = "z" +lto = true +debug = false +panic = "abort" + +[dependencies.paymaster] +path = ".." + +[dependencies.multiversx-sc-wasm-adapter] +version = "0.43.4" diff --git a/contracts/paymaster/wasm/src/lib.rs b/contracts/paymaster/wasm/src/lib.rs new file mode 100644 index 00000000..dc78bc29 --- /dev/null +++ b/contracts/paymaster/wasm/src/lib.rs @@ -0,0 +1,29 @@ +// Code generated by the multiversx-sc multi-contract system. DO NOT EDIT. + +//////////////////////////////////////////////////// +////////////////// AUTO-GENERATED ////////////////// +//////////////////////////////////////////////////// + +// Init: 1 +// Endpoints: 1 +// Async Callback: 1 +// Total number of exported functions: 3 + +#![no_std] + +// Configuration that works with rustc < 1.73.0. +// TODO: Recommended rustc version: 1.73.0 or newer. +#![feature(lang_items)] + +multiversx_sc_wasm_adapter::allocator!(); +multiversx_sc_wasm_adapter::panic_handler!(); + +multiversx_sc_wasm_adapter::endpoints! { + paymaster + ( + init => init + forwardExecution => forward_execution + ) +} + +multiversx_sc_wasm_adapter::async_callback! { paymaster }