Build on MultiversX
💰 Funding the Contract
Next, let’s set things up so people can start donating to reach the funding goal. This also tracks who donated and how much:
#\[view(getDeposit)\]
#\[storage_mapper("deposit")\]
fn deposit(&self, donor: &ManagedAddress) -> SingleValueMapper<BigUint>;
#\[endpoint\]
#\[payable("EGLD")\]
fn fund(&self) {
let payment = [self.call](http://self.call)\_value().egld_value();
let caller = self.blockchain().get_caller();
self.deposit(&caller).update(|deposit| *deposit +=* &payment);
}
Stop Donations After the Deadline
We need to ensure no one donates after the campaign’s deadline, so we’ll add a validation check:
#\[endpoint\]
#\[payable("EGLD")\]
fn fund(&self) {
let payment = [self.call](http://self.call)\_value().egld_value();
let current_time = self.blockchain().get_block_timestamp();
require!(current_time < self.deadline().get(), "cannot fund after deadline");
let caller = self.blockchain().get_caller();
self.deposit(&caller).update(|deposit| *deposit +=* &payment);
}
Now, donations are locked after the deadline passes. No more sneaking in late contributions!
Checking the Contract's Status
We’ll make it easy to check if the crowdfunding goal was reached, if it’s still open, or if it failed. Add an enum to make it clear:
#\[derive(TopEncode, TopDecode, TypeAbi, PartialEq, Clone, Copy)\]
pub enum Status {
FundingPeriod,
Successful,
Failed,
}
Place this outside the contract trait, and be sure to import the required types:
multiversx_sc::derive_imports!();
We can now use the type Status just like we use the other types, so we can write the following method in the contract trait:
#\[view\]
fn status(&self) -> Status {
if self.blockchain().get_block_timestamp() <= self.deadline().get() {
Status::FundingPeriod
} else if self.get_current_funds() >= [self.target](http://self.target)().get() {
Status::Successful
} else {
Status::Failed
}
}
#\[view(getCurrentFunds)\]
fn get_current_funds(&self) -> BigUint {
self.blockchain().get_sc_balance(&EgldOrEsdtTokenIdentifier::egld(), 0)
}
Claiming Funds!
If the campaign succeeds, the project creator can claim the funds. Otherwise, donors get their money back.
#\[endpoint\]
fn claim(&self) {
match self.status() {
Status::FundingPeriod => sc_panic!("cannot claim before deadline"),
Status::Successful => {
let caller = self.blockchain().get_caller();
require!(
caller == self.blockchain().get_owner_address(),
"only owner can claim successful funding"
);
let sc_balance = self.get_current_funds();
self.send().direct_egld(&caller, &sc_balance);
},
Status::Failed => {
let caller = self.blockchain().get_caller();
let deposit = self.deposit(&caller).get();
if deposit > 0u32 {
self.deposit(&caller).clear();
self.send().direct_egld(&caller, &deposit);
}
},
}
}
That’s it — you did it! 🎉 You’ve created a crowdfunding contract where anyone can contribute to a project, with protections in place for all parties involved. Now, go forth and fund some amazing projects!
Want the full code? Check it out on GitHub.
Comments
You need to enroll in the course to be able to comment!