allo-protocol / allo-v2 Goto Github PK
View Code? Open in Web Editor NEWCore Allo V2 Contracts
Core Allo V2 Contracts
We decided that an address will be the core recipientId
that persists throughout the Allo contracts.
Changes we need to make include (please add other tasks as needed):
applyToRound()
to addRecipient()
respectively.add-strategy
branch first to work from a clean main.This error is declared but never used in the contract:
per #11
We just finished out call about merging strategies into one, and then building out a library of components instead.
This has the negatives of:
But it has the positives of:
If we do this, I can imagine the reorganized repo would look something like this:
core/
libraries/
Metadata.sol
Allo.sol
Aqueduct.sol
Registry.sol
components/
IStrategy.sol
BaseStrategy.sol (abstract contract, inherits from IStrategy)
recipients/
BaseRecipientsComponent.sol
common/
AllocationGating.sol
ERC721AllocationGating.sol
TokenBalanceAllocationGating.sol
...
voters/
BaseVotersComponent.sol
common/
...
allocation/
BaseAllocationComponent.sol
common/
OffchainCalculations.sol
...
distribution/
BaseDistributionComponent.sol
common/
Splitter.sol
...
Then when a developer wants to create a strategy, they could do something like the below, and just override any functions they need (like using OpenZeppelin):
contract MyStrategy is BaseStrategy, ERC721AllocationGating, MyVotingComponent, OffchainCalculations, Splitter {}
Down the road, we can create something like https://wizard.openzeppelin.com/ to deploy mix and matches strategies automatically, or even put the components on chain.
Spec: #65
This is part of the work to create our initial batch of allocation strategies. This spec is for the strategy that will replace the current Quadratic Funding implementation in Grants Stack.
Strategy hitlist
Allocation module overview
Original strategy brainstorm
Use spec from #41
per #11
Note: As we create strategies, we'll put them in the appropriate folders and inherit from "../../interfaces/I{Type}Strategysol"
. We shouldn't need to create any other files to complete this. Let's see if we can hold ourselves to that.
Spec: #67
This is part of the work to create our initial batch of allocation strategies. This spec is to update the simple RFP strategy here.
Strategy hitlist
Allocation module overview
Original strategy brainstorm
Currently the donation voting contract holds the donation funds โ those funds should be sent directly to the recipients instead of being held temporarily.
Per #11, we want to reorganize the contracts/
folder
The structure should be:
Note: this removes the utils/
folder (which just duplicates the logic in core/libraries/Metadata.sol).
per #11, point (3)
Reminders:
address(uint160(uint(keccak256(identityId, name))))
It should have been:
metadataRequired = _metadataRequired;
per #11
Spec: #66
This is part of the work to create our initial batch of allocation strategies.
Strategy hitlist
Allocation module overview
Original strategy brainstorm
Deploy following contracts:
Deploy to following chains:
per #11
This spec is for the strategy that will update Bootnode's direct grants implementation for Allo v2.
Strategy hitlist
Allocation module overview
Original strategy brainstorm
From @KurtMerbeth
I would like to share my thoughts after walking through the strategy miro.
Maybe I can have your thoughts on it.
I would like to propose the addition of check functions for the functions in the core contract to enhance safety and usability:
Examples:
claim(uint _poolId, bytes memory _data) external;
Proposed Check Function: isClaimable(uint _poolId);
applyToPool(uint _poolId, bytes memory _data) external
Proposed Check Function: canApply(uint _poolId, bytes memory _data)
etc..
These check functions will enable frontends, users and other contracts to verify if executing the corresponding operations is possible or not, based on predefined conditions or requirements.
I would like discuss the idea of introducing an execute
function that would enable calling custom functions within Strategies through the Core contract. This feature aims to streamline pool handling and provide a unified approach for interacting with both standard and custom functions within Strategies.
Pros:
Simplified Pool Handling: With the execute
function, users and developers can interact with Strategies seamlessly through the Core contract, regardless of whether the functions are standard or custom. This streamlines pool handling and reduces the need to switch between different contracts, enhancing usability and developer experience.
Centralized Transaction Flow: By consolidating the function calls within the Core contract, the transaction flow becomes more centralized and easier to follow. This can improve the clarity and maintainability of the codebase.
Cons:
Potential Security Risks: Introducing an execute function that allows arbitrary function calls to custom Strategy functions carries inherent security risks. Careful consideration must be given to access control and validation mechanisms to prevent unauthorized or malicious function executions.
Increased Complexity: Implementing the execute function adds complexity to the Core contract and may require additional validation and error handling logic. This can increase the development and testing effort required to ensure the robustness and reliability of the system.
Currently, the Core contract has a function called claim
, but as we introduce distribution strategies that handle fund distribution to users, the name claim
seems in some cases a bit misleading since claim
is usually used as an action executed by an user.
To address this, I suggest adding an adtional function called distribute
to the Core contract. This function will be responsible for initiating the distribution of funds to users by the pool owner.
Alternatively, we could think about introducing a new name which represents both, claim
and distribute
. I don't have any suggestions right now, but I was thinking about a more generic name like handleDistribution
.
from @thelostone-mc
I would like to propose the addition of check functions for the functions in the core contract to enhance safety and usability:
I do like having these for enhancing safety check
Adding
execute
function.
I do see the benefit in flows like milestone based payout where :
rename claim as handleDistribution
In favour of this
from @KurtMerbeth
Having the execute solves this but this feels quite scary. we could make it safer by saying no re-enterancy and maybe not payable. I'm split on this
I feel the same. I wanted to encourage some thought on this matter.
Perhaps there is a viable way to implement something like this while ensuring safety. On the other hand, it's possible that the potential risks outweigh the benefits. Do we even consider it a problem worth addressing?
The idea of having one entry point for everything came up while I was going through the diagrams.
from @thelostone-mc
Would recommend having a updatePool on the interface cause we would def want to update the metadata
https://github.com/zobront/allo/blob/main/interfaces/IAllo.sol#L18
Also not relevant to the interface but we might want to add OZ multi-call to allow folks to allocate to multiple pools and stuff
from @codenamejason
I think multi-call here is a great idea and good call out @thelostone-mc as well as adding the updatePool()
to the interface.
Do we need to return any data on an update or just emit an event?
function updatePool(bytes memory _data) external payable returns (bytes memory);
per #11
Note: As we create strategies, we'll put them in the appropriate folders and inherit from "../../interfaces/I{Type}Strategysol"
. We shouldn't need to create any other files to complete this. Let's see if we can hold ourselves to that.
I know we keep having this discussion, but wanted to open it up again (for the fourth time?)
I think we may need to make it so that identities in the project registry are able to receive and hold funds (by deploying a lightweight proxy contract that people can only interact with through the Registry, similar to how Splits works). Reason being: I think it's just too natural to distribute payments to the anchor address
from @zobront
Starting a thread for us to discuss the fee skirting issue. The issue is that, since projects choose their own strategies, we can't have Allo protocol fees taken on the strategy, or users can easily skirt it. It needs to live on the core Allo.sol contract, but that poses challenges because when fees are taken may not be consistent across projects.
CURRENT WORKING SOLUTION
When a pool operator calls createPool()
, they can add tokens and a fee is taken directly at that point. The total balance with which the pool has been funded is stored in the Allo.sol contract.
At any point, the operator can all fundPool()
and add additional funds, and fees are taken at that point. The total balance with which the pool has been funded is updated in the Allo.sol contract.
When users call allocate()
in a strategy that requires them to send additional funds (ie Quantitative Funding), that can be handled in two ways:
a) If the funds go directly to the recipient, our prebuilt strategies take the fee directly at that point. If they deploy their own strategy, they could skirt this fee.
b) If the funds go into the distribution strategy for later distribution, a function is called on Allo.sol that updates the total funding amount for the pool and takes the fee.
In order to trigger payouts, we call finalize()
on Allo.sol. This checks the balance of the distribution strategy and, if it is greater than the stored amount of what it should be, takes any excess balance and transfers it to the Allo treasury.
ISSUES
An allocation strategy can be written that sends allocations straight to the recipient and pays no fees.
A distribution strategy can be written that skips over the finalize()
function. We could add a flag to the main contract that is is now claimable
once finalize()
is called (which would stop claimers from using the core contract's claim()
function if their distribution strategy skirts this step) but even that isn't perfect, because it doesn't account for distributions with ongoing phases.
from @KurtMerbeth
Additional Question, since we will have Pools with and without distribution strategies:
Are we taking only fees from the distribution, or also from allocations? @nfrgosselin
from @thelostone-mc
How would we ensure that the funds aren't sent directly to the DistributionStrategy and bypass the fundPool function ?
from @codenamejason
Can we do this by only allowing the Allocation Strategy to know the Distribution Strategy address or interact with the Distribution Strategy as the only owner? @thelostone-mc
from @nfrgosselin
Additional Question, since we will have Pools with and without distribution strategies:
Can you say more @KurtMerbeth? What types of pools wouldn't have distribution strategies?
Are we taking only fees from the distribution, or also from allocations?
My thinking was that the protocol would only take fees from the core pool (i.e. the distribution). Allocations could become separate income streams for strategy developers if they're creating novel strategies. So Gitcoin could deploy QF strategies that we technically take fees from, but for pools using those strategies we would actually be making fees on the distribution and the allocation. Another scenario are pools using externally-developed strategies, where the protocol would collect fees on the distribution and the strategy develop would collect fees on the allocation.
Goal is to confirm that strategies sandbox works with our deployment on OG
Thanks for the call this morning guys, and sorry I have been not as on top of it the past couple days.
I can feel things starting to sprawl a little bit, so want to make sure our actions for the rest of this week and really precise and focusing, rather than expansive.
Here is what I think needs to happen:
We've lost a single source of truth on a lot of this stuff. We can split sections out later, but for now, please remove IAllo.sol and IRegistry.sol and merge all the concepts and relevant comments into Allo.sol and Registry.sol. Then we'll be in a place to work to make those files perfect.
(The strategies can keep their interfaces because that's the only possible single source of truth, since they will all be different. I would recommend we delete the BaseAllocation.sol and BaseDistribution.sol and simply inherit straight from the interface in each strategy we create.)
This is small but will help. Let's adjust the file structure to be:
Note that this removes the utils/
folder (which just duplicates the logic in core/libraries/Metadata.sol).
As we create strategies, we'll put them in the appropriate folders and inherit from "../../interfaces/I{Type}Strategysol"
. We shouldn't need to create any other files to complete this. Let's see if we can hold ourselves to that.
Let's try to push this pretty quickly too, so we're operating from a clean base. This may take some time though, and it'll require consolidating interfaces and contracts that may be different, so don't rush it!
The current Registry.sol seems to be based on the old one, and doesn't align with the interface. I think this needs to be right before we start building complete flows.
I would recommend creating this contract to the best of our ability first. It's relatively self contained and we already know the logic.
Reminders:
address(uint160(uint(keccak256(identityId, name))))
I think the logic on here will actually be relatively simple, since so much work is being pushed to strategies. So let's get to a solid V1 that is as simple as possible and accomplishes everything we need, primarily to interact with the strategies (we'll worry about view functions in a bit).
Pick the easiest possible strategy pair and code them up so the whole thing works.
I would recommend doing Linear QF for allocation and "distribute from a mapping" for distribution, but whatever you guys want.
Think about if there are any view functions we know we need to add, both to the strategy interfaces and to core. Today, we spoke about amountClaimable()
, isClaimable()
and canApply()
.
Also consider whether there are additional states besides None, Pending, Approved, and Rejected that should be on the base status enum that projects need to implement.
Let's focus on those things first. There are other features worth exploring (like multicall) but I think we will be better served to consider those peripheral things, as well as building out the roster of strategies and making sure they all work, once the core piece is built.
I recognize that everything from STEP 4 on will rely on me figuring out the "finalize question" and fee skirting, so I will focus on that to make sure it's unblocked by the time you get there.
How does this plan sound to everyone? If good, I would say the Allo team can choose how to divide things up to tackle STEPS 1, 2, 3 (preferably in order and not in parallel, as there's a lot of restructuring that will make merging PRs messy) while I work on the "finalize stuff" over the next 2-3 days, and then we should be in a good place to bring all that together and start getting the rest of the system working.
Please include me as a review on these PRs too, so I can stay in the loop on new work being pushed.
Thanks!
can we move pendingOwner into a separate mapping?
just because it's not an important identity information and there is no need to pass this information when you quey an identity
Originally posted by @KurtMerbeth in #24 (comment)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.