Skip to content
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

Lineage extension #974

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8ab4f74
skeleton of lineage system
funderbrker Jul 4, 2024
74bf9d0
fert out logic
funderbrker Jul 4, 2024
14f385f
migrate in fert
funderbrker Jul 7, 2024
2fef3f8
migrate out deposits logic
funderbrker Jul 7, 2024
6abcd16
fert migrate out patch
funderbrker Jul 7, 2024
9b2e80a
mow on deposit migration
funderbrker Jul 7, 2024
54991fa
migrate in deposits logic
funderbrker Jul 8, 2024
a2a22c3
compilation fixes
funderbrker Jul 8, 2024
2437b86
Merge branch 'test-3' into lineage-extension
funderbrker Jul 8, 2024
17bf0d1
shuffle init diamond, fix typos
funderbrker Jul 9, 2024
5cceabe
migration patches. executes
funderbrker Jul 9, 2024
59e7705
lineage migration test. wip.
funderbrker Jul 9, 2024
50b4358
migration grown stalk fix
funderbrker Jul 9, 2024
de9be79
update field to handle holes via Slashing
funderbrker Jul 15, 2024
9f7d9da
pod migration out
funderbrker Jul 15, 2024
40a643b
migrate in plots
funderbrker Jul 19, 2024
fafcd7b
readme update
funderbrker Jul 27, 2024
6d7a778
remove fn to add new sources
funderbrker Aug 12, 2024
84fca25
partial revert of contracts/beanstalk/init/InitalizeDiamond.sol
funderbrker Aug 12, 2024
14da241
rm old init file
funderbrker Aug 13, 2024
a1cb901
update deposits tests and supporting logic
funderbrker Aug 13, 2024
52c83ec
cleap up foundry test helpers
funderbrker Aug 13, 2024
67977a2
update + fix fert migration logic. add fert migration test
funderbrker Aug 13, 2024
8d34f2b
finalized plot migration design. patch implementation. add plot migra…
funderbrker Aug 13, 2024
b120426
dust cleanup
funderbrker Aug 13, 2024
3851ae9
test - migrate deposits to new
funderbrker Aug 15, 2024
5cafece
parent migrate out events. bug fixes.
funderbrker Aug 15, 2024
9f63558
refactor foundry tests to allow multiple beanstalks
funderbrker Aug 15, 2024
41c95dd
test alternative beanstalk constants
funderbrker Aug 15, 2024
441dc85
plots descendants to new instance, tests & fixes
funderbrker Aug 16, 2024
00a733b
rename migrate -> transmit
funderbrker Aug 16, 2024
332584a
--lineage--
funderbrker Aug 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions protocol/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,13 @@ _Note: The Beanstalk repo is a monorepo with induvidual projects inside it. See

1. Clone the repository and install dependencies

*If using Mac on Apple Silicon*
`/usr/sbin/softwareupdate --install-rosetta --agree-to-license`

```bash
git clone https://github.com/BeanstalkFarms/Beanstalk
cd Beanstalk/protocol
export YARN_IGNORE_NODE=1
yarn
```

Expand Down
38 changes: 38 additions & 0 deletions protocol/contracts/beanstalk/ForkSystem/TransmitInFacet.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* SPDX-License-Identifier: MIT
**/

pragma solidity ^0.8.20;

import {AppStorage} from "contracts/beanstalk/storage/AppStorage.sol";
import {Invariable} from "contracts/beanstalk/Invariable.sol";
import {LibTransmitIn} from "contracts/libraries/ForkSystem/LibTransmitIn.sol";

/**
* @title TransmitInFacet
* @author funderbrker
* @notice Destination instance logic for receiving transmitted assets from another version.
* @notice Destination has knowledge of valid Sources and their configurations at deployment time.
**/
contract TransmitInFacet is Invariable {
AppStorage internal s;

/**
* @notice Process the inbound migration locally.
* @dev Reverts if failure to mint assets or handle migration in.
* @dev Arguments are bytes because different sources may use different encodings.
*/
function transmitIn(
address user,
bytes[] calldata deposits,
bytes[] calldata plots,
bytes[] calldata fertilizer,
bytes calldata // data
) external fundsSafu {
require(s.sys.supportedSourceForks[msg.sender], "Unsupported source");

LibTransmitIn.transmitInDeposits(user, deposits);
LibTransmitIn.transmitInPlots(user, plots);
LibTransmitIn.transmitInFertilizer(user, fertilizer);
}
}
50 changes: 50 additions & 0 deletions protocol/contracts/beanstalk/ForkSystem/TransmitOutFacet.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* SPDX-License-Identifier: MIT
**/

