From e108819e8e6917866837776675ba3c6defebfe8c Mon Sep 17 00:00:00 2001 From: Ron Turetzky Date: Thu, 26 Sep 2024 08:07:04 +0300 Subject: [PATCH 01/12] chore: updating testing and installation instructions --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 5ab48d6..33de9fb 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Contributions to this repo are expected to adhere to the [Biconomy Solidity Styl ### Build ```shell +$ git clone git@github.com:BreadchainCoop/breadchain.git --recursive $ forge build ``` @@ -32,10 +33,18 @@ $ forge snapshot ``` ### Test +For validating that tests are working run + +```shell +$ forge test --fork-url "https://rpc.gnosis.gateway.fm" -vvvv --fuzz-runs 1 +``` + +For a full run of tests run the following command, note that it may take a significant amount of time ```shell $ forge test --fork-url "https://rpc.gnosis.gateway.fm" -vvvv ``` + ### Deploy ```shell From 176787f2ac6e86eb5f7a7b3bd63850078b3c9206 Mon Sep 17 00:00:00 2001 From: Ron Turetzky Date: Thu, 26 Sep 2024 08:21:20 +0300 Subject: [PATCH 02/12] chore: adding plantuml for bread contract --- docs/Bread.md | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/Bread.md diff --git a/docs/Bread.md b/docs/Bread.md new file mode 100644 index 0000000..835a937 --- /dev/null +++ b/docs/Bread.md @@ -0,0 +1,52 @@ + + + +```plantuml +@startuml +' -- generated by: https://marketplace.visualstudio.com/items?itemName=tintinweb.solidity-visual-auditor +' +' -- for auto-render install: https://marketplace.visualstudio.com/items?itemName=jebbs.plantuml +' -- options -- + + + +' -- classes -- + + +class Bread { + ' -- inheritance -- + {abstract}ERC20VotesUpgradeable + {abstract}OwnableUpgradeable + {abstract}IBread + + ' -- usingFor -- + {abstract}📚SafeERC20 for [[IERC20]] + + ' -- vars -- + +[[address]] yieldClaimer + +[[IWXDAI]] wxDai + +[[ISXDAI]] sexyDai + + ' -- methods -- + +**__constructor__**() + +initialize() + +setYieldClaimer() + +💰mint() + +burn() + +claimYield() + +rescueToken() + +🔍yieldAccrued() + #🔍_yieldAccrued() + #_nativeTransfer() + +transfer() + +transferFrom() + +} +' -- inheritance / usingFor -- +Bread --[#DarkGoldenRod]|> ERC20VotesUpgradeable +Bread --[#DarkGoldenRod]|> OwnableUpgradeable +Bread --[#DarkGoldenRod]|> IBread +Bread ..[#DarkOliveGreen]|> SafeERC20 : //for IERC20// + +@enduml +``` \ No newline at end of file From 1cee21382ae12780b251b6f05e81818fe81da31c Mon Sep 17 00:00:00 2001 From: Ron Turetzky Date: Thu, 26 Sep 2024 10:41:35 +0300 Subject: [PATCH 03/12] init --- docs/Bread.md | 113 ++++++++++++++++++++++++--------------- docs/Breadchain.md | 14 +++++ docs/ButteredBread.md | 0 docs/YieldDistributor.md | 0 4 files changed, 84 insertions(+), 43 deletions(-) create mode 100644 docs/Breadchain.md create mode 100644 docs/ButteredBread.md create mode 100644 docs/YieldDistributor.md diff --git a/docs/Bread.md b/docs/Bread.md index 835a937..d63c277 100644 --- a/docs/Bread.md +++ b/docs/Bread.md @@ -1,52 +1,79 @@ +## What is BREAD? +BREAD is the community currency for the Breadchain ecosystem which exists on Gnosis Chain. All BREAD is created through the [Bread Crowdstaking Application](https://www.notion.so/Crowdstaking-Application-9f233bc2fb1e419ebeb58a2809b21658?pvs=21) which anyone with xDAI on Gnosis Chain is able to use to have some BREAD for themselves. +```mermaid +classDiagram +class Bread { + <> ERC20VotesUpgradeable + <> OwnableUpgradeable + <> IBread -```plantuml -@startuml -' -- generated by: https://marketplace.visualstudio.com/items?itemName=tintinweb.solidity-visual-auditor -' -' -- for auto-render install: https://marketplace.visualstudio.com/items?itemName=jebbs.plantuml -' -- options -- + <> SafeERC20 for IERC20 + + address yieldClaimer + + IWXDAI wxDai + + ISXDAI sexyDai + + __constructor__() + + initialize() + + setYieldClaimer() + + mint() 💰 + + burn() + + claimYield() + + rescueToken() + + yieldAccrued() 🔍 + # _yieldAccrued() 🔍 + # _nativeTransfer() + + transfer() + + transferFrom() +} -' -- classes -- +Bread <|-- ERC20VotesUpgradeable : Inheritance +Bread <|-- OwnableUpgradeable : Inheritance +Bread <|-- IBread : Inheritance +Bread .. SafeERC20 : uses IERC20 +``` +The Crowdstaking Application is a smart contract on Gnosis Chain that accepts a user’s xDAI and turns it into sDAI. In exchange, stakers receive BREAD tokens, minted at a 1-to-1 ratio with the collateralized xDAI. -class Bread { - ' -- inheritance -- - {abstract}ERC20VotesUpgradeable - {abstract}OwnableUpgradeable - {abstract}IBread - - ' -- usingFor -- - {abstract}📚SafeERC20 for [[IERC20]] - - ' -- vars -- - +[[address]] yieldClaimer - +[[IWXDAI]] wxDai - +[[ISXDAI]] sexyDai - - ' -- methods -- - +**__constructor__**() - +initialize() - +setYieldClaimer() - +💰mint() - +burn() - +claimYield() - +rescueToken() - +🔍yieldAccrued() - #🔍_yieldAccrued() - #_nativeTransfer() - +transfer() - +transferFrom() +All of the interest earned on the sDAI is helps fund the collective and its various member projects based on a monthly vote from BREAD holders. The Crowdstaking Application functions as a fundraising engine for the Breadchain Cooperative, while the BREAD token acts as a local currency within the ecosystem, promoting financial sustainability. + +Additionally, BREAD holders are able to to vote on how the yield generated from the sDAI is distributed among the projects part of the Breadchain Network every month. + +[Gnosis Chain Deployment](https://gnosisscan.io/token/0xa555d5344f6fb6c65da19e403cb4c1ec4a1a5ee3) + +## Technical Breakdown +### Minting +```solidity +1 function mint(address receiver) external payable { +2 // ... validation snippets +3 wxDai.deposit{value: val}(); +4 IERC20(address(wxDai)).safeIncreaseAllowance(address(sexyDai), val); +5 sexyDai.deposit(val, address(this)); +6 +7 _mint(receiver, val); +8 +9 // ... delegation snippet +10 } +``` +On line 3 the native currency (xDai) of Gnosis Chain gets converted to an ERC20 representation ([wxDai](https://gnosisscan.io/address/0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d)). This is done because in order to lock the xDai. + +[sDai](https://gnosisscan.io/address/0xaf204776c7245bF4147c2612BF6e5972Ee483701) is an automatic mechanism that allows a user to recieve yield from the [Dai Savings Rate](https://blog.makerdao.com/why-the-dai-savings-rate-is-a-game-changer-for-the-defi-ecosystem-and-beyond/) by depositing and locking wxDai. This is how BREAD generates yield. +On line 4 , the Bread contract allows the [sDai contract](https://gnosisscan.io/address/0xaf204776c7245bF4147c2612BF6e5972Ee483701) to take xDai from itself. + +On line 5 , the wxDai is deposited and turned into sDai, which is in possession by the BREAD contract. + +On line 7 , BREAD is minted to the reciever as a voucher for their deposit. This enables the reciever to redeem their BREAD for the amount of xDai that was deposited. + +Lets look at another snippet from the BREAD contract , which is used to calculate how much yield is available for the Breadchain federation. + +```solidity +1 function _yieldAccrued() internal view returns (uint256) { +2 uint256 bal = IERC20(address(sexyDai)).balanceOf(address(this)); +3 uint256 assets = sexyDai.convertToAssets(bal); +4 uint256 supply = totalSupply(); +5 return assets > supply ? assets - supply : 0; +6 } +``` -} -' -- inheritance / usingFor -- -Bread --[#DarkGoldenRod]|> ERC20VotesUpgradeable -Bread --[#DarkGoldenRod]|> OwnableUpgradeable -Bread --[#DarkGoldenRod]|> IBread -Bread ..[#DarkOliveGreen]|> SafeERC20 : //for IERC20// - -@enduml -``` \ No newline at end of file diff --git a/docs/Breadchain.md b/docs/Breadchain.md new file mode 100644 index 0000000..12bee57 --- /dev/null +++ b/docs/Breadchain.md @@ -0,0 +1,14 @@ +## About Breadchain Cooperative +Breadchain Cooperative is a **collective federation of decentralized cooperative projects** looking to advance a **progressive vision for blockchain** and its effect on society. We aim to do this by building and utilizing what we call *solidarity primitives* - development tools which help to forge solidarity between individuals and collectives. + +The first *solidarity primitive* created by the Breadchain Cooperative is the **BREAD** community token created through the [Bread Crowdstaking Application](https://app.breadchain.xyz/).  + +The primary infrastructure being built at Breadchain is to ask ourselves ***what if progressives had their own [community currency](https://www.notion.so/What-is-BREAD-f3335ccc7b5142bca578c6d2f2b563d3?pvs=21) and [credit union](https://www.notion.so/Yield-Governance-d3ac44ac679c4756a18e27e5ec0696d5?pvs=21)? Where would we decide to put resources towards to build a post-capitalist political economy?*** + +## BREAD as a Community Currency +### Consistent value +BREAD is linked to xDAI which is a stablecoin with equal value to USD. So $1 = 1 $BREAD. +### Built on solidarity +A solidarity primitive is a building block for solidarity through code. Build with $BREAD to have a tech stack with values. +### Fund the future +Earnings from the minting of BREAD go to supporting a co-operative of [post-capitalist web3 projects](https://breadchain.notion.site/e92f4f3dfb64402aada35a90bf2712af). \ No newline at end of file diff --git a/docs/ButteredBread.md b/docs/ButteredBread.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/YieldDistributor.md b/docs/YieldDistributor.md new file mode 100644 index 0000000..e69de29 From aeeed17502819a1bb867e84971a80ffc5536b3e9 Mon Sep 17 00:00:00 2001 From: Ron Turetzky Date: Fri, 27 Sep 2024 14:18:10 +0300 Subject: [PATCH 04/12] docs: BREAD documentation --- docs/Bread.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/Bread.md b/docs/Bread.md index d63c277..17f38aa 100644 --- a/docs/Bread.md +++ b/docs/Bread.md @@ -76,4 +76,14 @@ Lets look at another snippet from the BREAD contract , which is used to calculat 5 return assets > supply ? assets - supply : 0; 6 } ``` +On line 2 , the `bal` variable represents the sDai balance of the Bread contract. This represents how much xDai is locked and earning yield. + +In line 3 use the `bal` variable to determine how much xDai the Bread contract is eligible for by burning sDai, and we store that in the `assets` variable. This represents the original xDai locked and any rewards earned. + +On line 4 we determine how much BREAD is in circulation, and store that in the `supply` variable. This variable represents how much xDai the BREAD contract "owes" to BREAD holders, as they may redeem their BREAD for xDai at a 1:1 ratio. + +To understand how much yield the Bread contract has , we first ascertain that by burning all sDai we have enough xDai for BREAD redemptions. While the state is unreachable, this validation is present for safety reasons. Once we are certain of that , the `assets - supply` subtraction in line 5 represents the **total liquid xDai available for claim to the Bread contract** minus **the total xDai "owed" to BREAD holders**. Thus, what is left over is what can be allocated to the Breadchain projects. + +Click [here](https://docs.soliditylang.org/en/v0.8.27/types.html#ternary-operator) for a reference on the ternary operator that is used here. + From 688bb5b96af9c5ce4ba9774178ac0765289939ef Mon Sep 17 00:00:00 2001 From: Ron Turetzky Date: Fri, 27 Sep 2024 14:18:23 +0300 Subject: [PATCH 05/12] docs: YD documentation --- docs/YieldDistributor.md | 245 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) diff --git a/docs/YieldDistributor.md b/docs/YieldDistributor.md index e69de29..55b26ec 100644 --- a/docs/YieldDistributor.md +++ b/docs/YieldDistributor.md @@ -0,0 +1,245 @@ +```mermaid +classDiagram + class YieldDistributor { + <> IYieldDistributor + <> OwnableUpgradeable + + +Bread BREAD + +uint256 PRECISION + +uint256 cycleLength + +uint256 maxPoints + +uint256 minRequiredVotingPower + +uint256 lastClaimedBlockNumber + +uint256 currentVotes + +address projects + +address queuedProjectsForAddition + +address queuedProjectsForRemoval + +uint256 projectDistributions + +mapping(address => uint256) accountLastVoted + #mapping(address => null) voterDistributions + +uint256 yieldFixedSplitDivisor + +ERC20VotesUpgradeable BUTTERED_BREAD + + +__constructor__() + +initialize() + +getCurrentVotingDistribution() + +getCurrentVotingPower() + +getVotingPowerForPeriod() + +resolveYieldDistribution() + +distributeYield() + +castVote() + #_castVote() + #_updateBreadchainProjects() + +queueProjectAddition() + +queueProjectRemoval() + +setMinRequiredVotingPower() + +setMaxPoints() + +setCycleLength() + +setyieldFixedSplitDivisor() + +setButteredBread() + } + + YieldDistributor --|> IYieldDistributor : Inherits + YieldDistributor --|> OwnableUpgradeable : Inherits + +``` + +# YieldDistributor +The YieldDistributor contract is a smart contract designed to manage and distribute yield (in the form of $BREAD tokens) to eligible member projects within the Breadchain ecosystem. This contract implements a voting mechanism that allows token holders to influence the distribution of yield across various projects. By leveraging both $BREAD and $BUTTERED_BREAD tokens, the system creates a dual-token voting power structure, encouraging active participation and long-term commitment from community members. + +At its core, the YieldDistributor contract enables a democratic and transparent process for allocating resources within the Breadchain network. It features a cyclical distribution system, where token holders can cast votes using their voting power, which is calculated based on their token holdings over time. The contract supports dynamic project management, allowing for the addition and removal of eligible projects, and incorporates both fixed and voted components in the yield distribution to ensure a balance between equity and direct democracy. + +# Voting +The `castVote` function allows users to participate in the yield distribution process by allocating their voting power to different projects. Here's a detailed explanation: + +```mermaid +sequenceDiagram + actor User + participant YD as YieldDistributor + participant BREAD as BREAD Token + participant BB as BUTTERED_BREAD Token + + User->>YD: castVote(_points) + activate YD + YD->>YD: getCurrentVotingPower(msg.sender) + activate YD + YD->>YD: getVotingPowerForPeriod(BREAD, ...) + YD->>BREAD: numCheckpoints(account) + YD->>BREAD: checkpoints(account, index) + YD->>YD: getVotingPowerForPeriod(BUTTERED_BREAD, ...) + YD->>BB: numCheckpoints(account) + YD->>BB: checkpoints(account, index) + deactivate YD + + alt _currentVotingPower < minRequiredVotingPower + YD-->>User: revert BelowMinRequiredVotingPower + else _currentVotingPower >= minRequiredVotingPower + YD->>YD: _castVote(msg.sender, _points, _currentVotingPower) + end + deactivate YD +``` + + +1. The function takes an array of `_points` as input, representing the user's vote allocation for each project. These points allow for a dynamic and flexible voting system: + + - Each project can be assigned a number of points, up to `maxPoints`. + - The total number of points allocated across all projects can vary. + - The actual voting power distributed to each project is calculated proportionally based on the points allocated. + - This system allows users to express their preferences with fine-grained control, as they can allocate any number of points (up to `maxPoints`) to each project. + - For example, if there are two projects and `maxPoints` is 100, a user could vote [100, 50], [1, 2], or any other combination, providing a wide range of possible distributions within the precision of the points system. + +2. It first calculates the user's current voting power using `getCurrentVotingPower`. + +3. It checks if the user has sufficient voting power to participate. If not, it reverts. + +4. If the user has enough voting power, it calls the internal `_castVote` function. + +The internal `_castVote` function does the heavy lifting: + +```mermaid +sequenceDiagram + participant YD as YieldDistributor + participant Storage as Contract Storage + + activate YD + YD->>YD: Check _points.length == projects.length + YD->>YD: Calculate _totalPoints + YD->>YD: Check each point <= maxPoints + YD->>YD: Check _totalPoints > 0 + + YD->>Storage: Read accountLastVoted[_account] + YD->>Storage: Read lastClaimedBlockNumber + YD->>YD: Calculate _hasVotedInCycle + + alt !_hasVotedInCycle + YD->>Storage: Delete voterDistributions[_account] + YD->>Storage: Update currentVotes += _votingPower + end + + loop For each project + alt !_hasVotedInCycle + YD->>Storage: Initialize _voterDistributions[i] = 0 + else + YD->>Storage: Update projectDistributions[i] + end + + YD->>YD: Calculate _currentProjectDistribution + YD->>Storage: Update projectDistributions[i] + YD->>Storage: Update _voterDistributions[i] + end + + YD->>Storage: Update accountLastVoted[_account] + YD->>YD: Emit BreadHolderVoted event + deactivate YD +``` + +Here's what this function does: + +1. It checks if the number of points matches the number of projects. + +2. It calculates the total points and ensures they don't exceed the maximum allowed per project. + +3. It checks if the user has already voted in this cycle. + +4. If it's a new vote in the cycle, it resets the user's previous votes and adds their voting power to the current total votes. + +5. For each project: + + - If it's a new vote, it initializes the user's distribution for that project. + + - If it's an update to an existing vote, it subtracts the user's previous distribution. + + - It calculates the new distribution based on the points allocated and the user's voting power. + + - It updates both the overall project distribution and the user's personal distribution. + +6. It updates the last voted block number for the user. + +7. Finally, it emits an event with the voting details. + + +Key points: +- The function allows users to update their votes within a cycle. +- It uses precision calculations to ensure accurate distribution of voting power. +- It maintains both global project distributions and individual user distributions. +- The voting power is based on the user's token holdings (both BREAD and BUTTERED_BREAD) over a specific period. + +## Voting power +```mermaid +sequenceDiagram + actor User + participant YD as YieldDistributor + participant BREAD as BREAD Token + participant BB as BUTTERED_BREAD Token + + User->>YD: getCurrentVotingPower(account) + activate YD + YD->>YD: Calculate period start and end + YD->>YD: getVotingPowerForPeriod(BREAD, start, end, account) + activate YD + YD->>BREAD: numCheckpoints(account) + alt numCheckpoints == 0 + YD-->>YD: Return 0 + else numCheckpoints > 0 + YD->>BREAD: checkpoints(account, 0) + alt first checkpoint > end + YD-->>YD: Return 0 + else first checkpoint <= end + loop Find latest checkpoint within interval + YD->>BREAD: checkpoints(account, index) + end + YD->>YD: Calculate initial voting power + loop Process remaining checkpoints + YD->>BREAD: checkpoints(account, index) + YD->>YD: Update total voting power + alt checkpoint <= start + YD->>YD: Adjust for interval start + YD-->>YD: Break loop + end + end + end + end + YD-->>YD: Return BREAD voting power + deactivate YD + + YD->>YD: getVotingPowerForPeriod(BUTTERED_BREAD, start, end, account) + activate YD + Note over YD: Same process as BREAD + YD-->>YD: Return BUTTERED_BREAD voting power + deactivate YD + + YD->>YD: Sum BREAD and BUTTERED_BREAD voting power + YD-->>User: Return total voting power + deactivate YD +``` +Now, let's break down the getVotingPowerForPeriod function step by step: +1. Input Validation: + - Check if the start time is before the end time. + - Ensure the end time is not after the current block. +2. Initial Checkpoint Check: + - Get the total number of checkpoints for the account. + - If there are no checkpoints, return 0 voting power. +3. Boundary Checks: + - If the first checkpoint is after the end of the interval, return 0 voting power. +4. Find Relevant Checkpoints: + - Start from the latest checkpoint and move backwards. + - Find the most recent checkpoint that is within or before the end of the interval. +5. Initialize Voting Power Calculation: + - Set the initial voting power based on the latest relevant checkpoint. + - Calculate the duration from this checkpoint to the end of the interval. +6. Process Earlier Checkpoints: + - Iterate through earlier checkpoints, moving backwards in time. + - For each checkpoint: + - Calculate the voting power for the sub-interval between checkpoints. + - Add this to the total voting power. + - If the checkpoint is before or at the start of the interval: + - Adjust the voting power to exclude time before the interval start. + - Break the loop as we've covered the entire interval. +7. Return Total Voting Power: + - The function returns the accumulated voting power over the specified interval. +Key Points: + - The function uses a checkpoint system to track voting power changes over time. + - It calculates voting power as a product of token balance and time held within the specified interval. + - The calculation is done separately for both BREAD and BUTTERED_BREAD tokens, then summed for the total voting power. + - This method allows for accurate representation of voting power even with balance changes during the period. + - This approach ensures that voting power is proportional to both the amount of tokens held and the duration of holding within the specified period, promoting long-term engagement and preventing last-minute large token transfers from disproportionately influencing votes. \ No newline at end of file From 29a48b513345aa2672a199c7b03219e062525624 Mon Sep 17 00:00:00 2001 From: Ron Turetzky Date: Fri, 27 Sep 2024 16:56:39 +0300 Subject: [PATCH 06/12] docs: adding BB documentation --- docs/ButteredBread.md | 97 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/docs/ButteredBread.md b/docs/ButteredBread.md index e69de29..d2db6b2 100644 --- a/docs/ButteredBread.md +++ b/docs/ButteredBread.md @@ -0,0 +1,97 @@ +```mermaid +classDiagram + class ButteredBread { + <> IButteredBread + <> ERC20VotesUpgradeable + <> OwnableUpgradeable + + +static uint256 FIXED_POINT_PERCENT + +IERC20Votes bread + +mapping(address => bool) allowlistedLPs + +mapping(address => uint256) scalingFactors + #mapping(address => mapping(address => LPData)) _accountToLPData + + +__constructor__() + +initialize() + +accountToLPBalance() + +syncDelegation() + +deposit() + +withdraw() + +modifyAllowList() + +modifyScalingFactor() + +transfer() + +transferFrom() + +delegate() + #_deposit() + #_withdraw() + #_modifyScalingFactor() + #_syncDelegation() + #_syncVotingWeight() + } + + ButteredBread --|> IButteredBread : Inherits + ButteredBread --|> ERC20VotesUpgradeable : Inherits + ButteredBread --|> OwnableUpgradeable : Inherits +``` +# Buttered Bread + +The ButteredBread contract is designed to enhance liquidity provision and governance participation within the Breadchain ecosystem. At its core, it allows users to deposit Liquidity Pool (LP) tokens, referred to as "Butter," and in return, mint ButteredBread tokens. These ButteredBread tokens represent a scaled version of the deposited LP tokens, with the scaling factor determined for each supported liquidity pool. This mechanism incentivizes users to provide liquidity to specific pools by offering voting power. + +A key feature of the ButteredBread contract is its integration with the BREAD token's governance system. While ButteredBread tokens themselves are non-transferable, they inherit the voting power and delegation mechanics of the underlying BREAD token. This is achieved through a unique synchronization process where the ButteredBread contract mirrors the delegation choices made by users in the BREAD token contract. Additionally, the contract allows for dynamic adjustment of scaling factors, enabling the protocol to fine-tune incentives for different liquidity pools over time. + +## Deposits + +```mermaid +sequenceDiagram + actor User + participant BB as ButteredBread + participant LP as Liquidity Pool Token + + BB->>LP: deposit(amount) + BB->>LP: approve(address) approve BB to take tokens + User->>BB: deposit(lp, amount) + activate BB + BB->>BB: Check if LP is allowlisted + BB->>LP: transferFrom(user, this, amount) + BB->>BB: Update user's LP balance + BB->>BB: Calculate ButteredBread to mint + BB->>BB: Mint ButteredBread tokens + BB->>BB: Sync delegation + BB-->>User: Deposit complete + deactivate BB +``` +1. User calls deposit function with LP address and amount. +2. The contract checks if the LP is allowlisted. +3. It transfers LP tokens from the user to the contract. +4. Updates the user's LP balance in the contract's storage. +5. Calculates the amount of ButteredBread tokens to mint based on the scaling factor. +6. Mints the calculated amount of ButteredBread tokens to the user. +7. Syncs the user's delegation based on their delegation in the $BREAD contract + +## Withdrawals +```mermaid +sequenceDiagram + actor User + participant BB as ButteredBread + participant LP as Liquidity Pool Token + + User->>BB: withdraw(lp, amount) + activate BB + BB->>BB: Check if LP is allowlisted + BB->>BB: Check if user has sufficient balance + BB->>BB: Sync delegation + BB->>BB: Sync voting weight + BB->>BB: Update user's LP balance + BB->>BB: Calculate ButteredBread to burn + BB->>BB: Burn ButteredBread tokens + BB->>LP: transfer(user, amount) + BB-->>User: Withdrawal complete + deactivate BB +``` + +1. User calls `withdraw` function with LP address and amount. +2. The contract checks if the LP is allowlisted. +3. It checks if the user has sufficient balance to withdraw. +6. Updates the user's LP balance in the contract's storage. +8. Burns the calculated amount of ButteredBread tokens from the user. +9. Transfers the LP tokens back to the user. \ No newline at end of file From a033840e9f015f2e8a91cdb42a85167e51ed6b6f Mon Sep 17 00:00:00 2001 From: Ron Turetzky Date: Fri, 27 Sep 2024 17:01:15 +0300 Subject: [PATCH 07/12] fix: updating to https to make installation easier as per #76 --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index e2c1eca..254c1db 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,7 +9,7 @@ url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable [submodule "lib/bread-token-v2"] path = lib/bread-token-v2 - url = git@github.com:BreadchainCoop/bread-token-v2.git + url = https://github.com/BreadchainCoop/bread-token-v2.git [submodule "lib/openzeppelin-foundry-upgrades"] path = lib/openzeppelin-foundry-upgrades url = https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades From 16fff98429cdd10dd6f810afbb11fe6ca18aef56 Mon Sep 17 00:00:00 2001 From: Ron Turetzky Date: Fri, 27 Sep 2024 17:34:41 +0300 Subject: [PATCH 08/12] docs: addressing possible dust left by divison --- src/YieldDistributor.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/YieldDistributor.sol b/src/YieldDistributor.sol index 8128b57..f081189 100644 --- a/src/YieldDistributor.sol +++ b/src/YieldDistributor.sol @@ -195,7 +195,7 @@ contract YieldDistributor is IYieldDistributor, OwnableUpgradeable { } /** - * @notice Distribute $BREAD yield to projects based on cast votes + * @notice Distribute $BREAD yield to projects based on cast votes, may leave some dust */ function distributeYield() public { (bool _resolved,) = resolveYieldDistribution(); From 98911b6c5355e2f27830743742a577f224e262e4 Mon Sep 17 00:00:00 2001 From: Ron Turetzky Date: Fri, 27 Sep 2024 17:36:08 +0300 Subject: [PATCH 09/12] fix: removing reference to basis points as points can be arbitrarily scaled --- src/YieldDistributor.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/YieldDistributor.sol b/src/YieldDistributor.sol index f081189..9071064 100644 --- a/src/YieldDistributor.sol +++ b/src/YieldDistributor.sol @@ -236,7 +236,7 @@ contract YieldDistributor is IYieldDistributor, OwnableUpgradeable { /** * @notice Internal function for casting votes for a specified user * @param _account Address of user to cast votes for - * @param _points Basis points for calculating the amount of votes cast + * @param _points Points for calculating the amount of votes cast * @param _votingPower Amount of voting power being cast */ function _castVote(address _account, uint256[] calldata _points, uint256 _votingPower) internal { From 5a36481b09a9675b4005901cc78164a7714ac5cb Mon Sep 17 00:00:00 2001 From: Ron Turetzky Date: Fri, 27 Sep 2024 17:40:30 +0300 Subject: [PATCH 10/12] docs: mentioning the powerpool grant --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 33de9fb..c3ec35e 100644 --- a/README.md +++ b/README.md @@ -64,4 +64,7 @@ forge script script/deploy/DeployYieldDistributor.s.sol:DeployYieldDistributor - 1. Amend the `data` variable in `script/upgrades/UpgradeYieldDistributor.s.sol` to match desired data 2. run `forge clean && forge build && forge script script/upgrades/UpgradeYieldDistributor.s.sol --sig "run(address)" --rpc-url $RPC_URL --sender ` -The proxy admin address is configured to be the Breadchain multisig at address `0x918dEf5d593F46735f74F9E2B280Fe51AF3A99ad` and the Yield Distributor proxy address is `0xeE95A62b749d8a2520E0128D9b3aCa241269024b` \ No newline at end of file +The proxy admin address is configured to be the Breadchain multisig at address `0x918dEf5d593F46735f74F9E2B280Fe51AF3A99ad` and the Yield Distributor proxy address is `0xeE95A62b749d8a2520E0128D9b3aCa241269024b` + + +The development of this project was enabled by a [grant](https://gov.powerpool.finance/t/approved-grant-for-breadchain-cooperative-integrations/2007) from [Powerpool](https://powerpool.finance/). \ No newline at end of file From 3c620e5295b96ab45581246dc555b3a7918466b3 Mon Sep 17 00:00:00 2001 From: Ron Turetzky Date: Sat, 28 Sep 2024 19:52:26 +0300 Subject: [PATCH 11/12] fix: seperated clone and build --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c3ec35e..3cf3bdc 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,13 @@ If you have skills (both technical and non-technical) that you believe would ben Contributions to this repo are expected to adhere to the [Biconomy Solidity Style Guide](https://github.com/bcnmy/biconomy-solidity-style-guide). ## Usage - +### Clone +```shell +$ git clone git@github.com:BreadchainCoop/breadchain.git --recursive +``` ### Build ```shell -$ git clone git@github.com:BreadchainCoop/breadchain.git --recursive $ forge build ``` From a0360069eee5cfdf1525f407026c2d870e818029 Mon Sep 17 00:00:00 2001 From: Ron Turetzky Date: Sat, 28 Sep 2024 20:17:37 +0300 Subject: [PATCH 12/12] fix: fixing run on and specifying duration --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3cf3bdc..e5234bf 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ If you have skills (both technical and non-technical) that you believe would ben Contributions to this repo are expected to adhere to the [Biconomy Solidity Style Guide](https://github.com/bcnmy/biconomy-solidity-style-guide). ## Usage + ### Clone ```shell $ git clone git@github.com:BreadchainCoop/breadchain.git --recursive @@ -41,7 +42,7 @@ For validating that tests are working run $ forge test --fork-url "https://rpc.gnosis.gateway.fm" -vvvv --fuzz-runs 1 ``` -For a full run of tests run the following command, note that it may take a significant amount of time +For a full run of tests run the following command. Note that the command may take upwards of 8 minutes to execute. ```shell $ forge test --fork-url "https://rpc.gnosis.gateway.fm" -vvvv