diff --git a/pkg/pool-weighted/contracts/managed/ManagedPool.sol b/pkg/pool-weighted/contracts/managed/ManagedPool.sol index 29647b7dee..fddf3b720b 100644 --- a/pkg/pool-weighted/contracts/managed/ManagedPool.sol +++ b/pkg/pool-weighted/contracts/managed/ManagedPool.sol @@ -15,6 +15,7 @@ pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; +import "@balancer-labs/v2-interfaces/contracts/pool-utils/IVersion.sol"; import "@balancer-labs/v2-interfaces/contracts/pool-weighted/IExternalWeightedMath.sol"; import "@balancer-labs/v2-interfaces/contracts/pool-weighted/WeightedPoolUserData.sol"; @@ -43,7 +44,7 @@ import "./ManagedPoolSettings.sol"; * rebalancing through token changes, gradual weight or fee updates, fine-grained control of protocol and * management fees, allowlisting of LPs, and more. */ -contract ManagedPool is ManagedPoolSettings { +contract ManagedPool is IVersion, ManagedPoolSettings { // ManagedPool weights and swap fees can change over time: these periods are expected to be long enough (e.g. days) // that any timestamp manipulation would achieve very little. // solhint-disable not-rely-on-time @@ -57,6 +58,7 @@ contract ManagedPool is ManagedPoolSettings { // conceivable real liquidity - to allow for minting new BPT as a result of regular joins. uint256 private constant _PREMINTED_TOKEN_BALANCE = 2**(111); IExternalWeightedMath private immutable _weightedMath; + string private _version; struct ManagedPoolParams { string name; @@ -70,6 +72,7 @@ contract ManagedPool is ManagedPoolSettings { IExternalWeightedMath weightedMath; uint256 pauseWindowDuration; uint256 bufferPeriodDuration; + string version; } constructor( @@ -95,6 +98,11 @@ contract ManagedPool is ManagedPoolSettings { ManagedPoolSettings(settingsParams, configParams.protocolFeeProvider) { _weightedMath = configParams.weightedMath; + _version = configParams.version; + } + + function version() external view override returns (string memory) { + return _version; } function _getWeightedMath() internal view returns (IExternalWeightedMath) { diff --git a/pkg/pool-weighted/contracts/managed/ManagedPoolFactory.sol b/pkg/pool-weighted/contracts/managed/ManagedPoolFactory.sol index e8eb893249..016a579e40 100644 --- a/pkg/pool-weighted/contracts/managed/ManagedPoolFactory.sol +++ b/pkg/pool-weighted/contracts/managed/ManagedPoolFactory.sol @@ -15,9 +15,12 @@ pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; -import "@balancer-labs/v2-pool-utils/contracts/factories/BasePoolFactory.sol"; +import "@balancer-labs/v2-interfaces/contracts/pool-utils/IFactoryCreatedPoolVersion.sol"; import "@balancer-labs/v2-interfaces/contracts/standalone-utils/IProtocolFeePercentagesProvider.sol"; + +import "@balancer-labs/v2-pool-utils/contracts/factories/BasePoolFactory.sol"; import "@balancer-labs/v2-pool-utils/contracts/factories/FactoryWidePauseWindow.sol"; +import "@balancer-labs/v2-pool-utils/contracts/Version.sol"; import "./ManagedPool.sol"; import "../ExternalWeightedMath.sol"; @@ -34,13 +37,22 @@ import "../ExternalWeightedMath.sol"; * In this design, other client-specific factories will deploy a contract, then call this factory * to deploy the pool, passing in that contract address as the owner. */ -contract ManagedPoolFactory is BasePoolFactory, FactoryWidePauseWindow { +contract ManagedPoolFactory is IFactoryCreatedPoolVersion, Version, BasePoolFactory, FactoryWidePauseWindow { IExternalWeightedMath private immutable _weightedMath; + string private _poolVersion; - constructor(IVault vault, IProtocolFeePercentagesProvider protocolFeeProvider) - BasePoolFactory(vault, protocolFeeProvider, type(ManagedPool).creationCode) - { + constructor( + IVault vault, + IProtocolFeePercentagesProvider protocolFeeProvider, + string memory factoryVersion, + string memory poolVersion + ) BasePoolFactory(vault, protocolFeeProvider, type(ManagedPool).creationCode) Version(factoryVersion) { _weightedMath = new ExternalWeightedMath(); + _poolVersion = poolVersion; + } + + function getPoolVersion() public view override returns (string memory) { + return _poolVersion; } function getWeightedMath() external view returns (IExternalWeightedMath) { @@ -62,7 +74,8 @@ contract ManagedPoolFactory is BasePoolFactory, FactoryWidePauseWindow { protocolFeeProvider: getProtocolFeePercentagesProvider(), weightedMath: _weightedMath, pauseWindowDuration: pauseWindowDuration, - bufferPeriodDuration: bufferPeriodDuration + bufferPeriodDuration: bufferPeriodDuration, + version: getPoolVersion() }); return _create(abi.encode(params, configParams, settingsParams, owner)); diff --git a/pkg/pool-weighted/contracts/test/MockManagedPoolSettings.sol b/pkg/pool-weighted/contracts/test/MockManagedPoolSettings.sol index a9a9135ec5..645c764de7 100644 --- a/pkg/pool-weighted/contracts/test/MockManagedPoolSettings.sol +++ b/pkg/pool-weighted/contracts/test/MockManagedPoolSettings.sol @@ -28,7 +28,7 @@ contract MockManagedPoolSettings is ManagedPoolSettings { IVault vault, IProtocolFeePercentagesProvider protocolFeeProvider, ExternalWeightedMath weightedMath, - address[] memory asssetManagers, + address[] memory assetManagers, address owner ) NewBasePool( @@ -37,7 +37,7 @@ contract MockManagedPoolSettings is ManagedPoolSettings { vault, IVault.PoolSpecialization.MINIMAL_SWAP_INFO, settingsParams.tokens, - asssetManagers + assetManagers ), "MockManagedPoolName", "MockManagedPoolSymbol", diff --git a/pkg/pool-weighted/test/ControlledManagedPoolFactory.test.ts b/pkg/pool-weighted/test/ControlledManagedPoolFactory.test.ts index 4670b97b17..b9c4a63614 100644 --- a/pkg/pool-weighted/test/ControlledManagedPoolFactory.test.ts +++ b/pkg/pool-weighted/test/ControlledManagedPoolFactory.test.ts @@ -53,7 +53,7 @@ describe('ControlledManagedPoolFactory', function () { const circuitBreakerLib = await deploy('CircuitBreakerLib'); const addRemoveTokenLib = await deploy('ManagedPoolAddRemoveTokenLib'); factory = await deploy('ManagedPoolFactory', { - args: [vault.address, vault.getFeesProvider().address], + args: [vault.address, vault.getFeesProvider().address, 'factoryVersion', 'poolVersion'], libraries: { CircuitBreakerLib: circuitBreakerLib.address, ManagedPoolAddRemoveTokenLib: addRemoveTokenLib.address, diff --git a/pkg/pool-weighted/test/ManagedPool.test.ts b/pkg/pool-weighted/test/ManagedPool.test.ts index 8da8b23ef0..f37a3225a4 100644 --- a/pkg/pool-weighted/test/ManagedPool.test.ts +++ b/pkg/pool-weighted/test/ManagedPool.test.ts @@ -38,6 +38,12 @@ describe('ManagedPool', function () { let pool: WeightedPool; let vault: Vault; + const poolVersion = JSON.stringify({ + name: 'ManagedPool', + version: '0', + deployment: 'test-deployment', + }); + before('setup signers', async () => { [, admin, owner, other] = await ethers.getSigners(); }); @@ -70,6 +76,7 @@ describe('ManagedPool', function () { owner: owner.address, aumFeeId: ProtocolFee.AUM, poolType: WeightedPoolType.MOCK_MANAGED_POOL, + poolVersion, ...overrides, }; return WeightedPool.create(params); @@ -121,6 +128,10 @@ describe('ManagedPool', function () { expect(assetManager).to.be.eq(ZERO_ADDRESS); }); }); + + it('returns the expected pool version', async () => { + expect(await pool.version()).to.be.eq(poolVersion); + }); }); }); diff --git a/pkg/pool-weighted/test/ManagedPoolFactory.test.ts b/pkg/pool-weighted/test/ManagedPoolFactory.test.ts index 3da9cb0fc3..5e1a5aa81e 100644 --- a/pkg/pool-weighted/test/ManagedPoolFactory.test.ts +++ b/pkg/pool-weighted/test/ManagedPoolFactory.test.ts @@ -23,6 +23,17 @@ describe('ManagedPoolFactory', function () { let manager: SignerWithAddress; let assetManager: SignerWithAddress; + const factoryVersion = JSON.stringify({ + name: 'ManagedPoolFactory', + version: '4', + deployment: 'test-deployment', + }); + const poolVersion = JSON.stringify({ + name: 'ManagedPool', + version: '0', + deployment: 'test-deployment', + }); + const NAME = 'Balancer Pool Token'; const SYMBOL = 'BPT'; const POOL_SWAP_FEE_PERCENTAGE = fp(0.01); @@ -44,7 +55,7 @@ describe('ManagedPoolFactory', function () { const addRemoveTokenLib = await deploy('ManagedPoolAddRemoveTokenLib'); const circuitBreakerLib = await deploy('CircuitBreakerLib'); factory = await deploy('ManagedPoolFactory', { - args: [vault.address, vault.getFeesProvider().address], + args: [vault.address, vault.getFeesProvider().address, factoryVersion, poolVersion], libraries: { CircuitBreakerLib: circuitBreakerLib.address, ManagedPoolAddRemoveTokenLib: addRemoveTokenLib.address, @@ -142,6 +153,18 @@ describe('ManagedPoolFactory', function () { it('sets the decimals', async () => { expect(await pool.decimals()).to.equal(18); }); + + it('sets factory version', async () => { + expect(await factory.version()).to.be.eq(factoryVersion); + }); + + it('sets pool version', async () => { + expect(await factory.getPoolVersion()).to.be.eq(poolVersion); + }); + + it('sets pool version in the pool', async () => { + expect(await pool.version()).to.be.eq(poolVersion); + }); }); describe('temporarily pausable', () => { diff --git a/pkg/pool-weighted/test/managed/ownerOnlyActions.test.ts b/pkg/pool-weighted/test/managed/ownerOnlyActions.test.ts index 9ff240a2bb..a7977b522a 100644 --- a/pkg/pool-weighted/test/managed/ownerOnlyActions.test.ts +++ b/pkg/pool-weighted/test/managed/ownerOnlyActions.test.ts @@ -28,6 +28,7 @@ describe('ManagedPool owner only actions', () => { weightedMath: math.address, pauseWindowDuration: 0, bufferPeriodDuration: 0, + version: '', }, { tokens: tokens.addresses, diff --git a/pvt/benchmarks/misc.ts b/pvt/benchmarks/misc.ts index 98224149d0..33860d4134 100644 --- a/pvt/benchmarks/misc.ts +++ b/pvt/benchmarks/misc.ts @@ -211,7 +211,7 @@ async function deployPoolFromFactory( const addRemoveTokenLib = await deploy('v2-pool-weighted/ManagedPoolAddRemoveTokenLib'); const circuitBreakerLib = await deploy('v2-pool-weighted/CircuitBreakerLib'); const baseFactory = await deploy('v2-pool-weighted/ManagedPoolFactory', { - args: [vault.address, vault.getFeesProvider().address], + args: [vault.address, vault.getFeesProvider().address, 'factoryVersion', 'poolVersion'], libraries: { CircuitBreakerLib: circuitBreakerLib.address, ManagedPoolAddRemoveTokenLib: addRemoveTokenLib.address, diff --git a/pvt/helpers/src/models/pools/weighted/WeightedPool.ts b/pvt/helpers/src/models/pools/weighted/WeightedPool.ts index a2d32047b5..90d13fab88 100644 --- a/pvt/helpers/src/models/pools/weighted/WeightedPool.ts +++ b/pvt/helpers/src/models/pools/weighted/WeightedPool.ts @@ -62,6 +62,7 @@ export default class WeightedPool extends BasePool { mustAllowlistLPs: boolean; managementAumFeePercentage: BigNumberish; aumProtocolFeesCollector: string; + poolVersion: string; static async create(params: RawWeightedPoolDeployment = {}): Promise { return WeightedPoolDeployer.deploy(params); @@ -81,6 +82,7 @@ export default class WeightedPool extends BasePool { mustAllowlistLPs: boolean, managementAumFeePercentage: BigNumberish, aumProtocolFeesCollector: string, + poolVersion: string, owner?: SignerWithAddress ) { super(instance, poolId, vault, tokens, swapFeePercentage, owner); @@ -93,6 +95,7 @@ export default class WeightedPool extends BasePool { this.mustAllowlistLPs = mustAllowlistLPs; this.managementAumFeePercentage = managementAumFeePercentage; this.aumProtocolFeesCollector = aumProtocolFeesCollector; + this.poolVersion = poolVersion; } get maxWeight(): BigNumberish { @@ -148,6 +151,10 @@ export default class WeightedPool extends BasePool { return this.instance.getNormalizedWeights(); } + async version(): Promise { + return this.instance.version(); + } + async estimateSpotPrice(currentBalances?: BigNumberish[]): Promise { if (!currentBalances) currentBalances = await this.getBalances(); diff --git a/pvt/helpers/src/models/pools/weighted/WeightedPoolDeployer.ts b/pvt/helpers/src/models/pools/weighted/WeightedPoolDeployer.ts index 6416302a6c..d0fecfed9d 100644 --- a/pvt/helpers/src/models/pools/weighted/WeightedPoolDeployer.ts +++ b/pvt/helpers/src/models/pools/weighted/WeightedPoolDeployer.ts @@ -40,6 +40,7 @@ export default { mustAllowlistLPs, managementAumFeePercentage, aumProtocolFeesCollector, + poolVersion, } = deployment; return new WeightedPool( @@ -55,7 +56,8 @@ export default { swapEnabledOnStart, mustAllowlistLPs, managementAumFeePercentage, - aumProtocolFeesCollector + aumProtocolFeesCollector, + poolVersion ); }, @@ -76,6 +78,7 @@ export default { owner, from, aumFeeId, + poolVersion, } = params; let result: Promise; @@ -116,6 +119,7 @@ export default { weightedMath: math.address, pauseWindowDuration, bufferPeriodDuration, + version: poolVersion, }, { tokens: tokens.addresses, @@ -155,6 +159,7 @@ export default { weightedMath: math.address, pauseWindowDuration, bufferPeriodDuration, + version: poolVersion, }, { tokens: tokens.addresses, @@ -248,6 +253,8 @@ export default { owner, from, aumFeeId, + factoryVersion, + poolVersion, } = params; let result: Promise; @@ -276,7 +283,7 @@ export default { const addRemoveTokenLib = await deploy('v2-pool-weighted/ManagedPoolAddRemoveTokenLib'); const circuitBreakerLib = await deploy('v2-pool-weighted/CircuitBreakerLib'); const factory = await deploy('v2-pool-weighted/ManagedPoolFactory', { - args: [vault.address, vault.getFeesProvider().address], + args: [vault.address, vault.getFeesProvider().address, factoryVersion, poolVersion], from, libraries: { CircuitBreakerLib: circuitBreakerLib.address, diff --git a/pvt/helpers/src/models/pools/weighted/types.ts b/pvt/helpers/src/models/pools/weighted/types.ts index 9d07f1a475..bfcaaa09e5 100644 --- a/pvt/helpers/src/models/pools/weighted/types.ts +++ b/pvt/helpers/src/models/pools/weighted/types.ts @@ -36,6 +36,8 @@ export type RawWeightedPoolDeployment = { poolType?: WeightedPoolType; aumFeeId?: BigNumberish; mockContractName?: string; + factoryVersion?: string; + poolVersion?: string; }; export type WeightedPoolDeployment = { @@ -51,6 +53,8 @@ export type WeightedPoolDeployment = { mustAllowlistLPs: boolean; managementAumFeePercentage: BigNumberish; aumProtocolFeesCollector: string; + factoryVersion: string; + poolVersion: string; aumFeeId?: BigNumberish; owner?: string; admin?: SignerWithAddress; diff --git a/pvt/helpers/src/models/types/TypesConverter.ts b/pvt/helpers/src/models/types/TypesConverter.ts index f28faf7d6b..1891f1fa91 100644 --- a/pvt/helpers/src/models/types/TypesConverter.ts +++ b/pvt/helpers/src/models/types/TypesConverter.ts @@ -68,6 +68,8 @@ export default { aumProtocolFeesCollector, poolType, aumFeeId, + factoryVersion, + poolVersion, } = params; if (!params.owner) params.owner = ZERO_ADDRESS; if (!tokens) tokens = new TokenList(); @@ -84,6 +86,8 @@ export default { if (undefined == swapEnabledOnStart) swapEnabledOnStart = true; if (undefined == mustAllowlistLPs) mustAllowlistLPs = false; if (undefined == managementAumFeePercentage) managementAumFeePercentage = FP_ZERO; + if (undefined == factoryVersion) factoryVersion = 'default factory version'; + if (undefined == poolVersion) poolVersion = 'default pool version'; return { tokens, weights, @@ -100,7 +104,8 @@ export default { from: params.from, poolType, aumFeeId, - mockContractName: params.mockContractName, + factoryVersion, + poolVersion, }; },