Skip to content

Commit e1702e8

Browse files
Merge pull request #1657 from multiversx/promise-transf-callback
promise transfer no data example
2 parents 068e9b5 + 15d1db7 commit e1702e8

File tree

11 files changed

+301
-22
lines changed

11 files changed

+301
-22
lines changed

chain/vm/src/vm_err_msg.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,5 @@ pub const ERROR_SIGNALLED_BY_SMARTCONTRACT: &str = "error signalled by smartcont
1414

1515
pub const ERROR_NO_CALLBACK_CLOSURE: &str =
1616
"no callback for closure, cannot call callback directly";
17+
18+
pub const PROMISES_TOKENIZE_FAILED: &str = "tokenize failed";

chain/vm/src/vm_hooks/vh_handler/vh_send.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::{
55
},
66
tx_mock::{AsyncCallTxData, Promise, TxFunctionName, TxTokenTransfer},
77
types::{top_encode_big_uint, top_encode_u64, RawHandle, VMAddress, VMCodeMetadata},
8+
vm_err_msg,
89
vm_hooks::VMHooksHandlerSource,
910
};
1011
use num_traits::Zero;
@@ -215,6 +216,11 @@ pub trait VMHooksSend: VMHooksHandlerSource {
215216
let endpoint_name = self
216217
.m_types_lock()
217218
.mb_to_function_name(endpoint_name_handle);
219+
if endpoint_name.is_empty() {
220+
// immitating the behavior of the VM
221+
// TODO: lift limitation from the VM, then also remove this condition here
222+
self.vm_error(vm_err_msg::PROMISES_TOKENIZE_FAILED);
223+
}
218224
let arg_buffer = self.m_types_lock().mb_get_vec_of_bytes(arg_buffer_handle);
219225
let tx_hash = self.tx_hash();
220226
let callback_closure_data = self.m_types_lock().mb_get(callback_closure_handle).to_vec();

contracts/feature-tests/composability/promises-features/src/common.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ pub trait CommonModule {
2121
#[indexed] payment: &BigUint,
2222
);
2323

24+
#[event("callback_result")]
25+
fn callback_result(&self, #[indexed] result: MultiValueEncoded<ManagedBuffer>);
26+
2427
#[view]
2528
#[storage_mapper("callback_data")]
2629
fn callback_data(&self) -> VecMapper<CallbackData<Self::Api>>;

contracts/feature-tests/composability/promises-features/src/fwd_call_promises.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,50 @@ pub trait CallPromisesModule: common::CommonModule {
5555
args: ManagedVec::new(),
5656
});
5757
}
58+
59+
#[endpoint]
60+
#[payable("*")]
61+
fn forward_payment_callback(&self, to: ManagedAddress) {
62+
let payment = self.call_value().any_payment();
63+
let gas_limit = self.blockchain().get_gas_left() / 2;
64+
65+
self.tx()
66+
.to(&to)
67+
.gas(gas_limit)
68+
.payment(payment)
69+
.callback(self.callbacks().transfer_callback())
70+
.register_promise();
71+
}
72+
73+
#[promises_callback]
74+
fn transfer_callback(&self, #[call_result] result: MultiValueEncoded<ManagedBuffer>) {
75+
self.callback_result(result);
76+
77+
let call_value = self.call_value().any_payment();
78+
match call_value {
79+
EgldOrMultiEsdtPayment::Egld(egld) => {
80+
self.retrieve_funds_callback_event(&EgldOrEsdtTokenIdentifier::egld(), 0, &egld);
81+
let _ = self.callback_data().push(&CallbackData {
82+
callback_name: ManagedBuffer::from(b"transfer_callback"),
83+
token_identifier: EgldOrEsdtTokenIdentifier::egld(),
84+
token_nonce: 0,
85+
token_amount: egld,
86+
args: ManagedVec::new(),
87+
});
88+
},
89+
EgldOrMultiEsdtPayment::MultiEsdt(multi_esdt) => {
90+
for esdt in multi_esdt.into_iter() {
91+
let token_identifier = EgldOrEsdtTokenIdentifier::esdt(esdt.token_identifier);
92+
self.retrieve_funds_callback_event(&token_identifier, 0, &esdt.amount);
93+
let _ = self.callback_data().push(&CallbackData {
94+
callback_name: ManagedBuffer::from(b"transfer_callback"),
95+
token_identifier,
96+
token_nonce: 0,
97+
token_amount: esdt.amount,
98+
args: ManagedVec::new(),
99+
});
100+
}
101+
},
102+
}
103+
}
58104
}