pragma solidity ^0.8.20;

import {Invariable} from "contracts/beanstalk/Invariable.sol";
import {LibTractor} from "contracts/libraries/LibTractor.sol";
import {LibTransmitOut} from "contracts/libraries/ForkSystem/LibTransmitOut.sol";
import {ITransmitInFacet} from "contracts/interfaces/ITransmitInFacet.sol";

/**
* @title TransmitOutFacet
* @author funderbrker
* @notice Source instance logic for migrating assets to new version.
* @notice Source instance has no knowledge of possible Destinations or their configurations.
**/
contract TransmitOutFacet is Invariable {
/**
* @notice Process the outbound migration and transfer necessary assets to destination.
* @dev Reverts if failure to burn assets or destination fails.
*/
function transmitOut(
address destination,
LibTransmitOut.SourceDeposit[] calldata sourceDeposits,
LibTransmitOut.SourcePlot[] calldata sourcePlots,
LibTransmitOut.SourceFertilizer[] calldata sourceFertilizer,
bytes calldata // data
) external fundsSafu {
bytes[] memory deposits = LibTransmitOut.transmitOutDeposits(
LibTractor._user(),
destination,
sourceDeposits
);
bytes[] memory plots = LibTransmitOut.transmitOutPlots(LibTractor._user(), sourcePlots);
bytes[] memory fertilizer = LibTransmitOut.transmitOutFertilizer(
LibTractor._user(),
sourceFertilizer
);

// Reverts if Destination fails to handle transmitted assets.
ITransmitInFacet(destination).transmitIn(
LibTractor._user(),
deposits,
plots,
fertilizer,
abi.encode("")
);
}
}
2 changes: 1 addition & 1 deletion protocol/contracts/beanstalk/Invariable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ abstract contract Invariable {
s.sys.fert.leftoverBeans) + // unrinsed rinsable beans
s.sys.silo.unripeSettings[C.UNRIPE_BEAN].balanceOfUnderlying; // unchopped underlying beans
for (uint256 j; j < s.sys.fieldCount; j++) {
entitlements[i] += (s.sys.fields[j].harvestable - s.sys.fields[j].harvested); // unharvested harvestable beans
entitlements[i] += (s.sys.fields[j].harvestable - s.sys.fields[j].processed); // unharvested harvestable beans
}
} else if (tokens[i] == LibUnripe._getUnderlyingToken(C.UNRIPE_LP)) {
entitlements[i] += s.sys.silo.unripeSettings[C.UNRIPE_LP].balanceOfUnderlying;
Expand Down
4 changes: 1 addition & 3 deletions protocol/contracts/beanstalk/barn/FertilizerFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@ contract FertilizerFacet is Invariable {
uint256[] calldata ids,
LibTransfer.To mode
) external payable fundsSafu noSupplyChange oneOutFlow(C.BEAN) {
uint256 amount = C.fertilizer().beanstalkUpdate(LibTractor._user(), ids, s.sys.fert.bpf);
s.sys.fert.fertilizedPaidIndex += amount;
LibTransfer.sendToken(C.bean(), amount, LibTractor._user(), mode);
LibFertilizer.claimFertilized(ids, mode);
}

/**
Expand Down
40 changes: 27 additions & 13 deletions protocol/contracts/beanstalk/field/FieldFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {ReentrancyGuard} from "../ReentrancyGuard.sol";
import {Invariable} from "contracts/beanstalk/Invariable.sol";
import {LibDiamond} from "contracts/libraries/LibDiamond.sol";
import {LibMarket} from "contracts/libraries/LibMarket.sol";
import {LibField} from "contracts/libraries/LibField.sol";


interface IBeanstalk {
function cancelPodListing(uint256 fieldId, uint256 index) external;
Expand Down Expand Up @@ -156,6 +158,7 @@ contract FieldFacet is Invariable, ReentrancyGuard {
*
* Pods are "burned" when the corresponding Plot is deleted from
* `s.accts[account].fields[fieldId].plots`.
* @dev If Plot has been Slashed, burn the Plot. Anyone can burn Slashed Plots.
*/
function harvest(
uint256 fieldId,
Expand All @@ -169,6 +172,7 @@ contract FieldFacet is Invariable, ReentrancyGuard {
/**
* @dev Ensure that each Plot is at least partially harvestable, burn the Plot,
* update the total harvested, and emit a {Harvest} event.
* @dev If Plot has been Slashed, burn the Plot.
*/
function _harvest(
uint256 fieldId,
Expand All @@ -181,20 +185,24 @@ contract FieldFacet is Invariable, ReentrancyGuard {
uint256 harvested = _harvestPlot(LibTractor._user(), fieldId, plots[i]);
beansHarvested += harvested;
}
s.sys.fields[fieldId].harvested += beansHarvested;
s.sys.fields[fieldId].processed += beansHarvested;
emit Harvest(LibTractor._user(), fieldId, plots, beansHarvested);
}

/**
* @dev Check if a Plot is at least partially Harvestable; calculate how many
* Pods are Harvestable, create a new Plot if necessary.
* @dev If Plot has been Slashed, burn the Plot.
*/
function _harvestPlot(
address account,
uint256 fieldId,
uint256 index
) private returns (uint256 harvestablePods) {
// Check that `account` holds this Plot.
// If Plot held by null address, it has been Slashed. Burn Plot.
if (s.accts[address(0)].fields[fieldId].plots[index] > 0) {
account = address(0);
}
uint256 pods = s.accts[account].fields[fieldId].plots[index];
require(pods > 0, "Field: no plot");

Expand All @@ -203,10 +211,14 @@ contract FieldFacet is Invariable, ReentrancyGuard {
// are harvestable.
harvestablePods = s.sys.fields[fieldId].harvestable.sub(index);

LibMarket._cancelPodListing(LibTractor._user(), fieldId, index);
LibMarket._cancelPodListing(account, fieldId, index);

delete s.accts[account].fields[fieldId].plots[index];
LibDibbler.removePlotIndexFromAccount(account, fieldId, index);
LibField.deletePlot(account, fieldId, index);

// If burning a Slashed Plot, amount harvestable does not decrease.
if (account == address(0)) {
s.sys.fields[fieldId].harvestable += harvestablePods;
}

// If the entire Plot was harvested, exit.
if (harvestablePods >= pods) {
Expand Down Expand Up @@ -273,42 +285,44 @@ contract FieldFacet is Invariable, ReentrancyGuard {

/**
* @notice Returns the number of outstanding Pods. Includes Pods that are
* currently Harvestable but have not yet been Harvested.
* currently Harvestable or Burnable but have not yet been Harvested.
* @param fieldId The index of the Field to query.
*/
function totalPods(uint256 fieldId) public view returns (uint256) {
return s.sys.fields[fieldId].pods - s.sys.fields[fieldId].harvested;
return s.sys.fields[fieldId].pods - s.sys.fields[fieldId].processed;
}

/**
* @notice Returns the number of Pods that have ever been Harvested.
* @notice Returns the number of Pods that have ever been Harvested or Burned.
* @param fieldId The index of the Field to query.
*/
function totalHarvested(uint256 fieldId) public view returns (uint256) {
return s.sys.fields[fieldId].harvested;
function totalProcessed(uint256 fieldId) public view returns (uint256) {
return s.sys.fields[fieldId].processed;
}

/**
* @notice Returns the number of Pods that are currently Harvestable but
* have not yet been Harvested.
* @dev This is the number of Pods that Beanstalk is prepared to pay back,
* but that haven’t yet been claimed via the `harvest()` function.
* @dev Cannot use this number as an index, as there is no accounting for Slashed plots.
* @param fieldId The index of the Field to query.
*/
function totalHarvestable(uint256 fieldId) public view returns (uint256) {
return s.sys.fields[fieldId].harvestable - s.sys.fields[fieldId].harvested;
return s.sys.fields[fieldId].harvestable - s.sys.fields[fieldId].processed;
}

/**
* @notice Returns the number of Pods that are currently Harvestable for the active Field.
* @dev Cannot use this number as an index, as there is no accounting for Slashed plots.
*/
function totalHarvestableForActiveField() public view returns (uint256) {
return
s.sys.fields[s.sys.activeField].harvestable - s.sys.fields[s.sys.activeField].harvested;
return totalHarvestable(s.sys.activeField);
}

/**
* @notice Returns the number of Pods that are not yet Harvestable. Also known as the Pod Line.
* @dev Includes Slashed Pods.
* @param fieldId The index of the Field to query.
*/
function totalUnharvestable(uint256 fieldId) public view returns (uint256) {
Expand Down
67 changes: 11 additions & 56 deletions protocol/contracts/beanstalk/init/InitDiamond.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,68 +4,23 @@

pragma solidity ^0.8.20;

import {AppStorage} from "../storage/AppStorage.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import {IDiamondCut} from "../../interfaces/IDiamondCut.sol";
import {IDiamondLoupe} from "../../interfaces/IDiamondLoupe.sol";
import {LibDiamond} from "../../libraries/LibDiamond.sol";
import {LibIncentive} from "../../libraries/LibIncentive.sol";
import {LibCases} from "../../libraries/LibCases.sol";
import {LibGauge} from "contracts/libraries/LibGauge.sol";
import {C} from "../../C.sol";
import {IBean} from "../../interfaces/IBean.sol";
import {IWETH} from "../../interfaces/IWETH.sol";
import {MockToken} from "../../mocks/MockToken.sol";
import {Weather} from "contracts/beanstalk/sun/SeasonFacet/Weather.sol";
import {LibIncentive} from "contracts/libraries/LibIncentive.sol";
import {InitializeDiamond} from "contracts/beanstalk/init/InitializeDiamond.sol";
import {C} from "contracts/C.sol";

/**
* @author Publius
* @author Publius, Brean
* @title InitDiamond
* @notice InitDiamond initializes the Beanstalk Diamond.
* A new bean token and bean:TOKEN well are deployed.
*
**/
contract InitDiamond is Weather {
address private constant PEG_PAIR = address(0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc);
contract InitDiamond is InitializeDiamond {
// initial reward for deploying beanstalk.
uint256 constant INIT_SUPPLY = 100e6;

function init() external {
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
initializeDiamond(C.BEAN, C.BEAN_ETH_WELL);

ds.supportedInterfaces[type(IERC165).interfaceId] = true;
ds.supportedInterfaces[type(IDiamondCut).interfaceId] = true;
ds.supportedInterfaces[type(IDiamondLoupe).interfaceId] = true;
ds.supportedInterfaces[0xd9b67a26] = true; // ERC1155
ds.supportedInterfaces[0x0e89341c] = true; // ERC1155Metadata

LibCases.setCasesV2();
s.sys.weather.temp = 1;

s.sys.season.current = 1;
s.sys.season.withdrawSeasons = 25;
s.sys.season.period = C.getSeasonPeriod();
s.sys.season.timestamp = block.timestamp;
s.sys.season.start = s.sys.season.period > 0
? (block.timestamp / s.sys.season.period) * s.sys.season.period
: block.timestamp;

s.sys.weather.thisSowTime = type(uint32).max;
s.sys.weather.lastSowTime = type(uint32).max;
s.sys.isFarm = 1;

s.sys.usdTokenPrice[C.BEAN_ETH_WELL] = 1;
s.sys.twaReserves[C.BEAN_ETH_WELL].reserve0 = 1;
s.sys.twaReserves[C.BEAN_ETH_WELL].reserve1 = 1;

s.sys.seedGauge.beanToMaxLpGpPerBdvRatio = 50e18; // 50%
s.sys.seedGauge.averageGrownStalkPerBdvPerSeason = 3e6;

emit BeanToMaxLpGpPerBdvRatioChange(
s.sys.season.current,
type(uint256).max,
int80(int128(s.sys.seedGauge.beanToMaxLpGpPerBdvRatio))
);
emit LibGauge.UpdateAverageStalkPerBdvPerSeason(
s.sys.seedGauge.averageGrownStalkPerBdvPerSeason
);
C.bean().mint(msg.sender, INIT_SUPPLY);
}
}
}
Loading