Skip to content

Commit 253af9f

Browse files
added more comments
1 parent 1b8de27 commit 253af9f

File tree

4 files changed

+181
-36
lines changed

4 files changed

+181
-36
lines changed
Binary file not shown.

2-oracles/tweeter-oracle/scrypto/tweeter-oracle/src/airdrop_with_twitter_oracle.rs

Lines changed: 114 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,50 +16,82 @@ blueprint! {
1616
//At the stage of finalizing the airdrop methode finalize_airdrop the Tweeter_oracle component is used to verify that all tasks have been carried out by subscribers.
1717
//
1818
struct AirdropWithTweeterOracle {
19+
// ResourceAddress of admin_badge : this admin_badge is return to user who instanciate the component (Airdrop maker)
1920
admin_badge: ResourceAddress,
21+
// The vault that contains the tokens to distribute to the participants of the airdrop who have executed all the tasks
2022
tokens: Vault,
23+
// Badge resource address returned to people registered in the airdrop : This will allow them to make the withdrawal
2124
participant_badge_address: ResourceAddress,
25+
// minter of participant_badge vault
2226
minter_badge_vault: Vault,
27+
//Store the airdrop particpant : Tweeter Account by NonFungibleId : [{"12345678901234567890123456789012u128","cyover"},{"12345678901234567890123456788080u128","cyrolsi"}]
2328
airdrop_participants : HashMap<NonFungibleId, String>,
29+
//Store participants tweeter_account to avoid multiple participation with the same tweeter account
2430
participants_tweeter_account : HashSet<String>,
31+
// Store tweeters accounts to follow
2532
accounts_to_follow :Vec<String>,
33+
// Store tweets to retweet
2634
tweets_to_retweet :Vec<String> ,
35+
// Store tweets to like
2736
tweets_to_like : Vec<String>,
37+
// The oracle tweeter component which makes it possible to verify that all the tasks have been correctly executed
2838
tweeter_oracle : TweeterOracle,
39+
// Store the NonFongibleId of participants who have completed all the tasks and who will receive the airdrop
2940
recipients : HashSet<NonFungibleId>,
41+
// Amount per recipient
3042
amount_per_recipient : Decimal
3143
}
3244

3345
impl AirdropWithTweeterOracle {
34-
pub fn new( token_type: ResourceAddress,
46+
// This function instanciate the AirdropWithTweeterOracle
47+
// #Argumets
48+
// * `token_type` Tokens resourceAddress to distribute
49+
// * `accounts_to_follow` tweeters accounts to follow
50+
// * `tweets_to_retweet` tweets to retweet
51+
// * `tweets_to_like` tweets to like
52+
// * `tweeter_oracle_component_address` Address of TweeterOracle component
53+
pub fn new( token_type: ResourceAddress,
3554
accounts_to_follow :Vec<String>,
3655
tweets_to_retweet :Vec<String> ,
3756
tweets_to_like : Vec<String>,
3857
tweeter_oracle_component_address : ComponentAddress ) -> (ComponentAddress, Bucket) {
3958

59+
// Check that there is at least one task to do
4060
assert!(accounts_to_follow.len() > 0
4161
|| tweets_to_retweet.len() > 0
42-
|| tweets_to_like.len() > 0 , "you must give at leat 1 condition for the airdrop");
62+
|| tweets_to_like.len() > 0 , "you must give at leat 1 task for the airdrop");
4363

64+
// create admin_badge bucket with one supply
4465
let admin_badge = ResourceBuilder::new_fungible()
4566
.divisibility(DIVISIBILITY_NONE)
4667
.initial_supply(Decimal::one());
4768

69+
// create a minter badge
4870
let minter_badge = ResourceBuilder::new_fungible()
4971
.divisibility(DIVISIBILITY_NONE)
5072
.metadata("name", "minter badge")
5173
.initial_supply(Decimal::one());
5274

75+
// Create a participant badge address
5376
let participant_badge_address = ResourceBuilder::new_non_fungible()
5477
.metadata("name", "participant badge")
5578
.mintable(rule!(require(minter_badge.resource_address())), LOCKED)
5679
.updateable_non_fungible_data(rule!(require(minter_badge.resource_address())), LOCKED)
5780
.no_initial_supply();
5881

82+
// //Definition of the methods which will be accessible only to the administrator of the component
5983
let access_rules = AccessRules::new()
6084
.method("finalize_airdrop", rule!(require(admin_badge.resource_address())))
85+
.method("find_and_store_airdrop_recipients", rule!(require(admin_badge.resource_address())))
6186
.default(rule!(allow_all));
6287

88+
let tweeter_oracle : TweeterOracle = tweeter_oracle_component_address.into();
89+
tweeter_oracle.add_followers_to_update(accounts_to_follow.clone());
90+
tweeter_oracle.add_likers_to_update(tweets_to_like.clone());
91+
tweeter_oracle.add_retweeters_to_update(tweets_to_retweet.clone());
92+
93+
94+
// Instantiate AirdropWithTweeterOracle component and return it with the admin badge to caller
6395
let component = Self {
6496
admin_badge: admin_badge.resource_address(),
6597
tokens: Vault::new(token_type),
@@ -70,7 +102,7 @@ blueprint! {
70102
accounts_to_follow : accounts_to_follow,
71103
tweets_to_retweet : tweets_to_retweet,
72104
tweets_to_like : tweets_to_like,
73-
tweeter_oracle : tweeter_oracle_component_address.into(),
105+
tweeter_oracle : tweeter_oracle,
74106
recipients : HashSet::new(),
75107
amount_per_recipient : Decimal::zero()
76108
}
@@ -81,14 +113,28 @@ blueprint! {
81113
return (component, admin_badge);
82114
}
83115

84-
pub fn register(&mut self, tweeter_account_name: String, participant: ComponentAddress) {
116+
//This method allows you to register for an airdrop
117+
// #Arguments
118+
// `tweeter_account_name` : tweeter account name
119+
pub fn register(&mut self, tweeter_account_name: String) -> Bucket {
85120

121+
//Avoid multiple participation with the same tweeter account
86122
assert!(!self.participants_tweeter_account.contains(&tweeter_account_name),"already registered to this airdrop");
123+
124+
// Check if the airdrop were already finalize
125+
assert!(
126+
self.amount_per_recipient == Decimal::zero(),
127+
"The airdrop were already finalize"
128+
);
129+
// Generate NonFungibleId for participant
87130
let id = NonFungibleId::random();
88131

132+
// Store tweeter account name by NonFungibleId
89133
self.airdrop_participants.insert(id.clone(), tweeter_account_name.to_string());
134+
// Store tweeter account name
90135
self.participants_tweeter_account.insert(tweeter_account_name);
91136

137+
// create participant badge that will allow him to make the withdrawal
92138
let participant_badge = self.minter_badge_vault.authorize(|| {
93139
borrow_resource_manager!(self.participant_badge_address).mint_non_fungible(
94140
&id,
@@ -98,71 +144,115 @@ blueprint! {
98144
},
99145
)
100146
});
147+
148+
// return the participant_badge to caller
149+
return participant_badge;
150+
}
101151

102-
borrow_component!(participant).call::<()>("deposit", args![participant_badge]);
152+
//This find the participants that have completed the tasks and to store them
153+
pub fn find_and_store_airdrop_recipients(&mut self) -> usize
154+
{
155+
//find partcipants who made all tasks
156+
for nft_id in self.airdrop_participants.keys() {
157+
// check if current participant have executed all tasks
158+
let tweeter_account = self.airdrop_participants.get(&nft_id).unwrap().clone();
159+
if !self.recipients.contains(&nft_id) && self.has_completed_all_tasks(tweeter_account) {
160+
// store the recipient Nft_id for widhraw
161+
self.recipients.insert(nft_id.clone());
162+
}
163+
}
164+
// return the number of recipients
165+
return self.recipients.len();
103166
}
104167

168+
// this method makes it possible to finalize the airdrop
169+
// #Arguments
170+
// * `tokens` Bucket containing the tokens to distribute
105171
pub fn finalize_airdrop(&mut self,
106-
mut tokens: Bucket) {
172+
mut tokens: Bucket) -> Bucket {
107173

174+
// check tokens quantity
108175
assert!(
109176
tokens.amount() > Decimal::zero(),
110177
"tokens quantity cannot be 0"
111178
);
112-
179+
180+
// check token address
113181
assert_eq!(
114182
tokens.resource_address(),
115183
self.tokens.resource_address(),
116184
"token address must match"
117185
);
118186

187+
// check recipients
188+
assert!(
189+
self.recipients.len() > 0 ,
190+
"there is no recipient for the airdrop"
191+
);
192+
193+
// Check if the airdrop were already finalize
119194
assert!(
120195
self.amount_per_recipient == Decimal::zero(),
121-
"The airdrop is already finalize"
196+
"The airdrop were already finalize"
122197
);
123198

124-
//find partcipants who made all taks
125-
for nft_id in self.airdrop_participants.keys() {
126-
// check eligibility
127-
let tweeter_account = self.airdrop_participants.get(&nft_id).unwrap().clone();
128-
if self.can_receive_airdrop(tweeter_account) {
129-
self.recipients.insert(nft_id.clone());
130-
}
131-
}
132-
199+
// check tokens quantity for NonFungible
133200
assert!(
134-
self.recipients.len() > 0 ,
135-
"there is no recipient for the airdrop"
136-
);
201+
borrow_resource_manager!(tokens.resource_address()).resource_type()
202+
== ResourceType::NonFungible && tokens.amount() >= Decimal::from(self.recipients.len() as i128 ) ,
203+
"For non-fungible tokens, a number at least equal to the number of recipients is required"
204+
);
137205

138206
// Calculate the amount of tokens each recipient can receive
139-
let amount_per_recipient = tokens.amount() / Decimal::from(self.recipients.len() as i128);
207+
let mut amount_per_recipient = tokens.amount() / Decimal::from(self.recipients.len() as i128);
208+
209+
// Special case for NonFongible Token
210+
if borrow_resource_manager!(tokens.resource_address()).resource_type() == ResourceType::NonFungible
211+
{
212+
amount_per_recipient = Decimal::from(amount_per_recipient.round(18, RoundingMode::TowardsZero));
213+
}
214+
140215
self.amount_per_recipient = amount_per_recipient;
141216

142-
self.tokens.put(tokens);
217+
// Take necessary amount from tokens bucket
218+
self.tokens.put(tokens.take(amount_per_recipient * Decimal::from(self.recipients.len() as i128)));
219+
220+
// return tokens bucket to caller
221+
return tokens;
143222
}
144223

224+
//This method allows recipients to withdraw their tokens
225+
//#Arguments
226+
//* `auth` Aidrop registration proof
227+
//#Return
228+
// This function return a bucket containing the quantity of tokens to be distributed
145229
pub fn withdraw(&mut self, auth: Proof) -> Bucket {
146230

231+
//checking if airdrop is filnalize
147232
assert!(self.amount_per_recipient > Decimal::zero() , "impossible withdraw : the airdrop is in progress");
233+
// checking participant badge
148234
assert_eq!(auth.resource_address(), self.participant_badge_address, "Invalid Badge Provided");
235+
// checking badge amount
149236
assert_eq!(auth.amount(), dec!("1"), "Invalid Badge Provided");
150237
let nft_id = auth.non_fungible::<AirdropWithTweeterOracleData>().id();
238+
// checking if current user completed all tasks
151239
assert!(self.recipients.contains(&nft_id), "you cannot receive the airdrop");
152-
153240
let mut nft_data = auth.non_fungible::<AirdropWithTweeterOracleData>().data();
241+
// checking if withdrawal is already done
154242
assert!(!nft_data.is_collected, "withdraw already done");
155243
nft_data.is_collected = true;
156244
let amount = self.amount_per_recipient;
245+
// update nft data
157246
self.minter_badge_vault.authorize({|| {
158247
auth.non_fungible().update_data(nft_data);
159248
}
160249
});
161250
info!("withdraw_token : {}", amount);
251+
// return tokens to caller
162252
return self.tokens.take(amount);
163253
}
164254

165-
fn can_receive_airdrop(&self, participant_tweeter_account : String) -> bool {
255+
fn has_completed_all_tasks(&self, participant_tweeter_account : String) -> bool {
166256

167257
let is_follower = self.accounts_to_follow.len() == 0 || self.accounts_to_follow.clone().into_iter()
168258
.all(|x| self.tweeter_oracle.is_account_follower(x, participant_tweeter_account.to_string()));

0 commit comments

Comments
 (0)