Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DeFi tutorial refactor #1

Draft
wants to merge 5 commits into
base: step-2
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 44 additions & 106 deletions src/escrow.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
#![no_std]

multiversx_sc::imports!();
multiversx_sc::derive_imports!();

#[derive(TypeAbi, TopEncode, TopDecode)]
pub struct Offer<M: ManagedTypeApi> {
pub creator: ManagedAddress<M>,
pub identifier: TokenIdentifier<M>,
pub nonce: u64,
pub accepted_token: TokenIdentifier<M>,
pub accepted_nonce: u64,
pub accepted_amount: BigUint<M>,
pub accepted_address: ManagedAddress<M>,
}

pub mod events;
pub mod offer;

use crate::offer::Offer;
use offer::OfferId;

#[multiversx_sc::contract]
pub trait Escrow {
pub trait Escrow: offer::OfferModule + events::EventsModule {
#[init]
fn init(&self) {}

Expand All @@ -30,46 +24,29 @@ pub trait Escrow {
accepted_nonce: u64,
accepted_amount: BigUint,
accepted_address: ManagedAddress,
) -> u32 {
let caller = self.blockchain().get_caller();
) -> OfferId {
let payment = self.call_value().single_esdt();
let caller = self.blockchain().get_caller();
let new_offer_id = self.get_new_offer_id();

require!(
payment.token_nonce > 0 && payment.amount == 1,
"ESDT is not an NFT"
);

let offer_id = self.last_offer_id().update(|v| {
*v += 1;

*v
});
self.created_offers(&caller).insert(new_offer_id);
self.wanted_offers(&accepted_address).insert(new_offer_id);

let offer = Offer {
creator: caller,
identifier: payment.token_identifier,
nonce: payment.token_nonce,
accepted_token,
accepted_nonce,
accepted_amount,
accepted_address
};
let accepted_payment =
EsdtTokenPayment::new(accepted_token, accepted_nonce, accepted_amount);
let offer = Offer::new(caller, payment, accepted_payment, accepted_address);
self.offers(new_offer_id).set(&offer);

self.offers(offer_id).set(offer);
self.emit_create_offer_event(&offer);

offer_id
new_offer_id
}

#[endpoint(cancelOffer)]
fn cancel_offer(&self, offer_id: u32) {
let offers_mapper = self.offers(offer_id);

require!(!offers_mapper.is_empty(), "Offer does not exist");

fn cancel_offer(&self, offer_id: OfferId) {
let offer = self.get_offer_by_id(offer_id);
let caller = self.blockchain().get_caller();

let offer = offers_mapper.get();

require!(
offer.creator == caller,
"Only the offer creator can cancel it"
Expand All @@ -78,38 +55,33 @@ pub trait Escrow {
self.created_offers(&caller).swap_remove(&offer_id);
self.wanted_offers(&offer.accepted_address)
.swap_remove(&offer_id);

self.offers(offer_id).clear();

self.send().direct_esdt(
&offer.creator,
&offer.identifier,
offer.nonce,
&BigUint::from(1u64),
&offer.offered_payment.token_identifier,
offer.offered_payment.token_nonce,
&offer.offered_payment.amount,
);

self.emit_cancel_offer_event(&offer);
}

#[payable("*")]
#[endpoint(acceptOffer)]
fn accept_offer(&self, offer_id: u32) {
let offers_mapper = self.offers(offer_id);

require!(!offers_mapper.is_empty(), "Offer does not exist");

let offer = offers_mapper.get();
fn accept_offer(&self, offer_id: OfferId) {
let caller = self.blockchain().get_caller();
let offer = self.get_offer_by_id(offer_id);
let payment = self.call_value().single_esdt();

require!(
payment.token_identifier == offer.accepted_token
&& payment.token_nonce == offer.accepted_nonce
&& payment.amount == offer.accepted_amount,
payment == offer.accepted_payment,
"Incorrect payment for offer"
);
require!(offer.accepted_address == caller, "Incorrect caller");

self.created_offers(&offer.creator).swap_remove(&offer_id);
self.wanted_offers(&offer.accepted_address)
.swap_remove(&offer_id);

self.offers(offer_id).clear();

self.send().direct_esdt(
Expand All @@ -119,61 +91,27 @@ pub trait Escrow {
&payment.amount,
);
self.send().direct_esdt(
&offer.accepted_address,
&offer.identifier,
offer.nonce,
&BigUint::from(1u64),
&caller,
&offer.offered_payment.token_identifier,
offer.offered_payment.token_nonce,
&offer.offered_payment.amount,
);
}

#[view(getCreatedOffers)]
fn get_created_offers(
&self,
address: ManagedAddress,
) -> MultiValueEncoded<MultiValue2<u32, Offer<Self::Api>>> {
let mut result = MultiValueEncoded::new();

for offer_id in self.created_offers(&address).iter() {
result.push(self.get_offer_result(offer_id));
}

result
self.emit_accept_offer_event(&offer);
}

#[view(getWantedOffers)]
fn get_wanted_offers(
&self,
address: ManagedAddress,
) -> MultiValueEncoded<MultiValue2<u32, Offer<Self::Api>>> {
let mut result = MultiValueEncoded::new();

for offer_id in self.wanted_offers(&address).iter() {
result.push(self.get_offer_result(offer_id));
}
fn get_offer_by_id(&self, offer_id: OfferId) -> Offer<Self::Api> {
let offer_mapper = self.offers(offer_id);
require!(!offer_mapper.is_empty(), "Offer does not exist");

result
offer_mapper.get()
}

fn get_offer_result(&self, offer_id: u32) -> MultiValue2<u32, Offer<Self::Api>> {
let offer = self.offers(offer_id).get();
fn get_new_offer_id(&self) -> OfferId {
let last_offer_id_mapper = self.last_offer_id();
let new_offer_id = last_offer_id_mapper.get() + 1;
last_offer_id_mapper.set(new_offer_id);

MultiValue2::from((offer_id, offer))
new_offer_id
}

// storage

#[view]
#[storage_mapper("createdOffers")]
fn created_offers(&self, address: &ManagedAddress) -> UnorderedSetMapper<u32>;

#[view]
#[storage_mapper("wantedOffers")]
fn wanted_offers(&self, address: &ManagedAddress) -> UnorderedSetMapper<u32>;

#[view]
#[storage_mapper("offers")]
fn offers(&self, id: u32) -> SingleValueMapper<Offer<Self::Api>>;

#[storage_mapper("lastOfferId")]
fn last_offer_id(&self) -> SingleValueMapper<u32>;
}
72 changes: 72 additions & 0 deletions src/events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
multiversx_sc::imports!();

use crate::offer::{self, Offer};

#[multiversx_sc::module]
pub trait EventsModule: offer::OfferModule {
fn emit_create_offer_event(&self, offer: &Offer<Self::Api>) {
let epoch = self.blockchain().get_block_epoch();
let timestamp = self.blockchain().get_block_timestamp();
self.create_offer_event(
&offer.creator,
&offer.accepted_address,
epoch,
timestamp,
offer,
);
}

fn emit_cancel_offer_event(&self, offer: &Offer<Self::Api>) {
let epoch = self.blockchain().get_block_epoch();
let timestamp = self.blockchain().get_block_timestamp();
self.cancel_offer_event(
&offer.creator,
&offer.accepted_address,
epoch,
timestamp,
offer,
);
}

fn emit_accept_offer_event(&self, offer: &Offer<Self::Api>) {
let epoch = self.blockchain().get_block_epoch();
let timestamp = self.blockchain().get_block_timestamp();
self.accept_offer_event(
&offer.creator,
&offer.accepted_address,
epoch,
timestamp,
offer,
);
}

#[event("createOffer")]
fn create_offer_event(
&self,
#[indexed] creator: &ManagedAddress,
#[indexed] buyer: &ManagedAddress,
#[indexed] epoch: u64,
#[indexed] timestamp: u64,
offer: &Offer<Self::Api>,
);

#[event("cancelOffer")]
fn cancel_offer_event(
&self,
#[indexed] creator: &ManagedAddress,
#[indexed] buyer: &ManagedAddress,
#[indexed] epoch: u64,
#[indexed] timestamp: u64,
offer: &Offer<Self::Api>,
);

#[event("acceptOffer")]
fn accept_offer_event(
&self,
#[indexed] creator: &ManagedAddress,
#[indexed] buyer: &ManagedAddress,
#[indexed] epoch: u64,
#[indexed] timestamp: u64,
offer: &Offer<Self::Api>,
);
}
79 changes: 79 additions & 0 deletions src/offer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
multiversx_sc::imports!();
multiversx_sc::derive_imports!();

pub type OfferId = u64;

#[derive(TypeAbi, TopEncode, TopDecode)]
pub struct Offer<M: ManagedTypeApi> {
pub creator: ManagedAddress<M>,
pub offered_payment: EsdtTokenPayment<M>,
pub accepted_payment: EsdtTokenPayment<M>,
pub accepted_address: ManagedAddress<M>,
}

impl<M: ManagedTypeApi> Offer<M> {
pub fn new(
creator: ManagedAddress<M>,
offered_payment: EsdtTokenPayment<M>,
accepted_payment: EsdtTokenPayment<M>,
accepted_address: ManagedAddress<M>,
) -> Self {
Offer {
creator,
offered_payment,
accepted_payment,
accepted_address,
}
}
}

#[multiversx_sc::module]
pub trait OfferModule {
#[view(getCreatedOffers)]
fn get_created_offers(
&self,
address: ManagedAddress,
) -> MultiValueEncoded<MultiValue2<OfferId, Offer<Self::Api>>> {
let mut result = MultiValueEncoded::new();

for offer_id in self.created_offers(&address).iter() {
result.push(self.get_offer_result(offer_id));
}

result
}

#[view(getWantedOffers)]
fn get_wanted_offers(
&self,
address: ManagedAddress,
) -> MultiValueEncoded<MultiValue2<OfferId, Offer<Self::Api>>> {
let mut result = MultiValueEncoded::new();

for offer_id in self.wanted_offers(&address).iter() {
result.push(self.get_offer_result(offer_id));
}

result
}

fn get_offer_result(&self, offer_id: OfferId) -> MultiValue2<OfferId, Offer<Self::Api>> {
let offer = self.offers(offer_id).get();

MultiValue2::from((offer_id, offer))
}

#[storage_mapper("createdOffers")]
fn created_offers(&self, address: &ManagedAddress) -> UnorderedSetMapper<OfferId>;

#[storage_mapper("wantedOffers")]
fn wanted_offers(&self, address: &ManagedAddress) -> UnorderedSetMapper<OfferId>;

#[view(getOffer)]
#[storage_mapper("offers")]
fn offers(&self, id: OfferId) -> SingleValueMapper<Offer<Self::Api>>;

#[view(getLastOfferId)]
#[storage_mapper("lastOfferId")]
fn last_offer_id(&self) -> SingleValueMapper<OfferId>;
}
10 changes: 4 additions & 6 deletions wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
////////////////////////////////////////////////////

// Init: 1
// Endpoints: 10
// Endpoints: 8
// Async Callback (empty): 1
// Total number of exported functions: 12
// Total number of exported functions: 10

#![no_std]
#![allow(internal_features)]
Expand All @@ -26,10 +26,8 @@ multiversx_sc_wasm_adapter::endpoints! {
acceptOffer => accept_offer
getCreatedOffers => get_created_offers
getWantedOffers => get_wanted_offers
getUserBalance => user_balance
created_offers => created_offers
wanted_offers => wanted_offers
offers => offers
getOffer => offers
getLastOfferId => last_offer_id
)
}

Expand Down