contracts/feature-tests/composability/promises-features/src/promises_feature_proxy.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,18 @@ where
127127
.original_result()
128128
}
129129

130+
pub fn forward_payment_callback<
131+
Arg0: ProxyArg<ManagedAddress<Env::Api>>,
132+
>(
133+
self,
134+
to: Arg0,
135+
) -> TxTypedCall<Env, From, To, (), Gas, ()> {
136+
self.wrapped_tx
137+
.raw_call("forward_payment_callback")
138+
.argument(&to)
139+
.original_result()
140+
}
141+
130142
pub fn promise_raw_single_token<
131143
Arg0: ProxyArg<ManagedAddress<Env::Api>>,
132144
Arg1: ProxyArg<ManagedBuffer<Env::Api>>,

contracts/feature-tests/composability/promises-features/wasm/src/lib.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
////////////////////////////////////////////////////
66

77
// Init: 1
8-
// Endpoints: 10
8+
// Endpoints: 11
99
// Async Callback (empty): 1
10-
// Promise callbacks: 3
11-
// Total number of exported functions: 15
10+
// Promise callbacks: 4
11+
// Total number of exported functions: 17
1212

1313
#![no_std]
1414

@@ -24,12 +24,14 @@ multiversx_sc_wasm_adapter::endpoints! {
2424
clear_callback_data => clear_callback_data
2525
forward_promise_accept_funds => forward_promise_accept_funds
2626
forward_promise_retrieve_funds => forward_promise_retrieve_funds
27+
forward_payment_callback => forward_payment_callback
2728
promise_raw_single_token => promise_raw_single_token
2829
promise_raw_multi_transfer => promise_raw_multi_transfer
2930
forward_sync_retrieve_funds_bt => forward_sync_retrieve_funds_bt
3031
forward_sync_retrieve_funds_bt_twice => forward_sync_retrieve_funds_bt_twice
3132
forward_promise_retrieve_funds_back_transfers => forward_promise_retrieve_funds_back_transfers
3233
retrieve_funds_callback => retrieve_funds_callback
34+
transfer_callback => transfer_callback
3335
the_one_callback => the_one_callback
3436
retrieve_funds_back_transfers_callback => retrieve_funds_back_transfers_callback
3537
)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"steps": [
3+
{
4+
"step": "setState",
5+
"accounts": {
6+
"address:a_user": {
7+
"nonce": "0",
8+
"balance": "1000"
9+
},
10+
"sc:vault": {
11+
"nonce": "0",
12+
"balance": "0",
13+
"code": "mxsc:../vault/output/vault.mxsc.json"
14+
},
15+
"sc:forwarder": {
16+
"nonce": "0",
17+
"balance": "0",
18+
"code": "mxsc:../promises-features/output/promises-features.mxsc.json"
19+
}
20+
}
21+
},
22+
{
23+
"step": "scCall",
24+
"id": "1",
25+
"tx": {
26+
"from": "address:a_user",
27+
"to": "sc:forwarder",
28+
"egldValue": "1000",
29+
"function": "forward_payment_callback",
30+
"arguments": [
31+
"sc:vault"
32+
],
33+
"gasLimit": "60,000,000",
34+
"gasPrice": "0"
35+
},
36+
"expect": {
37+
"out": [],
38+
"status": "10",
39+
"message": "str:tokenize failed",
40+
"gas": "*",
41+
"refund": "*"
42+
}
43+
}
44+
]
45+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
{
2+
"steps": [
3+
{
4+
"step": "setState",
5+
"accounts": {
6+
"address:a_user": {
7+
"nonce": "0",
8+
"balance": "0",
9+
"esdt": {
10+
"str:FWD-TOKEN": "1000"
11+
}
12+
},
13+
"sc:vault": {
14+
"nonce": "0",
15+
"balance": "0",
16+
"code": "mxsc:../vault/output/vault.mxsc.json"
17+
},
18+
"sc:forwarder": {
19+
"nonce": "0",
20+
"balance": "0",
21+
"code": "mxsc:../promises-features/output/promises-features.mxsc.json"
22+
}
23+
}
24+
},
25+
{
26+
"step": "scCall",
27+
"id": "1",
28+
"tx": {
29+
"from": "address:a_user",
30+
"to": "sc:forwarder",
31+
"esdtValue": [
32+
{
33+
"tokenIdentifier": "str:FWD-TOKEN",
34+
"value": "1000"
35+
}
36+
],
37+
"function": "forward_payment_callback",
38+
"arguments": [
39+
"sc:vault"
40+
],
41+
"gasLimit": "60,000,000",
42+
"gasPrice": "0"
43+
},
44+
"expect": {
45+
"out": [],
46+
"status": "0",
47+
"logs": [
48+
{
49+
"address": "sc:forwarder",
50+
"endpoint": "str:ESDTTransfer",
51+
"topics": [
52+
"str:FWD-TOKEN",
53+
"",
54+
"1000",
55+
"sc:vault"
56+
],
57+
"data": [
58+
"str:AsyncCall",
59+
"str:ESDTTransfer",
60+
"str:FWD-TOKEN",
61+
"1000"
62+
]
63+
},
64+
{
65+
"address": "sc:vault",
66+
"endpoint": "str:transferValueOnly",
67+
"topics": [
68+
"",
69+
"sc:forwarder"
70+
],
71+
"data": [
72+
"str:AsyncCallback",
73+
"str:transfer_callback",
74+
"0x00"
75+
]
76+
},
77+
{
78+
"address": "sc:forwarder",
79+
"endpoint": "str:transfer_callback",
80+
"topics": [
81+
"str:callback_result",
82+
"0x00"
83+
],
84+
"data": [
85+
""
86+
]
87+
},
88+
{
89+
"address": "sc:forwarder",
90+
"endpoint": "str:transfer_callback",
91+
"topics": [
92+
"str:retrieve_funds_callback",
93+
"str:EGLD",
94+
"",
95+
""
96+
],
97+
"data": [
98+
""
99+
]
100+
}
101+
],
102+
"gas": "*",
103+
"refund": "*"
104+
}
105+
},
106+
{
107+
"step": "checkState",
108+
"accounts": {
109+
"address:a_user": {
110+
"nonce": "*",
111+
"balance": "0",
112+
"storage": {},
113+
"code": ""
114+
},
115+
"sc:vault": {
116+
"nonce": "0",
117+
"balance": "0",
118+
"esdt": {
119+
"str:FWD-TOKEN": "1000"
120+
},
121+
"storage": {
122+
"str:call_counts|nested:str:accept_funds": "0"
123+
},
124+
"code": "mxsc:../vault/output/vault.mxsc.json"
125+
},
126+
"sc:forwarder": {
127+
"nonce": "0",
128+
"balance": "0",
129+
"storage": {
130+
"str:callback_data.len": "1",
131+
"str:callback_data.item|u32:1": [
132+
"nested:str:transfer_callback",
133+
"nested:str:EGLD",
134+
"u64:0",
135+
"u32:0",
136+
"u32:0"
137+
]
138+
139+
},
140+
"code": "mxsc:../promises-features/output/promises-features.mxsc.json"
141+
}
142+
}
143+
}
144+
]
145+
}

