diff --git a/contracts/examples/ping-pong-egld/scenarios/ping-pong-call-pong-all-interrupted-2.scen.json b/contracts/examples/ping-pong-egld/scenarios/ping-pong-call-pong-all-interrupted-2.scen.json index 9253cff4f8..baf1753018 100644 --- a/contracts/examples/ping-pong-egld/scenarios/ping-pong-call-pong-all-interrupted-2.scen.json +++ b/contracts/examples/ping-pong-egld/scenarios/ping-pong-call-pong-all-interrupted-2.scen.json @@ -21,7 +21,7 @@ "to": "sc:ping-pong", "function": "pongAll", "arguments": [], - "gasLimit": "3,500,000", + "gasLimit": "4,500,000", "gasPrice": "0" }, "expect": { diff --git a/contracts/examples/ping-pong-egld/src/ping_pong.rs b/contracts/examples/ping-pong-egld/src/ping_pong.rs index 683c2a2ed5..b2b7aaa6dd 100644 --- a/contracts/examples/ping-pong-egld/src/ping_pong.rs +++ b/contracts/examples/ping-pong-egld/src/ping_pong.rs @@ -2,9 +2,9 @@ use multiversx_sc::imports::*; -mod user_status; +mod types; -use user_status::UserStatus; +use types::{ContractState, UserStatus}; /// Derived empirically. const PONG_ALL_LOW_GAS_LIMIT: u64 = 3_000_000; @@ -25,7 +25,7 @@ const PONG_ALL_LOW_GAS_LIMIT: u64 = 3_000_000; #[multiversx_sc::contract] pub trait PingPong { /// Necessary configuration when deploying: - /// `ping_amount` - the exact EGLD amounf that needs to be sent when `ping`-ing. + /// `ping_amount` - the exact EGLD amount that needs to be sent when `ping`-ing. /// `duration_in_seconds` - how much time (in seconds) until contract expires. /// `opt_activation_timestamp` - optionally specify the contract to only actvivate at a later date. /// `max_funds` - optional funding cap, no more funds than this can be added to the contract. @@ -48,7 +48,20 @@ pub trait PingPong { } #[upgrade] - fn upgrade(&self) {} + fn upgrade( + &self, + ping_amount: &BigUint, + duration_in_seconds: u64, + opt_activation_timestamp: Option, + max_funds: OptionalValue, + ) { + self.init( + ping_amount, + duration_in_seconds, + opt_activation_timestamp, + max_funds, + ) + } /// User sends some EGLD to be locked in the contract for a period of time. /// Optional `_data` argument is ignored. @@ -98,6 +111,8 @@ pub trait PingPong { sc_panic!("already withdrawn") }, } + + self.ping_event(&caller, &payment); } fn pong_by_user_id(&self, user_id: usize) -> Result<(), &'static str> { @@ -108,7 +123,8 @@ pub trait PingPong { self.user_status(user_id).set(UserStatus::Withdrawn); if let Some(user_address) = self.user_mapper().get_user_address(user_id) { let amount = self.ping_amount().get(); - self.tx().to(user_address).egld(amount).transfer(); + self.tx().to(&user_address).egld(&amount).transfer(); + self.pong_event(&user_address, &amount); Result::Ok(()) } else { Result::Err("unknown user") @@ -142,24 +158,27 @@ pub trait PingPong { /// Can only be called after expiration. #[endpoint(pongAll)] fn pong_all(&self) -> OperationCompletionStatus { + let now = self.blockchain().get_block_timestamp(); require!( - self.blockchain().get_block_timestamp() >= self.deadline().get(), + now >= self.deadline().get(), "can't withdraw before deadline" ); let num_users = self.user_mapper().get_user_count(); let mut pong_all_last_user = self.pong_all_last_user().get(); + let mut status = OperationCompletionStatus::InterruptedBeforeOutOfGas; loop { if pong_all_last_user >= num_users { // clear field and reset to 0 pong_all_last_user = 0; self.pong_all_last_user().set(pong_all_last_user); - return OperationCompletionStatus::Completed; + status = OperationCompletionStatus::Completed; + break; } if self.blockchain().get_gas_left() < PONG_ALL_LOW_GAS_LIMIT { self.pong_all_last_user().set(pong_all_last_user); - return OperationCompletionStatus::InterruptedBeforeOutOfGas; + break; } pong_all_last_user += 1; @@ -167,6 +186,10 @@ pub trait PingPong { // in case of error just ignore the error and skip let _ = self.pong_by_user_id(pong_all_last_user); } + + self.pong_all_event(now, &status, pong_all_last_user); + + status } /// Lists the addresses of all users that have `ping`-ed, @@ -176,6 +199,19 @@ pub trait PingPong { self.user_mapper().get_all_addresses().into() } + /// Returns the current contract state as a struct + /// for faster fetching from external parties + #[view(getContractState)] + fn get_contract_state(&self) -> ContractState { + ContractState { + ping_amount: self.ping_amount().get(), + deadline: self.deadline().get(), + activation_timestamp: self.activation_timestamp().get(), + max_funds: self.max_funds().get(), + pong_all_last_user: self.pong_all_last_user().get(), + } + } + // storage #[view(getPingAmount)] @@ -213,4 +249,23 @@ pub trait PingPong { #[view(pongAllLastUser)] #[storage_mapper("pongAllLastUser")] fn pong_all_last_user(&self) -> SingleValueMapper; + + // events + + /// Signals a successful ping by user with amount + #[event] + fn ping_event(&self, #[indexed] caller: &ManagedAddress, pinged_amount: &BigUint); + + /// Signals a successful pong by user with amount + #[event] + fn pong_event(&self, #[indexed] caller: &ManagedAddress, ponged_amount: &BigUint); + + /// Signals the beginning of the pong_all operation, status and last user + #[event] + fn pong_all_event( + &self, + #[indexed] timestamp: u64, + #[indexed] status: &OperationCompletionStatus, + #[indexed] pong_all_last_user: usize, + ); } diff --git a/contracts/examples/ping-pong-egld/src/types.rs b/contracts/examples/ping-pong-egld/src/types.rs new file mode 100644 index 0000000000..e83cc714d3 --- /dev/null +++ b/contracts/examples/ping-pong-egld/src/types.rs @@ -0,0 +1,20 @@ +use multiversx_sc::derive_imports::*; +use multiversx_sc::imports::*; + +#[type_abi] +#[derive(TopEncode, TopDecode, PartialEq, Eq, Clone, Copy)] +pub enum UserStatus { + New, + Registered, + Withdrawn, +} + +#[type_abi] +#[derive(TopEncode, TopDecode, Default)] +pub struct ContractState { + pub ping_amount: BigUint, + pub deadline: u64, + pub activation_timestamp: u64, + pub max_funds: Option>, + pub pong_all_last_user: usize, +} diff --git a/contracts/examples/ping-pong-egld/src/user_status.rs b/contracts/examples/ping-pong-egld/src/user_status.rs deleted file mode 100644 index 291981b0d7..0000000000 --- a/contracts/examples/ping-pong-egld/src/user_status.rs +++ /dev/null @@ -1,8 +0,0 @@ -use multiversx_sc::derive_imports::*; - -#[derive(TopEncode, TopDecode, TypeAbi, PartialEq, Eq, Clone, Copy)] -pub enum UserStatus { - New, - Registered, - Withdrawn, -} diff --git a/contracts/examples/ping-pong-egld/wasm/src/lib.rs b/contracts/examples/ping-pong-egld/wasm/src/lib.rs index 35bade6af2..ece506bfb5 100644 --- a/contracts/examples/ping-pong-egld/wasm/src/lib.rs +++ b/contracts/examples/ping-pong-egld/wasm/src/lib.rs @@ -6,9 +6,9 @@ // Init: 1 // Upgrade: 1 -// Endpoints: 10 +// Endpoints: 11 // Async Callback (empty): 1 -// Total number of exported functions: 13 +// Total number of exported functions: 14 #![no_std] @@ -24,6 +24,7 @@ multiversx_sc_wasm_adapter::endpoints! { pong => pong pongAll => pong_all getUserAddresses => get_user_addresses + getContractState => get_contract_state getPingAmount => ping_amount getDeadline => deadline getActivationTimestamp => activation_timestamp