diff --git a/pkg/interfaces/contracts/pool-utils/IPoolVersion.sol b/pkg/interfaces/contracts/pool-utils/IPoolVersion.sol
new file mode 100644
index 0000000000..56d3e4cf88
--- /dev/null
+++ b/pkg/interfaces/contracts/pool-utils/IPoolVersion.sol
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+pragma solidity >=0.7.0 <0.9.0;
+
+/**
+ * @notice Simple interface to retrieve the version of pools deployed by a pool factory.
+ */
+interface IPoolVersion {
+ /**
+ * @dev Returns a JSON representation of the deployed pool version containing name, version number and task ID.
+ *
+ * This is typically only useful in complex Pool deployment schemes, where multiple subsystems need to know about
+ * each other. Note that this value will only be updated at factory creation time.
+ */
+ function getPoolVersion() external view returns (string memory);
+}
diff --git a/pkg/interfaces/contracts/pool-utils/IVersion.sol b/pkg/interfaces/contracts/pool-utils/IVersion.sol
new file mode 100644
index 0000000000..9079808ee2
--- /dev/null
+++ b/pkg/interfaces/contracts/pool-utils/IVersion.sol
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+pragma solidity >=0.7.0 <0.9.0;
+
+/**
+ * @notice Simple interface to retrieve the version of a deployed contract.
+ */
+interface IVersion {
+ /**
+ * @dev Returns a JSON representation of the contract version containing name, version number and task ID.
+ */
+ function version() external view returns (string memory);
+}
diff --git a/pkg/pool-stable/contracts/ComposableStablePool.sol b/pkg/pool-stable/contracts/ComposableStablePool.sol
index dbb6a2aee3..814e61d245 100644
--- a/pkg/pool-stable/contracts/ComposableStablePool.sol
+++ b/pkg/pool-stable/contracts/ComposableStablePool.sol
@@ -19,6 +19,7 @@ import "@balancer-labs/v2-interfaces/contracts/pool-stable/StablePoolUserData.so
import "@balancer-labs/v2-interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol";
import "@balancer-labs/v2-interfaces/contracts/standalone-utils/IProtocolFeePercentagesProvider.sol";
import "@balancer-labs/v2-interfaces/contracts/pool-utils/IRateProvider.sol";
+import "@balancer-labs/v2-interfaces/contracts/pool-utils/IVersion.sol";
import "@balancer-labs/v2-solidity-utils/contracts/math/FixedPoint.sol";
import "@balancer-labs/v2-solidity-utils/contracts/math/Math.sol";
@@ -50,6 +51,7 @@ import "./StableMath.sol";
*/
contract ComposableStablePool is
IRateProvider,
+ IVersion,
BaseGeneralPool,
StablePoolAmplification,
ComposableStablePoolRates,
@@ -64,6 +66,8 @@ contract ComposableStablePool is
// We are preminting half of that value (rounded up).
uint256 private constant _PREMINTED_TOKEN_BALANCE = 2**(111);
+ string private _version;
+
// The constructor arguments are received in a struct to work around stack-too-deep issues
struct NewPoolParams {
IVault vault;
@@ -79,6 +83,7 @@ contract ComposableStablePool is
uint256 pauseWindowDuration;
uint256 bufferPeriodDuration;
address owner;
+ string version;
}
constructor(NewPoolParams memory params)
@@ -99,7 +104,7 @@ contract ComposableStablePool is
ComposableStablePoolRates(_extractRatesParams(params))
ProtocolFeeCache(params.protocolFeeProvider, ProtocolFeeCache.DELEGATE_PROTOCOL_SWAP_FEES_SENTINEL)
{
- // solhint-disable-previous-line no-empty-blocks
+ _version = params.version;
}
// Translate parameters to avoid stack-too-deep issues in the constructor
@@ -130,6 +135,10 @@ contract ComposableStablePool is
});
}
+ function version() external view override returns (string memory) {
+ return _version;
+ }
+
/**
* @notice Return the minimum BPT balance, required to avoid minimum token balances.
* @dev This amount is minted and immediately burned on pool initialization, so that the total supply
diff --git a/pkg/pool-stable/contracts/ComposableStablePoolFactory.sol b/pkg/pool-stable/contracts/ComposableStablePoolFactory.sol
index 9002e9f5ab..35f711dfc9 100644
--- a/pkg/pool-stable/contracts/ComposableStablePoolFactory.sol
+++ b/pkg/pool-stable/contracts/ComposableStablePoolFactory.sol
@@ -15,6 +15,8 @@
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
+import "@balancer-labs/v2-interfaces/contracts/pool-utils/IPoolVersion.sol";
+import "@balancer-labs/v2-interfaces/contracts/pool-utils/IVersion.sol";
import "@balancer-labs/v2-interfaces/contracts/vault/IVault.sol";
import "@balancer-labs/v2-pool-utils/contracts/factories/BasePoolFactory.sol";
@@ -22,11 +24,26 @@ import "@balancer-labs/v2-pool-utils/contracts/factories/FactoryWidePauseWindow.
import "./ComposableStablePool.sol";
-contract ComposableStablePoolFactory is BasePoolFactory, FactoryWidePauseWindow {
- constructor(IVault vault, IProtocolFeePercentagesProvider protocolFeeProvider)
- BasePoolFactory(vault, protocolFeeProvider, type(ComposableStablePool).creationCode)
- {
- // solhint-disable-previous-line no-empty-blocks
+contract ComposableStablePoolFactory is IVersion, IPoolVersion, BasePoolFactory, FactoryWidePauseWindow {
+ string private _version;
+ string private _poolVersion;
+
+ constructor(
+ IVault vault,
+ IProtocolFeePercentagesProvider protocolFeeProvider,
+ string memory factoryVersion,
+ string memory poolVersion
+ ) BasePoolFactory(vault, protocolFeeProvider, type(ComposableStablePool).creationCode) {
+ _version = factoryVersion;
+ _poolVersion = poolVersion;
+ }
+
+ function version() external view override returns (string memory) {
+ return _version;
+ }
+
+ function getPoolVersion() public view override returns (string memory) {
+ return _poolVersion;
}
/**
@@ -61,7 +78,8 @@ contract ComposableStablePoolFactory is BasePoolFactory, FactoryWidePauseWindow
swapFeePercentage: swapFeePercentage,
pauseWindowDuration: pauseWindowDuration,
bufferPeriodDuration: bufferPeriodDuration,
- owner: owner
+ owner: owner,
+ version: getPoolVersion()
})
)
)
diff --git a/pkg/pool-stable/test/ComposableStablePoolFactory.test.ts b/pkg/pool-stable/test/ComposableStablePoolFactory.test.ts
index 110fdc8e90..e7a4fbad8c 100644
--- a/pkg/pool-stable/test/ComposableStablePoolFactory.test.ts
+++ b/pkg/pool-stable/test/ComposableStablePoolFactory.test.ts
@@ -27,6 +27,7 @@ describe('ComposableStablePoolFactory', function () {
let createTime: BigNumber;
let protocolFeeExemptFlags: boolean[];
+ let factoryVersion: string, poolVersion: string;
before('setup signers', async () => {
[, owner] = await ethers.getSigners();
@@ -34,7 +35,19 @@ describe('ComposableStablePoolFactory', function () {
sharedBeforeEach('deploy factory & tokens', async () => {
vault = await Vault.create();
- factory = await deploy('ComposableStablePoolFactory', { args: [vault.address, vault.getFeesProvider().address] });
+ factoryVersion = JSON.stringify({
+ name: 'ComposableStablePoolFactory',
+ version: '1',
+ deployment: 'test-deployment',
+ });
+ poolVersion = JSON.stringify({
+ name: 'ComposableStablePool',
+ version: '0',
+ deployment: 'test-deployment',
+ });
+ factory = await deploy('ComposableStablePoolFactory', {
+ args: [vault.address, vault.getFeesProvider().address, factoryVersion, poolVersion],
+ });
createTime = await currentTimestamp();
tokens = await TokenList.create(['baDAI', 'baUSDC', 'baUSDT'], { sorted: true });
@@ -70,10 +83,22 @@ describe('ComposableStablePoolFactory', function () {
pool = await createPool();
});
+ it('sets the factory version', async () => {
+ expect(await factory.version()).to.equal(factoryVersion);
+ });
+
it('sets the vault', async () => {
expect(await pool.getVault()).to.equal(vault.address);
});
+ it('sets the pool version', async () => {
+ expect(await pool.version()).to.equal(poolVersion);
+ });
+
+ it('gets pool version from the factory', async () => {
+ expect(await factory.getPoolVersion()).to.equal(poolVersion);
+ });
+
it('registers tokens in the vault', async () => {
const poolId = await pool.getPoolId();
const poolTokens = await vault.getPoolTokens(poolId);
diff --git a/pvt/benchmarks/misc.ts b/pvt/benchmarks/misc.ts
index 5ac1b17b0a..462e7c0c4c 100644
--- a/pvt/benchmarks/misc.ts
+++ b/pvt/benchmarks/misc.ts
@@ -207,7 +207,7 @@ async function deployPoolFromFactory(
});
factory = await deploy(`${fullName}Factory`, { args: [baseFactory.address] });
} else if (poolName == 'ComposableStablePool') {
- factory = await deploy(`${fullName}Factory`, { args: [vault.address, vault.getFeesProvider().address] });
+ factory = await deploy(`${fullName}Factory`, { args: [vault.address, vault.getFeesProvider().address, '', ''] });
} else {
factory = await deploy(`${fullName}Factory`, { args: [vault.address, vault.getFeesProvider().address] });
}
diff --git a/pvt/helpers/src/models/pools/stable/StablePoolDeployer.ts b/pvt/helpers/src/models/pools/stable/StablePoolDeployer.ts
index b4a98def62..044f53326a 100644
--- a/pvt/helpers/src/models/pools/stable/StablePoolDeployer.ts
+++ b/pvt/helpers/src/models/pools/stable/StablePoolDeployer.ts
@@ -36,6 +36,7 @@ export default {
bufferPeriodDuration,
amplificationParameter,
from,
+ version,
} = params;
const owner = TypesConverter.toAddress(params.owner);
@@ -56,6 +57,7 @@ export default {
pauseWindowDuration,
bufferPeriodDuration,
owner,
+ version: version,
},
],
from,
diff --git a/pvt/helpers/src/models/pools/stable/types.ts b/pvt/helpers/src/models/pools/stable/types.ts
index 45793b1eb0..83d4cb1ad6 100644
--- a/pvt/helpers/src/models/pools/stable/types.ts
+++ b/pvt/helpers/src/models/pools/stable/types.ts
@@ -125,6 +125,7 @@ export type RawStablePoolDeployment = {
from?: SignerWithAddress;
vault?: Vault;
mockedVault?: boolean;
+ version?: string;
};
export type StablePoolDeployment = {
@@ -134,6 +135,7 @@ export type StablePoolDeployment = {
rateProviders: Account[];
tokenRateCacheDurations: BigNumberish[];
exemptFromYieldProtocolFeeFlags: boolean[];
+ version: string;
pauseWindowDuration?: BigNumberish;
bufferPeriodDuration?: BigNumberish;
owner?: SignerWithAddress;
diff --git a/pvt/helpers/src/models/types/TypesConverter.ts b/pvt/helpers/src/models/types/TypesConverter.ts
index 08676f4d5d..1bd679125a 100644
--- a/pvt/helpers/src/models/types/TypesConverter.ts
+++ b/pvt/helpers/src/models/types/TypesConverter.ts
@@ -137,6 +137,7 @@ export default {
swapFeePercentage,
pauseWindowDuration,
bufferPeriodDuration,
+ version,
} = params;
if (!tokens) tokens = new TokenList();
@@ -147,6 +148,7 @@ export default {
if (!pauseWindowDuration) pauseWindowDuration = 3 * MONTH;
if (!bufferPeriodDuration) bufferPeriodDuration = MONTH;
if (!exemptFromYieldProtocolFeeFlags) exemptFromYieldProtocolFeeFlags = Array(tokens.length).fill(false);
+ if (!version) version = 'test';
return {
tokens,
@@ -158,6 +160,7 @@ export default {
pauseWindowDuration,
bufferPeriodDuration,
owner: params.owner,
+ version,
};
},