contracts/feature-tests/composability/tests/composability_scenario_go_test.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,16 @@ fn promises_call_callback_directly_go() {
437437
world().run("scenarios/promises_call_callback_directly.scen.json");
438438
}
439439

440+
#[test]
441+
fn promises_call_transfer_callback_egld_go() {
442+
world().run("scenarios/promises_call_transfer_callback_egld.scen.json");
443+
}
444+
445+
#[test]
446+
fn promises_call_transfer_callback_esdt_go() {
447+
world().run("scenarios/promises_call_transfer_callback_esdt.scen.json");
448+
}
449+
440450
#[test]
441451
#[ignore = "TODO"]
442452
fn promises_multi_transfer_go() {

contracts/feature-tests/composability/tests/composability_scenario_rs_test.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,16 @@ fn promises_call_callback_directly_rs() {
488488
world().run("scenarios/promises_call_callback_directly.scen.json");
489489
}
490490

491+
#[test]
492+
fn promises_call_transfer_callback_egld_rs() {
493+
world().run("scenarios/promises_call_transfer_callback_egld.scen.json");
494+
}
495+
496+
#[test]
497+
fn promises_call_transfer_callback_esdt_rs() {
498+
world().run("scenarios/promises_call_transfer_callback_esdt.scen.json");
499+
}
500+
491501
#[test]
492502
fn promises_multi_transfer_rs() {
493503
world().run("scenarios/promises_multi_transfer.scen.json");

0 commit comments

Comments
 (0)