-
Notifications
You must be signed in to change notification settings - Fork 6
Add Potlock contract #76
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
base: main
Are you sure you want to change the base?
Conversation
fn project_donations( | ||
&self, | ||
project_id: ProjectId, | ||
) -> MapMapper<ManagedAddress, EsdtTokenPayment>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless you've got no other choice, avoid MapMapper.
let project_id = self.projects().len() + 1; | ||
let owner = self.blockchain().get_caller(); | ||
let project = Project::new(project_id, potlock_id, project_name, description, owner); | ||
self.projects().push(&project); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this respects the specs. I don't see where an admin/owner can accept/reject an application. Docs say this:
ApplyForPot@potID@projectName@description - anyone can submit application, but an authority will review the submission and evaluate for eligibility and potential impact
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new
function for Project::new
will create a Project with Status = Inactive
.
An authority would have to call endpoint(acceptApplication)
to set the project status to Active
Framework upgrade potlock
Add blackbox tests
Potlock system tests
Coverage SummaryTotals
FilesExpand
|
); | ||
let caller = self.blockchain().get_caller(); | ||
|
||
let potlock_id = self.potlocks().len() + 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is a good idea, as you also have a way to remove data from this storage (removePot endpoint) - which means it may overwrite already existing ids. So it will be better if you keep a separate storage for the lastId and increment that value each time a new pot is created.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing the second element from a VecMapper that contains 4 elements (1, 2, 3, 4), we would get 1, 3, 4.
Removing the last element from a VecMapper that contains 4 elements (1, 2, 3, 4), we would get 1, 2, 3. By adding another element, we would get 1, 2, 3, 5.
There is no need for the lastId.
let caller = self.blockchain().get_caller(); | ||
self.require_potlock_exists(potlock_id); | ||
self.require_potlock_is_active(potlock_id); | ||
self.pot_donations(potlock_id).insert(caller, payment); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a problem here if I donate twice. The old donation would be overwritten and I'll remain with that amount in the contract unregistered. There are a few ways around this:
- You take the output of the insert function and send back to the user
- You add a check if there is already a donation on behalf of that user.
- Instead of a EsdtTokenPayment per user, you save a PaymentsVec.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Accepted multiple payments but only with the same token_id.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is still the same. The payment token is not checked. And in case you only ask for a specific payment token, you would still need a check, to see if there is already some donation from the caller. If it isn't, then you add it, if there's already something, you accumulate it. But this works only if the accepted token_id is always the same and not changeable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now I see you did this update for the donateToProject endpoint, but it is needed here also.
for pp in project_percentage { | ||
let (project_id, percentage) = pp.into_tuple(); | ||
let mut output_payments = ManagedVec::new(); | ||
for (_, donation) in pot_donations.iter() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There may be a few problems with this way of implementing (as Dorin also suggested), mostly concerning gas usage. If a malicious user donates values from 1000 addresses, the potlock will be blocked, with an outOfGas error.
Maybe rethink the architecture of the storages. One option would be instead of a mapMapper, to save under the potlock_id and user keys, a singleValueMapper of PaymentsVec. This allows you to quickly go to a specific user for donations and also, this endpoint would control the gasCost by clearly providing a list of users, besides the potlockId.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are unable to iterated through all payments and distribute them if we have singleValueMapper.
|
||
#[view(getProjects)] | ||
#[storage_mapper("projects")] | ||
fn projects(&self) -> VecMapper<Project<Self::Api>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UnorderedSetMapper here as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would get a different behavior as explained to potlocks.
…or-tests Add potlock contract interactor tests
#[payable("*")] | ||
#[endpoint(addPot)] | ||
fn add_pot(&self, name: ManagedBuffer, description: ManagedBuffer) { | ||
let payment_for_adding_pot = self.call_value().single_esdt(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not mandatory, but you could add these 2 storages under a single one, that keeps a EsdtTokenPayment struct. And you can check here if the payments are equal.
|
||
#[only_admin] | ||
#[endpoint(distributePotToProjects)] | ||
fn distribute_pot_to_projects( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few more questions here. Not mandatory but are good to be discussed.
- Right now, there is no way to be sure all the projects that applied for this pot were covered in the provided array, is it ok for the owner to be able to give the amounts arbitrary and to not all projects?
- Also, there is no check that the project applied to this specific pot, maybe add a check after you read each project from storage, that the project is active for this pot? If not, why even bother to approve a project for a pot?
- And finally, how about a limit to the number of projects that can apply for a pot? Either here for the number of elements for project_percentages, or for when subscribing a project to a pot.
let (_, perc) = pp.into_tuple(); | ||
total_perc += perc; | ||
} | ||
require!( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would still enforce clear equality here.
total_perc == MAX_PERCENTAGE
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll keep it like this for now in case we want to distribute part of the pot.
Contract comparison - from d451bc5 to 8733f5f
|
No description provided.