Skip to content

Commit

Permalink
clean up wellUpgradeable.
Browse files Browse the repository at this point in the history
  • Loading branch information
Brean0 committed Jul 23, 2024
1 parent dd66d36 commit fd47d26
Show file tree
Hide file tree
Showing 7 changed files with 28 additions and 99 deletions.
1 change: 0 additions & 1 deletion script/helpers/WellDeployer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ abstract contract WellDeployer {
_well = Well(Aquifer(_aquifer).boreWell(_wellImplementation, immutableData, initData, _salt));
}


/**
* @notice Encode the Well's immutable data, and deploys the well. Modified for upgradeable wells.
* @param _aquifer The address of the Aquifer which will deploy this Well.
Expand Down
52 changes: 12 additions & 40 deletions src/WellUpgradeable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,11 @@ import {UUPSUpgradeable} from "ozu/proxy/utils/UUPSUpgradeable.sol";
import {OwnableUpgradeable} from "ozu/access/OwnableUpgradeable.sol";
import {IERC20, SafeERC20} from "oz/token/ERC20/utils/SafeERC20.sol";
import {IAquifer} from "src/interfaces/IAquifer.sol";
import {console} from "forge-std/console.sol";

/**
* @title WellUpgradeable
* @author Publius, Silo Chad, Brean, Deadmanwalking
* @dev A Well is a constant function AMM allowing the provisioning of liquidity
* into a single pooled on-chain liquidity position.
*
* Given the dynamic storage layout of Wells initialized by an minimal proxy,
* Creating an upgradeable Well requires a custom initializer function that allows the Well
* to be initialized with immutable storage, but does not deploy a Well token.
*
* Rebasing Tokens:
* - Positive rebasing tokens are supported by Wells, but any tokens recieved from a
* rebase will not be rewarded to LP holders and instead can be extracted by anyone
* using `skim`, `sync` or `shift`.
* - Negative rebasing tokens should not be used in Well as the effect of a negative
* rebase will be realized by users interacting with the Well, not LP token holders.
*
* Fee on Tranfer (FoT) Tokens:
* - When transferring fee on transfer tokens to a Well (swapping from or adding liquidity),
* use `swapFromFeeOnTrasfer` or `addLiquidityFeeOnTransfer`. `swapTo` does not support
* fee on transfer tokens (See {swapTo}).
* - When recieving fee on transfer tokens from a Well (swapping to and removing liquidity),
* INCLUDE the fee that is taken on transfer when calculating amount out values.
* @author Deadmanwalking, Brean, Brendan, Silo Chad
* @notice WellUpgradeable is an upgradeable version of the Well contract.
*/
contract WellUpgradeable is Well, UUPSUpgradeable, OwnableUpgradeable {
address private immutable ___self = address(this);
Expand All @@ -40,7 +20,7 @@ contract WellUpgradeable is Well, UUPSUpgradeable, OwnableUpgradeable {
* @notice verifies that the execution is called through an minimal proxy or is not a delegate call.
*/
modifier notDelegatedOrIsMinimalProxy() {
if (address(this) != ___self) {
if (address(this) != ___self) {
address aquifer = aquifer();
address wellImplmentation = IAquifer(aquifer).wellImplementation(address(this));
require(wellImplmentation == ___self, "Function must be called by a Well bored by an aquifer");
Expand All @@ -50,10 +30,7 @@ contract WellUpgradeable is Well, UUPSUpgradeable, OwnableUpgradeable {
_;
}

function init(
string memory _name,
string memory _symbol
) external override reinitializer(2) {
function init(string memory _name, string memory _symbol) external override reinitializer(2) {
// owner of Well param as the aquifier address will be the owner initially
// ownable init transfers ownership to msg.sender
__ERC20Permit_init(_name);
Expand All @@ -74,9 +51,7 @@ contract WellUpgradeable is Well, UUPSUpgradeable, OwnableUpgradeable {
}

/**
* @notice `initClone` allows for the Well to be initialized without deploying a Well token.
* @dev This function is required given intializing with the Well token would create two valid Wells.
* Sets ReentraryGuard to true to prevent users from interacting with the Well.
* @notice `initNoWellToken` allows for the Well to be initialized without deploying a Well token.
*/
function initNoWellToken() external initializer {}

Expand All @@ -100,24 +75,21 @@ contract WellUpgradeable is Well, UUPSUpgradeable, OwnableUpgradeable {

// verify the new implmentation is a well bored by an aquifier.
require(
IAquifer(aquifer).wellImplementation(newImplmentation) !=
address(0),
IAquifer(aquifer).wellImplementation(newImplmentation) != address(0),
"New implementation must be a well implmentation"
);

// verify the new implmentation is a valid ERC-1967 implmentation.
console.log("here");
require(
UUPSUpgradeable(newImplmentation).proxiableUUID() ==
_IMPLEMENTATION_SLOT,
UUPSUpgradeable(newImplmentation).proxiableUUID() == _IMPLEMENTATION_SLOT,
"New implementation must be a valid ERC-1967 implmentation"
);
}

/**
* @notice Upgrades the implementation of the proxy to `newImplementation`.
* Calls {_authorizeUpgrade}.
* @dev `upgradeTo` was modified to support ERC-1167 minimal proxies
* @dev `upgradeTo` was modified to support ERC-1167 minimal proxies
* cloned (Bored) by an Aquifer.
*/
function upgradeTo(address newImplementation) public override {
Expand All @@ -128,10 +100,10 @@ contract WellUpgradeable is Well, UUPSUpgradeable, OwnableUpgradeable {
/**
* @notice Upgrades the implementation of the proxy to `newImplementation`.
* Calls {_authorizeUpgrade}.
* @dev `upgradeTo` was modified to support ERC-1167 minimal proxies
* @dev `upgradeTo` was modified to support ERC-1167 minimal proxies
* cloned (Bored) by an Aquifer.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable override {
function upgradeToAndCall(address newImplementation, bytes memory data) public payable override {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data, true);
}
Expand All @@ -142,7 +114,7 @@ contract WellUpgradeable is Well, UUPSUpgradeable, OwnableUpgradeable {
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. However, Wells bored by Aquifers
* are ERC-1167 minimal immutable clones and cannot delgate to another proxy. Thus, `proxiableUUID` was updated to support
* are ERC-1167 minimal immutable clones and cannot delgate to another proxy. Thus, `proxiableUUID` was updated to support
* this specific usecase.
*/
function proxiableUUID() external view override notDelegatedOrIsMinimalProxy returns (bytes32) {
Expand All @@ -153,7 +125,7 @@ contract WellUpgradeable is Well, UUPSUpgradeable, OwnableUpgradeable {
return _getImplementation();
}

function getVersion() external pure virtual returns (uint256) {
function getVersion() external pure virtual returns (uint256) {
return 1;
}

Expand Down
1 change: 0 additions & 1 deletion src/libraries/LibMath.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ library LibMath {
* Implementation from: https://github.com/Gaussian-Process/solidity-sqrt/blob/main/src/FixedPointMathLib.sol
* based on https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol
*/

function sqrt(uint256 a) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/LibWellUpgradeableConstructor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,4 @@ library LibWellUpgradeableConstructor {
function encodeCall(address target, bytes memory data) public pure returns (Call memory) {
return Call(target, data);
}
}
}
1 change: 0 additions & 1 deletion src/pumps/MultiFlowPump.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import {LibMath} from "src/libraries/LibMath.sol";
* Note: If an `update` call is made with a reserve of 0, the Geometric mean oracles will be set to 0.
* Each Well is responsible for ensuring that an `update` call cannot be made with a reserve of 0.
*/

contract MultiFlowPump is IPump, IMultiFlowPumpErrors, IInstantaneousPump, ICumulativePump {
using LibLastReserveBytes for bytes32;
using LibBytes16 for bytes32;
Expand Down
64 changes: 14 additions & 50 deletions test/WellUpgradeable.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {ConstantProduct2} from "src/functions/ConstantProduct2.sol";
import {Aquifer} from "src/Aquifer.sol";
import {WellDeployer} from "script/helpers/WellDeployer.sol";
import {LibWellUpgradeableConstructor} from "src/libraries/LibWellUpgradeableConstructor.sol";
import {LibContractInfo} from "src/libraries/LibContractInfo.sol";
import {MockToken} from "mocks/tokens/MockToken.sol";
import {WellDeployer} from "script/helpers/WellDeployer.sol";
import {ERC1967Proxy} from "oz/proxy/ERC1967/ERC1967Proxy.sol";
Expand Down Expand Up @@ -44,16 +43,13 @@ contract WellUpgradeTest is Test, WellDeployer {
user = makeAddr("user");

// Mint tokens
MockToken(address(tokens[0])).mint(user, 10000000000000000);
MockToken(address(tokens[1])).mint(user, 10000000000000000);
MockToken(address(tokens[0])).mint(user, 10_000_000_000_000_000);
MockToken(address(tokens[1])).mint(user, 10_000_000_000_000_000);
// Well Function
IWellFunction cp2 = new ConstantProduct2();
vm.label(address(cp2), "CP2");
wellFunctionAddress = address(cp2);
Call memory wellFunction = Call(
address(cp2),
abi.encode("beanstalkFunction")
);
Call memory wellFunction = Call(address(cp2), abi.encode("beanstalkFunction"));

// Pump
IPump mockPump = new MockPump();
Expand All @@ -69,14 +65,8 @@ contract WellUpgradeTest is Test, WellDeployer {
initialOwner = makeAddr("owner");

// Well
WellUpgradeable well = encodeAndBoreWellUpgradeable(
aquifer,
wellImplementation,
tokens,
wellFunction,
pumps,
bytes32(0)
);
WellUpgradeable well =
encodeAndBoreWellUpgradeable(aquifer, wellImplementation, tokens, wellFunction, pumps, bytes32(0));
wellAddress = address(well);
vm.label(wellAddress, "upgradeableWell");
// Sum up of what is going on here
Expand All @@ -102,10 +92,7 @@ contract WellUpgradeTest is Test, WellDeployer {
vm.startPrank(initialOwner);
ERC1967Proxy proxy = new ERC1967Proxy(
address(well), // implementation address
LibWellUpgradeableConstructor.encodeWellInitFunctionCall(
tokens,
wellFunction
) // init data
LibWellUpgradeableConstructor.encodeWellInitFunctionCall(tokens, wellFunction) // init data
);
vm.stopPrank();
proxyAddress = address(proxy);
Expand Down Expand Up @@ -140,12 +127,8 @@ contract WellUpgradeTest is Test, WellDeployer {
}

function testProxyGetWellFunction() public {
Call memory proxyWellFunction = WellUpgradeable(proxyAddress)
.wellFunction();
assertEq(
address(proxyWellFunction.target),
address(wellFunctionAddress)
);
Call memory proxyWellFunction = WellUpgradeable(proxyAddress).wellFunction();
assertEq(address(proxyWellFunction.target), address(wellFunctionAddress));
assertEq(proxyWellFunction.data, abi.encode("beanstalkFunction"));
}

Expand All @@ -160,10 +143,7 @@ contract WellUpgradeTest is Test, WellDeployer {

function testProxyNumTokens() public {
uint256 expectedNumTokens = 2;
assertEq(
expectedNumTokens,
WellUpgradeable(proxyAddress).numberOfTokens()
);
assertEq(expectedNumTokens, WellUpgradeable(proxyAddress).numberOfTokens());
}

///////////////// Interaction test //////////////////
Expand All @@ -173,18 +153,8 @@ contract WellUpgradeTest is Test, WellDeployer {
uint256[] memory amounts = new uint256[](2);
amounts[0] = 1000;
amounts[1] = 1000;
WellUpgradeable(wellAddress).addLiquidity(
amounts,
0,
user,
type(uint256).max
);
WellUpgradeable(proxyAddress).addLiquidity(
amounts,
0,
user,
type(uint256).max
);
WellUpgradeable(wellAddress).addLiquidity(amounts, 0, user, type(uint256).max);
WellUpgradeable(proxyAddress).addLiquidity(amounts, 0, user, type(uint256).max);
assertEq(amounts, WellUpgradeable(proxyAddress).getReserves());
vm.stopPrank();
}
Expand Down Expand Up @@ -218,16 +188,10 @@ contract WellUpgradeTest is Test, WellDeployer {
Call memory wellFunction = Call(wellFunctionAddress, abi.encode("2"));
Call[] memory pumps = new Call[](1);
pumps[0] = Call(mockPumpAddress, abi.encode("2"));
// create new mock Well Implementation:
// create new mock Well Implementation:
address wellImpl = address(new MockWellUpgradeable());
WellUpgradeable well2 = encodeAndBoreWellUpgradeable(
aquifer,
wellImpl,
tokens,
wellFunction,
pumps,
bytes32(abi.encode("2"))
);
WellUpgradeable well2 =
encodeAndBoreWellUpgradeable(aquifer, wellImpl, tokens, wellFunction, pumps, bytes32(abi.encode("2")));
vm.label(address(well2), "upgradeableWell2");

vm.startPrank(initialOwner);
Expand Down
6 changes: 1 addition & 5 deletions test/pumps/Pump.CapReserves.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,7 @@ contract CapBalanceTest is TestHelper, MultiFlowPump {

_well = address(
new MockStaticWell(
deployMockTokens(2),
Call(address(wf), new bytes(0)),
deployPumps(1),
address(0),
new bytes(0)
deployMockTokens(2), Call(address(wf), new bytes(0)), deployPumps(1), address(0), new bytes(0)
)
);
}
Expand Down

0 comments on commit fd47d26

Please sign in to comment.