-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
- Loading branch information
There are no files selected for viewing
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*/ |
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" |
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" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
fn main() { | ||
multiversx_sc_meta::cli_main::<paymaster::AbiProvider>(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"language": "rust" | ||
} |
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", | ||
] |
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": "*" | ||
} | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
use crate::forward_call::PaymentsVec; | ||
|
||
multiversx_sc::imports!(); | ||
|
||
pub mod pair_proxy { | ||
#[multiversx_sc::proxy] | ||
pub trait PairProxy { | ||
#[view(getSafePriceByDefaultOffset)] | ||
fn get_safe_price_by_default_offset( | ||
&self, | ||
pair_address: ManagedAddress, | ||
input_payment: EsdtTokenPayment, | ||
) -> EsdtTokenPayment; | ||
} | ||
} | ||
|
||
#[multiversx_sc::module] | ||
pub trait FeesModule { | ||
#[only_owner] | ||
#[endpoint(addAcceptedFeesTokens)] | ||
fn add_accepted_fees_tokens( | ||
&self, | ||
accepted_tokens: MultiValueEncoded<MultiValue2<TokenIdentifier, ManagedAddress>>, | ||
) { | ||
for pair in accepted_tokens { | ||
let (token_id, pair_address) = pair.into_tuple(); | ||
require!(token_id.is_valid_esdt_identifier(), "Invalid token"); | ||
|
||
self.pair_address_for_token(&token_id).set(pair_address); | ||
} | ||
} | ||
|
||
fn get_price(&self, token_id: TokenIdentifier, amount: BigUint) -> BigUint { | ||
let mapper = self.pair_address_for_token(&token_id); | ||
require!( | ||
!mapper.is_empty(), | ||
"There is no pair addres for the token provided!" | ||
); | ||
|
||
let pair_address = mapper.get(); | ||
let price_query_address = self.price_query_address().get(); | ||
let price: EsdtTokenPayment = self | ||
.pair_proxy(price_query_address) | ||
.get_safe_price_by_default_offset( | ||
pair_address, | ||
EsdtTokenPayment::new(token_id, 0, amount), | ||
) | ||
.execute_on_dest_context(); | ||
|
||
price.amount | ||
} | ||
|
||
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, | ||
); | ||
} | ||
|
||
#[proxy] | ||
fn pair_proxy(&self, sc_address: ManagedAddress) -> pair_proxy::Proxy<Self::Api>; | ||
|
||
#[storage_mapper("pairAddressForToken")] | ||
fn pair_address_for_token( | ||
&self, | ||
token_id: &TokenIdentifier, | ||
) -> SingleValueMapper<ManagedAddress>; | ||
|
||
#[storage_mapper("priceQueryAddress")] | ||
fn price_query_address(&self) -> SingleValueMapper<ManagedAddress>; | ||
} |
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); | ||
} 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 | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#![no_std] | ||
|
||
multiversx_sc::imports!(); | ||
|
||
pub mod fees; | ||
pub mod forward_call; | ||
|
||
/// An empty contract. To be used as a template when starting a new contract from scratch. | ||
#[multiversx_sc::contract] | ||
pub trait PaymasterContract: fees::FeesModule + forward_call::ForwardCall { | ||
#[init] | ||
fn init(&self, price_query_address: ManagedAddress) { | ||
self.price_query_address().set(price_query_address); | ||
} | ||
|
||
#[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()); | ||
let mut payments_without_fee = payments.clone_value(); | ||
payments_without_fee.remove(0); | ||
self.forward_call(dest, endpoint_name, endpoint_args, payments_without_fee); | ||
} | ||
} |
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 GitHub Actions / Contracts / Rust tests
Check failure on line 4 in contracts/paymaster/tests/empty_scenario_go_test.rs GitHub Actions / clippy[clippy] contracts/paymaster/tests/empty_scenario_go_test.rs#L4
Raw output
|
||
} | ||
|
||
#[test] | ||
fn empty_go() { | ||
world().run("scenarios/empty.scen.json"); | ||
Check failure on line 9 in contracts/paymaster/tests/empty_scenario_go_test.rs GitHub Actions / Contracts / Rust tests
Check failure on line 9 in contracts/paymaster/tests/empty_scenario_go_test.rs GitHub Actions / clippy[clippy] contracts/paymaster/tests/empty_scenario_go_test.rs#L9
Raw output
|
||
} |
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 GitHub Actions / Contracts / Wasm tests
Check failure on line 7 in contracts/paymaster/tests/empty_scenario_rs_test.rs GitHub Actions / clippy[clippy] contracts/paymaster/tests/empty_scenario_rs_test.rs#L7
Raw output
|
||
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 GitHub Actions / Contracts / Wasm tests
Check failure on line 13 in contracts/paymaster/tests/empty_scenario_rs_test.rs GitHub Actions / clippy[clippy] contracts/paymaster/tests/empty_scenario_rs_test.rs#L13
Raw output
|
||
} |