diff --git a/README.md b/README.md index 768ea51e..9a64775a 100644 --- a/README.md +++ b/README.md @@ -30,15 +30,27 @@ Read the local [docs](./docs/src/), hosted docs [docs.primitive.xyz](https://doc | Contract | Canonical cross-chain address | | -------------------- | -------------------------------------------- | | Portfolio 1.3.0-beta | `0x82360b9a2076a09ea8abe2b3e11aed89de3a02d1` | -| Portfolio 1.4.0-beta | `todo` | +| Portfolio 1.4.0-beta | `n/a` | +| Portfolio 1.5.0-beta | `0x0000a37Fd680Ab248119b448545eF72C51Bf7530` | ### Deployments by Chain -| Network | Portfolio 1.3.0-beta | Portfolio v1.4.0-beta | -| -------- | ----------------------------------------------------------------------------------------------------------------------------- | --------------------- | -| Ethereum | [0x82360b9a2076a09ea8abe2b3e11aed89de3a02d1](https://etherscan.io/address/0x82360b9a2076a09ea8abe2b3e11aed89de3a02d1 ) | todo | -| Base | n/a | todo | -| Sepolia | [0x82360b9a2076a09ea8abe2b3e11aed89de3a02d1](https://sepolia.etherscan.io/address/0x82360b9a2076a09ea8abe2b3e11aed89de3a02d1) | todo | +| Network | Portfolio 1.3.0-beta | Portfolio v1.4.0-beta | Portfolio v1.5.0-beta | +| -------- | ----------------------------------------------------------------------------------------------------------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------- | +| Ethereum | [0x82360b9a2076a09ea8abe2b3e11aed89de3a02d1](https://etherscan.io/address/0x82360b9a2076a09ea8abe2b3e11aed89de3a02d1 ) | n/a | [0x0000a37Fd680Ab248119b448545eF72C51Bf7530](https://etherscan.io/address/0x0000a37fd680ab248119b448545ef72c51bf7530) | +| Base | n/a | n/a | n/a | +| Sepolia | [0x82360b9a2076a09ea8abe2b3e11aed89de3a02d1](https://sepolia.etherscan.io/address/0x82360b9a2076a09ea8abe2b3e11aed89de3a02d1) | n/a | n/a | + +| Network | PortfolioRegistry v1.5.0-beta | +| -------- | --------------------------------------------------------------------------------------------------------------------- | +| Ethereum | [0x42776F58b6BC63492E0b7A7a937D1138DF716670](https://etherscan.io/address/0x42776f58b6bc63492e0b7a7a937d1138df716670) | + +| Network | PositionRenderer v1.5.0-beta | +| -------- | --------------------------------------------------------------------------------------------------------------------- | +| Ethereum | [0xdDA01E1d7684Cc35e6a3A5803736D32d012B8C99](https://etherscan.io/address/0xdDA01E1d7684Cc35e6a3A5803736D32d012B8C99) | + + + # Security diff --git a/contracts/Portfolio.sol b/contracts/Portfolio.sol index 13c298f7..850bf0a7 100644 --- a/contracts/Portfolio.sol +++ b/contracts/Portfolio.sol @@ -7,7 +7,6 @@ import "./interfaces/IERC20.sol"; import "./interfaces/IPortfolio.sol"; import "./interfaces/IPortfolioRegistry.sol"; import "./interfaces/IStrategy.sol"; -import "./strategies/NormalStrategy.sol"; import "./PositionRenderer.sol"; /** @@ -35,11 +34,11 @@ contract Portfolio is ERC1155, IPortfolio { mstore(0x00, 0x20) // We load the length of our string (11 bytes, 0x0b in hex) and its - // actual hex value (0x76312e342e302d62657461) using the offset 0x2b. + // actual hex value (0x76312e352e302d62657461) using the offset 0x2b. // Using this particular offset value will right pad the length at // the end of the slot and left pad the string at the beginning of // the next slot, assuring the right ABI format to return a string. - mstore(0x2b, 0x0b76312e342e302d62657461) // "v1.4.0-beta" + mstore(0x2b, 0x0b76312e352e302d62657461) // "v1.5.0-beta" // Return all the 96 bytes (0x60) of data that was loaded into // the memory. @@ -56,9 +55,6 @@ contract Portfolio is ERC1155, IPortfolio { /// @inheritdoc IPortfolioState address public immutable REGISTRY; - /// @inheritdoc IPortfolioState - address public immutable DEFAULT_STRATEGY; - /// @inheritdoc IPortfolioState address public immutable POSITION_RENDERER; @@ -206,7 +202,6 @@ contract Portfolio is ERC1155, IPortfolio { ) ERC1155() { WETH = weth; REGISTRY = registry; - DEFAULT_STRATEGY = address(new NormalStrategy(address(this))); POSITION_RENDERER = positionRenderer; __account__.settled = true; } @@ -729,12 +724,9 @@ contract Portfolio is ERC1155, IPortfolio { // Increment the pool nonce. uint32 poolNonce = ++getPoolNonce[pairNonce]; - // Zero address strtaegy is a magic value to use the default strategy. - strategy = strategy == address(0) ? DEFAULT_STRATEGY : strategy; - // Compute the poolId, which is a packed 64-bit integer. poolId = PoolIdLib.encode( - strategy != DEFAULT_STRATEGY, // Flips the "altered" flag in the upper 4 bits: "0x10..." + false, // Flips the "altered" flag in the upper 4 bits: "0x10..." controller != address(0), // Flips the "controlled" flag in the lower 4 bits: "0x01..." pairNonce, poolNonce diff --git a/contracts/PositionRenderer.sol b/contracts/PositionRenderer.sol index ec0e1674..6cf66048 100644 --- a/contracts/PositionRenderer.sol +++ b/contracts/PositionRenderer.sol @@ -45,7 +45,6 @@ contract PositionRenderer { address controller; address strategy; uint256 spotPriceWad; - bool hasDefaultStrategy; } struct Config { @@ -157,9 +156,7 @@ contract PositionRenderer { priorityFeeBasisPoints: priorityFeeBasisPoints, controller: controller, strategy: strategy, - spotPriceWad: spotPriceWad, - hasDefaultStrategy: strategy - == IPortfolio(msg.sender).DEFAULT_STRATEGY() + spotPriceWad: spotPriceWad }); } @@ -598,9 +595,7 @@ contract PositionRenderer { '

', controlledLabel, " and uses ", - properties.pool.hasDefaultStrategy - ? "the default strategy." - : "a custom strategy.", + "a custom strategy.", "

" ) ); diff --git a/contracts/interfaces/IPortfolio.sol b/contracts/interfaces/IPortfolio.sol index 5a34929b..a776e19d 100644 --- a/contracts/interfaces/IPortfolio.sol +++ b/contracts/interfaces/IPortfolio.sol @@ -216,9 +216,6 @@ interface IPortfolioState { /// @notice Contract for rendering position tokens. function POSITION_RENDERER() external view returns (address); - /// @notice Default strategy contract used in pool creation. - function DEFAULT_STRATEGY() external view returns (address); - /// @notice Proportion of swap fee allocated to the Registry controller. function protocolFee() external view returns (uint256); diff --git a/lib/nugu b/lib/nugu index 71fbe1e7..4c456d07 160000 --- a/lib/nugu +++ b/lib/nugu @@ -1 +1 @@ -Subproject commit 71fbe1e7e1441147886e70425cbb4f6b645ee286 +Subproject commit 4c456d0745a88c7507977574fd5a037d6d5c10e1 diff --git a/package.json b/package.json index b02b842c..3f921d0c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@primitivexyz/portfolio", "license": "AGPL-3.0-only", - "version": "v1.4.0-beta", + "version": "v1.5.0-beta", "description": "Portfolio is an automated market making protocol for implementing custom liquidity distribution strategies at the lowest cost possible. ", "publishConfig": { "access": "public" diff --git a/scripts/Prepare.s.sol b/scripts/Prepare.s.sol index 1920ee32..f0947c0d 100644 --- a/scripts/Prepare.s.sol +++ b/scripts/Prepare.s.sol @@ -35,13 +35,14 @@ import "../contracts/PositionRenderer.sol"; // data that was generated and send the transaction. // 5. Repeat step 4 for all the data generated by this script (3 in total). -address constant MULTISIG_WALLET = 0x8cDb0095ceddb092aD592aCE2971e4f364b5E8eE; +address constant MULTISIG_WALLET = 0xD86872c94484abf03EA8F98ED8E91E9D943781CE; address constant NUGU_ADDRESS = 0xe50ea0e9849cb17829907Acaf764af8F37d4938E; -address constant WETH_ADDRESS = 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6; +address constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; bytes32 constant REGISTRY_SALT = keccak256("REGISTRY0"); bytes32 constant POSITION_RENDERER_SALT = keccak256("POSITION_RENDERER0"); -bytes32 constant PORTFOLIO_SALT = keccak256("PORTFOLIO0"); +bytes32 constant PORTFOLIO_SALT = + bytes32(0x0EB4AB9B29D4F1CFBCDB500D936BCD61BC941EFDBCD3141738F68F972CC15ED4); contract Deploy is Script { bytes internal constant PROXY_BYTECODE = @@ -56,14 +57,13 @@ contract Deploy is Script { abi.encodePacked( type(PortfolioRegistry).creationCode, abi.encode(MULTISIG_WALLET) - ), - 0 + ) ) ); bytes memory positionRendererDeployData = abi.encodeCall( NuguFactory.deploy, - (POSITION_RENDERER_SALT, type(PositionRenderer).creationCode, 0) + (POSITION_RENDERER_SALT, type(PositionRenderer).creationCode) ); address predictedRegistryAddress = @@ -83,8 +83,7 @@ contract Deploy is Script { predictedRegistryAddress, predictedPositionRendererAddress ) - ), - 0 + ) ) ); @@ -96,6 +95,8 @@ contract Deploy is Script { console.log("\nPortfolio deploy data:"); console.logBytes(portfolioDeployData); + console.log("\n Portfolio address:"); + console.log(getDeployed(NUGU_ADDRESS, MULTISIG_WALLET, PORTFOLIO_SALT)); } function getDeployed( diff --git a/test/ETHSP.t.sol b/test/ETHSP.t.sol index 029420a1..cb08c10e 100644 --- a/test/ETHSP.t.sol +++ b/test/ETHSP.t.sol @@ -235,10 +235,12 @@ contract ETHSP is Setup { Configuration memory TRANCHE_A_CONFIG = CONFIG.edit( "asset", abi.encode(TOKEN_0) ).edit("quote", abi.encode(TOKEN_1)); + TRANCHE_A_CONFIG.strategy = normalStrategy(); Configuration memory TRANCHE_B_CONFIG = CONFIG.edit( "asset", abi.encode(TOKEN_2) ).edit("quote", abi.encode(TOKEN_3)); + TRANCHE_B_CONFIG.strategy = normalStrategy(); // Creates the pools with the configs. TRANCHE_A_POOL = TRANCHE_A_CONFIG.activate( address(subject()), NormalConfiguration.validateNormalStrategy diff --git a/test/Setup.sol b/test/Setup.sol index c0a850ab..c325935a 100644 --- a/test/Setup.sol +++ b/test/Setup.sol @@ -34,6 +34,7 @@ struct SubjectsType { address weth; address portfolio; address positionRenderer; + address normalStrategy; } // Interfaces @@ -70,6 +71,9 @@ interface ISetup { /// @dev Returns the position renderer contract used in the subject. function positionRenderer() external view returns (address); + + /// @dev Returns the normal strategy address. + function normalStrategy() external view returns (address); } contract Setup is ISetup, Test, ERC1155TokenReceiver { @@ -115,13 +119,17 @@ contract Setup is ISetup, Test, ERC1155TokenReceiver { ); vm.label(_subjects.portfolio, "portfolio"); + _subjects.normalStrategy = + address(new NormalStrategy(_subjects.portfolio)); + vm.label(_subjects.normalStrategy, "normal-strategy"); + _ghost_state = GhostType({ actor: address(this), subject: _subjects.portfolio, poolId: 0 }); - assertEq(subject().VERSION(), "v1.4.0-beta", "version-not-equal"); + assertEq(subject().VERSION(), "v1.5.0-beta", "version-not-equal"); } // ============= Edit Test Environment ============= // @@ -136,6 +144,7 @@ contract Setup is ISetup, Test, ERC1155TokenReceiver { (address asset, address quote) = deployDefaultTokenPair(); if (config.asset == address(0)) config.asset = asset; if (config.quote == address(0)) config.quote = quote; + config.strategy = normalStrategy(); // Makes it accessible for debugging via `Setup.global_config()`. _global_config = config; @@ -501,5 +510,10 @@ contract Setup is ISetup, Test, ERC1155TokenReceiver { return _subjects.positionRenderer; } + /// @inheritdoc ISetup + function normalStrategy() public view override returns (address) { + return _subjects.normalStrategy; + } + receive() external payable { } } diff --git a/test/TestGas.t.sol b/test/TestGas.t.sol index 77c91c2b..c0bf2e5a 100644 --- a/test/TestGas.t.sol +++ b/test/TestGas.t.sol @@ -148,7 +148,7 @@ contract TestGas is Setup { hundred, // fee 0, // prior fee address(0), // controller - subject().DEFAULT_STRATEGY(), + normalStrategy(), testConfig.strategyArgs ) ); @@ -271,7 +271,7 @@ contract TestGas is Setup { hundred, // fee 0, // prior fee address(0), // controller - address(0), // default strategy + normalStrategy(), testConfig.strategyArgs ) ); @@ -559,7 +559,7 @@ contract TestGas is Setup { uint16(100 + 100 / i), // fee 0, // prior fee controller, - subject().DEFAULT_STRATEGY(), + normalStrategy(), testConfig.strategyArgs ) ); @@ -692,7 +692,7 @@ contract TestGas is Setup { uint16(100), // fee uint16(10), // prior fee address(0), // controller - subject().DEFAULT_STRATEGY(), + normalStrategy(), testConfig.strategyArgs ) ); diff --git a/test/TestPortfolioAllocate.t.sol b/test/TestPortfolioAllocate.t.sol index bd94382b..5782d893 100644 --- a/test/TestPortfolioAllocate.t.sol +++ b/test/TestPortfolioAllocate.t.sol @@ -37,7 +37,7 @@ contract TestPortfolioAllocate is Setup { 100, // fee 0, // prior fee address(0), // controller - subject().DEFAULT_STRATEGY(), + normalStrategy(), testConfig.strategyArgs ) ); @@ -610,7 +610,7 @@ contract TestPortfolioAllocate is Setup { 30, // fee 0, // priority fee address(0), - subject().DEFAULT_STRATEGY(), + normalStrategy(), testConfig.strategyArgs ); diff --git a/test/TestPortfolioCreatePool.t.sol b/test/TestPortfolioCreatePool.t.sol index c6dabe02..5b2a9d48 100644 --- a/test/TestPortfolioCreatePool.t.sol +++ b/test/TestPortfolioCreatePool.t.sol @@ -61,27 +61,6 @@ contract TestPortfolioCreatePool is Setup { ); } - function test_createPool_no_strategy_defaults() public defaultConfig { - Configuration memory testConfig = configureNormalStrategy(); - - testConfig.reserveXPerWad++; // Avoid the reserve error - testConfig.reserveYPerWad++; // Avoid the reserve error - - uint64 poolId = subject().createPool( - 0, - testConfig.reserveXPerWad, - testConfig.reserveYPerWad, - 100, // fee - 0, // prior fee - address(0), // controller - address(0), // strategy - testConfig.strategyArgs - ); - - (,,,,,,, address strategy) = subject().pools(poolId); - assertEq(strategy, subject().DEFAULT_STRATEGY()); - } - function test_revert_createPool_invalid_priority_fee() public { bytes[] memory data = new bytes[](1); @@ -101,7 +80,7 @@ contract TestPortfolioCreatePool is Setup { 1, // fee testConfig.priorityFeeBasisPoints.safeCastTo16(), // prior fee address(this), // controller - subject().DEFAULT_STRATEGY(), + normalStrategy(), testConfig.strategyArgs ) ); @@ -184,7 +163,7 @@ contract TestPortfolioCreatePool is Setup { 100, 1, address(0), - subject().DEFAULT_STRATEGY(), + normalStrategy(), abi.encode( PortfolioConfig( 100, diff --git a/test/TestPositionRendererUri.t.sol b/test/TestPositionRendererUri.t.sol index cf3346d7..b79cac18 100644 --- a/test/TestPositionRendererUri.t.sol +++ b/test/TestPositionRendererUri.t.sol @@ -31,7 +31,7 @@ contract TestPositionRendererUri is Setup { } (bytes memory strategyData, uint256 initialX, uint256 initialY) = - INormalStrategy(subject().DEFAULT_STRATEGY()).getStrategyData( + INormalStrategy(normalStrategy()).getStrategyData( ctx.strikePriceWad, 1_00, // volatilityBasisPoints ctx.durationSeconds, @@ -83,7 +83,7 @@ contract TestPositionRendererUri is Setup { isPerpetual: false, priceWad: AssemblyLib.scaleToWad(1666 * 10 ** 6, 6), controller: address(0), - strategy: address(0), + strategy: normalStrategy(), prioritySwapFee: 0 }); @@ -102,7 +102,7 @@ contract TestPositionRendererUri is Setup { isPerpetual: false, priceWad: AssemblyLib.scaleToWad(1666 * 10 ** 6, 6), controller: address(this), - strategy: address(0), + strategy: normalStrategy(), prioritySwapFee: 200 }); @@ -121,7 +121,7 @@ contract TestPositionRendererUri is Setup { isPerpetual: true, priceWad: AssemblyLib.scaleToWad(1666 * 10 ** 6, 6), controller: address(0), - strategy: address(0), + strategy: normalStrategy(), prioritySwapFee: 0 }); @@ -178,7 +178,7 @@ contract TestPositionRendererUri is Setup { isPerpetual: false, priceWad: AssemblyLib.scaleToWad(1666 * 10 ** 6, 6), controller: address(0), - strategy: address(0), + strategy: normalStrategy(), prioritySwapFee: 0 });