Skip to content

Commit

Permalink
Composable stable pool versioning (#2034)
Browse files Browse the repository at this point in the history
* WIP: version for ComposableStablePool.

* Fix stack too deep error and adjust tests.

* ComposableStablePoolFactory test.

* Remove unused var.

* Add factory version / pool version.

* Fix benchmarks.

* Remove IVersionProvider.
  • Loading branch information
Juan Ignacio Ubeira committed Nov 24, 2022
1 parent d85d381 commit 3f42407
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 10 deletions.
28 changes: 28 additions & 0 deletions pkg/interfaces/contracts/pool-utils/IPoolVersion.sol
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

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);
}
25 changes: 25 additions & 0 deletions pkg/interfaces/contracts/pool-utils/IVersion.sol
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

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);
}
11 changes: 10 additions & 1 deletion pkg/pool-stable/contracts/ComposableStablePool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -50,6 +51,7 @@ import "./StableMath.sol";
*/
contract ComposableStablePool is
IRateProvider,
IVersion,
BaseGeneralPool,
StablePoolAmplification,
ComposableStablePoolRates,
Expand All @@ -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;
Expand All @@ -79,6 +83,7 @@ contract ComposableStablePool is
uint256 pauseWindowDuration;
uint256 bufferPeriodDuration;
address owner;
string version;
}

constructor(NewPoolParams memory params)
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
30 changes: 24 additions & 6 deletions pkg/pool-stable/contracts/ComposableStablePoolFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,35 @@
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";
import "@balancer-labs/v2-pool-utils/contracts/factories/FactoryWidePauseWindow.sol";

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;
}

/**
Expand Down Expand Up @@ -61,7 +78,8 @@ contract ComposableStablePoolFactory is BasePoolFactory, FactoryWidePauseWindow
swapFeePercentage: swapFeePercentage,
pauseWindowDuration: pauseWindowDuration,
bufferPeriodDuration: bufferPeriodDuration,
owner: owner
owner: owner,
version: getPoolVersion()
})
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ abstract contract ComposableStablePoolProtocolFees is
// To convert to a percentage of pool ownership, multiply by the rate,
// then normalize against the final invariant
uint256 protocolOwnershipPercentage = Math.divDown(
Math.mul(invariantDeltaFromFees, getProtocolFeePercentageCache(ProtocolFeeType.SWAP)),
Math.mul(invariantDeltaFromFees, getProtocolFeePercentageCache(ProtocolFeeType.SWAP)),
postJoinExitInvariant
);

Expand Down
27 changes: 26 additions & 1 deletion pkg/pool-stable/test/ComposableStablePoolFactory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,27 @@ describe('ComposableStablePoolFactory', function () {

let createTime: BigNumber;
let protocolFeeExemptFlags: boolean[];
let factoryVersion: string, poolVersion: string;

before('setup signers', async () => {
[, owner] = await ethers.getSigners();
});

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 });
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion pvt/benchmarks/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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] });
}
Expand Down
2 changes: 2 additions & 0 deletions pvt/helpers/src/models/pools/stable/StablePoolDeployer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export default {
bufferPeriodDuration,
amplificationParameter,
from,
version,
} = params;

const owner = TypesConverter.toAddress(params.owner);
Expand All @@ -56,6 +57,7 @@ export default {
pauseWindowDuration,
bufferPeriodDuration,
owner,
version: version,
},
],
from,
Expand Down
2 changes: 2 additions & 0 deletions pvt/helpers/src/models/pools/stable/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export type RawStablePoolDeployment = {
from?: SignerWithAddress;
vault?: Vault;
mockedVault?: boolean;
version?: string;
};

export type StablePoolDeployment = {
Expand All @@ -134,6 +135,7 @@ export type StablePoolDeployment = {
rateProviders: Account[];
tokenRateCacheDurations: BigNumberish[];
exemptFromYieldProtocolFeeFlags: boolean[];
version: string;
pauseWindowDuration?: BigNumberish;
bufferPeriodDuration?: BigNumberish;
owner?: SignerWithAddress;
Expand Down
3 changes: 3 additions & 0 deletions pvt/helpers/src/models/types/TypesConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ export default {
swapFeePercentage,
pauseWindowDuration,
bufferPeriodDuration,
version,
} = params;

if (!tokens) tokens = new TokenList();
Expand All @@ -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,
Expand All @@ -158,6 +160,7 @@ export default {
pauseWindowDuration,
bufferPeriodDuration,
owner: params.owner,
version,
};
},

Expand Down

0 comments on commit 3f42407

Please sign in to comment.