Open lolmcshizz opened 5 months ago
@lolmcshizz so what is the idea here? You will search for someone that wants to implement this?
I assume the "flexible inflation" is probably achieved by this pr: https://github.com/polkadot-fellows/runtimes/pull/364?
Yes, the part about
parameterise flexible inflation to drip some % of funds into a “pot” for distribution (achieved through https://github.com/polkadot-fellows/RFCs/pull/89)
Is contained in #364 and RFC89.
The purpose of this issue otherwise should be for someone to be able to understand what needs to be implemented, reach out to @lolmcshizz, and for the fellowship to be aware.
Ideally these wish for change ideas should be not in the fellowship repo, but for now since there is only, we can track it here.
I pointed out in twitter and PBA already that these wish for change impls are great starting point for those that already know FRAME and Polkadot a bit, and are looking for an impactful contribution.
Please see a suggestion here: https://github.com/kudos-ink/portal/issues/103#issuecomment-2220776313
I've made a public element room where anyone wishing to have a more sync chat with @lolmcshizz or I to join: https://matrix.to/#/#wish-for-change-impls:parity.io
optimistic-funding
palletThis pallet enables the creation and management of pots that distribute rewards to whitelisted projects based on nominations from token holders.
I have detailed the changes if we are only doing one pot.
MinimumVote: Balance
: The minimum amount that can be added to a potMaxMemoLength: u32
: The maximum length of memos attached to potsMaxWhitelistedProjects: u32
: The maximum number of projects that can be whitelisted per potLockPeriod: BlockNumber
: The duration for which votes are lockedNominationRenewalPeriod: BlockNumber
: The period after which nominations must be renewedstruct PotInfo {
owner: AccountId,
start_time: BlockNumber,
end_time: Option<BlockNumber>,
cap: Option<Balance>, // may not be useful
time_basis: TimeBasis, // some enum with variants: Daily, Weekly, Monthly, Yearly
last_distribution_time: Option<BlockNumber>,
whitelisted_projects: BoundedVec<ProjectId, MaxWhitelistedProjects>,
total_votes: Balance,
}
struct VoteInfo {
amount: Balance,
is_fund bool,
}
Pots: PotId => PotInfo
Votes: (PotId, ProjectId, AccountId) => VoteInfo
Might not be useful, but if we wish to track the amount of votes per (pot, project, voter), we can do so.
start_time: BlockNumber
, end_time: Option<BlockNumber>
, cap: Option<Balance>
, time_basis: TimeBasis
, owner: AccountId
pot_id: PotId
, project_id: ProjectId
pot_id: PotId
, project_id: ProjectId
pot_id: PotId
, project_id: ProjectId
, amount: Balance
, conviction: Conviction
, is_fund: bool
pot_id: PotId
, project_id: ProjectId
, amount: Balance
, is_fund: bool
pot_id: PotId
time_basis
)pot_id: PotId
, new_end_time: Option<BlockNumber>
pot_id: PotId
, new_cap: Option<Balance>
pot_id: PotId
, new_time_basis: TimeBasis
pot_id: PotId
, project_id: ProjectId
, memo: BoundedVec<u8, MaxMemoLength>
pot_id: PotId
, new_owner: Option<AccountId>
Add InflationFundingRate: Permill
: The rate at which funding is received from inflation
Move PotInfo
to parameters, and changes will be made through governance. So, there will be no need for a pots storage item.
owner
can be removedNo create_pot
or setters for start_time
, end_time
, cap
, time_basis
.
distribute_rewards
extrinsic
- simple pallet that locks DOT & distributes to nominated projects based on a locked amount from the pot
The Pallet is only responsible for locking and distributing Dots, my assumptions are therefore:
This leads me to think that another pallet will manage parameters such as conviction
or NominationRenewalPeriod
.
We will however need a mock referendum for testing purposes.
Question 3: The Pot should take into account the existential deposit
Question 4: I suggest that the project_owner/proposal_creator claim the reward within a given time frame => claim_reward
extrinsic.
claim_reward_for
so that anyone can claim on a project's behalf (for example, if a parachain is one of the projects it wouldn't be great UX for them to have to do a governance referendum just to claim the rewards :)Just to clarify @marcuspang - DOT holders can issue both "fund" and "not fund" votes, but they don't have to do both. So for example, I could vote to fund project A with 1,000 DOT, and vote to not fund project B with 1,000 DOT. Or I could just vote to fund project A and not vote to not fund another project - or I could vote to just not fund a specific project, and not offer funding to any project.
@lolmcshizz and @ndkazu thank you for the feedback and response.
Here is my revised spec for the pallet, which is much more simplified now. I realised that there is a "scheduler" trait in substrate, which removes the need for manual distribution as discussed above.
Also, I am not sure if there's a better way of keeping track of votes + conviction, but for now I am keeping the values in the pallet as a first draft :)
MaxWhitelistedProjects: u32
: The maximum number of projects that can be whitelisted per potVoteLockingPeriod: BlockNumber
: The minimum duration for which votes are lockedNominationRenewalPeriod: BlockNumber
: The period after which nominations must be renewedTimeBasis: TimeBasis
: The time basis used to distribute rewardsPotAccount: AccountId
: The account that holds the funds to be distributedScheduler: schedule::v3::Named
: The scheduler used to schedule the distribution of rewardsWhitelistProjectOrigin: Origin
: The origin that can whitelist projectsProjectId: AccountId
: The identifier of a projectstruct VoteInfo {
amount: Balance, // Perhaps combine with `conviction` to some auxiliary type like pallet_democracy::Voting
conviction: Conviction,
is_fund: bool, // Whether the vote is "fund" / "not fund"
}
struct ProjectInfo {
whitelisted_block: BlockNumber,
total_votes: u32,
}
WhitelistedProjects: BoundedVec<ProjectId, MaxWhitelistedProjects>
: The list of whitelisted projectsProjects: ProjectId => ProjectInfo
: Project informationVotes: (AccountId, ProjectId) => VoteInfo
: The votes by each account for each whitelisted projectLastDistributedBlock: BlockNumber
: The last block number at which rewards were distributedvote_project
project_id: ProjectId
, amount: Balance
, conviction: Conviction
, is_fund: bool
remove_project_vote
project_id: ProjectId
, amount: Balance
is_fund
doesn't affect the subtracted amountWhitelistProjectOrigin
whitelist_project
project_id: ProjectId
remove_whitelisted_project
project_id: ProjectId
I am not sure if conviction makes sense here. I don't follow the whole discussion so can someone explain why it is a useful thing?
The cons I have:
It is always good to start with something simple, with the possibility to extend in the future, than try to get the ultimate version done in V1.
From the additional information received here: https://matrix.to/#/#wish-for-change-impls:parity.io, I feel that different things are being mixed up together, so @kianenigma and @lolmcshizz correct me if I am wrong:
For me, this means the following:
project_id/AccountId
, and the corresponding DOTs amount: Balance
to be locked & distributed.VoteInfo
and the corresponding storage are not necessary. ProjectInfo
could look like:struct ProjectInfo {
whitelisted_block: BlockNumber,
requested_amount: Balance,
distributed: bool,
}
project_id: ProjectId
is received by the pallet. I am not sure if conviction makes sense here. I don't follow the whole discussion so can someone explain why it is a useful thing?
The cons I have:
- It makes things more complicated.
- If I read it correctly, higher conviction means more funds to be distributed. This is different to OpenGov referenda, higher conviction wouldn't impact the execution of the proposal. It maybe fine, but I want to make sure the impact is thoroughly considered.
It is always good to start with something simple, with the possibility to extend in the future, than try to get the ultimate version done in V1.
I agree that this is a good first step. Initially, I assumed that the voting of distribution amount would work similar to OpenGov, with conviction / delegation. In which case it would be better to rely on the existing logic in pallet_democracy, but I wasn't sure if this was the best approach.
Inspired by what @marcuspang did, this is another suggestion for the pallet configuration, which reflects my understanding of the task.
• MaxWhitelistedProjects: u32 ⇒ The maximum number of projects that can be whitelisted • LockingPeriod: BlockNumber ⇒ The minimum duration/Buffer time for which funds are locked after project approval/before the reward can be claimed. • TimeBasis: TimeBasis ⇒ The time basis used to distribute rewards • PotAccount: PalletId ⇒ The account that holds the funds to be distributed
• ProjectId: AccountId ⇒The identifier of a project
/// Reward distribution plan (Optional)
pub enum DistributionPlan {
OneDayUpFront,
ThreeDays,
FiveDays,
}
/// Payment status
pub enum PaymentState {
/// Unclaimed
Unclaimed
/// Claimed & Pending.
Pending,
/// Claimed & Paid.
Completed,
/// Claimed but Failed.
Failed,
}
/// Information relative to a given payment/distribution
pub struct PaymentInfo{
/// The asset amount of the spend.
pub amount: Balance,
/// The beneficiary of the spend.
pub ProjectId: ProjectId,
/// The block number from which the spend can be claimed
pub valid_from: BlockNumber,
/// The status of the payout.
pub status: PaymentState,
/// Payment Plan (Optional)
pub plan: SpendingPlan,
/// Amount already paid
pub paid: Balance>,
}
struct ProjectInfo {
whitelisted_block: BlockNumber,
requested_amount: Balance,
distributed: bool,
}
WhitelistedProjects: BoundedVec<ProjectId, MaxWhitelistedProjects>⇒ The list of whitelisted projects Projects: ProjectId ⇒ ProjectInfo: Project information LastDistributedBlock: BlockNumber ⇒ The last block number at which rewards were distributed
claim_reward_for
: Claim the reward for a specific project. Accessible by any signed_origin
@ndkazu - yes to be clear, the "funding" part is outside of the scope - we only need (as described in the channel by @kianenigma) a key-less account that the pallet controls.
The pallet does not need to know about the actual project status, as it will be called by another pallet that will take care of that. Ability to add/remove a project from the list is also out of scope here.
We will need some storage containing all whitelisted projects, which can be added/ removed using some track on OpenGov - I don't know where this "list" needs to be but it needs to be somewhere.
The struct ProjectInfo could look like: struct ProjectInfo { whitelisted_block: BlockNumber, requested_amount: Balance, distributed: bool, }
Can you clarify what is meant by requested_amount
here? Projects will not be requesting any funding specifically - the amount is determined by the portion of votes that a project receives out of the total number of votes (minus any NAY votes).
The distribution time frame is open to discussion, it could be variable depending on the reward amount for exemple (1 time in full, over 3days, or over 1 week...etc).
Is this adding more complexity? I am fine with just daily distribution the same we have in staking right now.
I am not sure if conviction makes sense here. I don't follow the whole discussion so can someone explain why it is a useful thing?
The cons I have:
It makes things more complicated. If I read it correctly, higher conviction means more funds to be distributed. This is different to OpenGov referenda, higher conviction wouldn't impact the execution of the proposal. It maybe fine, but I want to make sure the impact is thoroughly considered. It is always good to start with something simple, with the possibility to extend in the future, than try to get the ultimate version done in V1.
@xlc the conviction is important here in the same way as in OpenGov - higher conviction means a longer lock so your votes carry more weight. Yes projects would receive more funding if their votes are of higher conviction than those of other projects - but imo this is a positive feature.
We will need some storage containing all whitelisted projects, which can be added/ removed using some track on OpenGov - I don't know where this "list" needs to be but it needs to be somewhere.
I don't disagree, this storage was even defined as follows by @marcuspang, and I kept it:
WhitelistedProjects: BoundedVec<ProjectId, MaxWhitelistedProjects>⇒ The list of whitelisted projects
My point here is that it should be populated by an external source/pallet, but we will probably need a function to populate it for the pallet testing.
Can you clarify what is meant by
requested_amount
here? Projects will not be requesting any funding specifically - the amount is determined by the portion of votes that a project receives out of the total number of votes (minus any NAY votes).
@lolmcshizz , you are correct, it should be amount
instead of requested_amount
The distribution time frame is open to discussion, it could be variable depending on the reward amount for exemple (1 time in full, over 3days, or over 1 week...etc).
Is this adding more complexity? I am fine with just daily distribution the same we have in staking right now.
I think you are also right here: let's keep it simple.
Ok, I prepared the main structure of the pallet with a few modifications compared to the plan described above. The next steps are:
@lolmcshizz :
Hello, I would like to know your opinion on the following: Although I think the OPF voting system could just be added in the existing pallet, having the rewards distribution process in a different pallet makes more sense in my opinion.
Please let me know what you think.
As this is more of a technical implementation question than impacting how it works for users, I would defer to @kianenigma here for guidance
@lolmcshizz , what do you think about the following timeline for opf_voting:
|--------------------Nomination_Period_0--------------------->|--------------------Nomination_Period_1--------------------->|
|--------Voting_Period-------->|--------Voting_locked-------->|--------Voting_Period-------->|--------Voting_locked-------->|
|----------------------------->|-----Rewards_Distribution---->|------------------------------->|-----Rewards_Distribution--->|
I am glad to see this, but let's note that this pallet can also live elsewhere, perhaps here or in anyone's repo, given that we have proper releases now :)
Future-proof solution, considering the multiple ways rewards could be/are being distributed
I don't have strong opinions about whether reward should be in a separate pallet or not, but I would probably reside to one of possible.
Claimable vs Automated distribution is not necessarily a clear-cut decision
Automated solutions are generally more hairy. I suggest doing a claim-able only impl for now, and later on you can always use #[pallet::task]
or on_idle
to soft-automate it :)
If more specific tech questions, let's continue in your draft PR as it is easier to review the whole code.
@ndkazu here is what I imagined the pallet would roughly look like https://github.com/paritytech/polkadot-sdk/pull/5225.
After your recent changes, I think the main difference now is storage and how claims are being kept track of
Hello, I recently noticed & reverted unwanted changes, probably added by the command cargo fmt
at some point. Review request is already out.
@kianenigma, for now, I am using a constant defined in the runtime for the total reward to be distributed from the pot to the selected projects during each round, but I am guessing there will be (or already is...) a pallet/function to get the portion of inflation to be distributed. Is this correct?
Re-posting something I have discussed with @lolmcshizz: I genuinely think that merging and getting this to production in the midst of moving everything outside of the relay chain to AH will be very, very hard.
A more forward-looking suggestion: Implement this as a solidity contract. Once Solidity contracts are live (~mid-2025), all that the fellowship would then have to do is to forward a small part of the inflation to this contract's account.
This is a tracking issue for the implementation of Optimistic Project Funding - which was approved by DOT holders in Referendum #712.
Implementation of this feature appears to be achievable in two separate parts:
flexible inflation
to drip some % of funds into a “pot” for distribution (achieved through RFC #89)Relevant links:
Full description of the mechanism that was approved: https://docs.google.com/document/d/1cl6CpWyqX7NCshV0aYT5a8ZTm75PWcLrEBcfk2I1tAA/edit#heading=h.hh40wjcakxp9
Polkadot's economics Forum post: https://forum.polkadot.network/t/polkadots-economics-tools-to-shape-the-forseeable-future/8708?u=lolmcshizz
Project discussion TG: https://t.me/parachainstaking