[Proposal] Boosted Pools: Authorize Balancer Labs to emergency pause

The Boosted Pools factories were deployed to mainnet last week, and the Balancer app now supports them too.

The authorizations to be ratified by this proposal would enable a multisig controlled by Balancer Labs team members to control the Boosted Pools emergency pause mechanism during its first 3 months.

Motivation

The Boosted Pools smart contracts ( AaveLinearPool and StablePhantomPool ) have an emergency pause period which is hardcoded at 3 months from the time the factories were deployed. During the pause period, the Balancer Governance Multisig has the power to gracefully pause the system in case vulnerabilities or issues arise. Funds can always be withdrawn by users , even during an emergency pause, and the pause is only to be invoked in situations where user funds may be at risk.

Since gathering 6/11 governance multisig signers during an emergency may not be feasible or expedient, we propose also authorizing a Balancer Labs controlled multisig to pause the system . The BLabs Multisig will be controlled by a handful of team members at Balancer Labs. Note that after the 3-month pause period ends, neither the Governance Multisig nor the BLabs Multisig will have any pause power.

An important distinction between the pause mechanism in Boosted Pools and that of previous pool types and of the vault is that Boosted Pools are not supposed to be unpaused. In practice, after a pool is paused users should withdraw assets from the pool and a new pool should be deployed. In the event that the pause mechanism must be triggered, Balancer Labs will commit resources to draw attention from liquidity providers to the fact that they must withdraw their funds.

Specification

The Balancer governance multisig on Ethereum Mainnet ( 0x10A19e7eE7d7F8a52822f6817de8ea18204F2e4f ) would submit a transaction to the Authorizer ( 0xA331D84eC860Bf466b4CdCcFb4aC09a1B43F3aE6 ) in order to grant the following roles to a Multisig controlled by Balancer Labs ( 0x02f35dA6A02017154367Bc4d47bb6c7D06C7533B ):

  1. the ability to call the setPaused function on pools deployed from the AaveLinearPool factory ( 0xD7FAD3bd59D6477cbe1BE7f646F7f1BA25b230f8 )
  2. the ability to call the setPaused function on pools deployed from the StablePhantomPool factory ( 0xb08E16cFc07C684dAA2f93C70323BAdb2A6CBFd2 )

0xfcd7627e000000000000000000000000000000000000000000000000000000000000004000000000000000000000000002f35da6a02017154367bc4d47bb6c7d06c7533b0000000000000000000000000000000000000000000000000000000000000002bdac75576424959cffc7f91ec4674a05fd1c62bedcbcbce9dab046c58c8819505bcdcc8d471eea0c6345d3dd65ad4997a32054e1e0672b780a9b6c36df0166a3

Which is the ABI-encoded calldata for:

authorizer.grantRoles(
  [
    0xbdac75576424959cffc7f91ec4674a05fd1c62bedcbcbce9dab046c58c881950,
    0x5bcdcc8d471eea0c6345d3dd65ad4997a32054e1e0672b780a9b6c36df0166a3,
  ],
  0x02f35dA6A02017154367Bc4d47bb6c7D06C7533B
);

For transparency’s sake, a developer could reproduce the bytes specifying the roles above using this code:

const ethers = require("ethers")

const authorizer = new ethers.utils.Interface([
  "function grantRoles(bytes32[] memory roles, address account)",
]);
const pool = new ethers.utils.Interface([
  "function setPaused(bool)",
]);

const factories = [
  "0xb08E16cFc07C684dAA2f93C70323BAdb2A6CBFd2",
  "0xD7FAD3bd59D6477cbe1BE7f646F7f1BA25b230f8"
];

function roleId(address, sighash) {
  return ethers.utils.solidityKeccak256(["uint256", "bytes4"], [address, sighash])
}

const roles = factories
  .map(factory => roleId(factory, pool.getSighash("setPaused")));

// Mainnet
let bLabsMultisig = "0x02f35dA6A02017154367Bc4d47bb6c7D06C7533B";
let data = authorizer.encodeFunctionData("grantRoles", [roles, bLabsMultisig]);

console.log(`authorizer.grantRoles(
  [
    ${roles.map(role => `${role},`).join("\n    ")}
  ],
  ${bLabsMultisig}
);`);
console.log(data);
1 Like