Skip to content

Commit e23d5c9

Browse files
committed
refactor: expand ProtocolRegistry to list all contracts + pause
1 parent b2dde16 commit e23d5c9

File tree

3 files changed

+157
-56
lines changed

3 files changed

+157
-56
lines changed

src/contracts/core/ProtocolRegistry.sol

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pragma solidity ^0.8.27;
33

44
import "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
55
import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";
6+
import "../interfaces/IPausable.sol";
67
import "./ProtocolRegistryStorage.sol";
78

89
contract ProtocolRegistry is Initializable, OwnableUpgradeable, ProtocolRegistryStorage {
@@ -31,29 +32,77 @@ contract ProtocolRegistry is Initializable, OwnableUpgradeable, ProtocolRegistry
3132
*/
3233

3334
/// @inheritdoc IProtocolRegistry
34-
function setVersion(address addr, string calldata semver) external onlyOwner {
35-
_setVersion(addr, semver);
35+
function ship(
36+
Deployment calldata deployment,
37+
address[] calldata implementations,
38+
string calldata semanticVersion
39+
) external onlyOwner {
40+
// Update the semantic version.
41+
_semanticVersions.push(semanticVersion.toShortString());
42+
// Append the single deployment.
43+
_appendDeployment(deployment, implementations, semanticVersion);
3644
}
3745

3846
/// @inheritdoc IProtocolRegistry
39-
function setVersions(address[] calldata addresses, string calldata semver) external onlyOwner {
40-
for (uint256 i = 0; i < addresses.length; ++i) {
41-
_setVersion(addresses[i], semver);
47+
function ship(
48+
Deployment[] calldata deployments,
49+
address[][] calldata implementations,
50+
string calldata semanticVersion
51+
) external onlyOwner {
52+
// Update the semantic version.
53+
_semanticVersions.push(semanticVersion.toShortString());
54+
for (uint256 i = 0; i < deployments.length; ++i) {
55+
// Append each provided deployment.
56+
_appendDeployment(deployments[i], implementations[i], semanticVersion);
4257
}
4358
}
4459

4560
/// @inheritdoc IProtocolRegistry
46-
function setVersions(address[] calldata addresses, string[] calldata semvers) external onlyOwner {
47-
require(addresses.length == semvers.length, InputArrayLengthMismatch());
48-
for (uint256 i = 0; i < addresses.length; ++i) {
49-
_setVersion(addresses[i], semvers[i]);
61+
function configure(uint256 deploymentIndex, DeploymentConfig calldata config) external onlyOwner {
62+
// Create a storage pointer for so we only read once.
63+
Deployment storage deployment = _deployments[deploymentIndex];
64+
// Update the deployment config.
65+
deployment.config = config;
66+
// Emit the event.
67+
emit DeploymentConfigured(deployment.addr, config);
68+
}
69+
70+
/// @inheritdoc IProtocolRegistry
71+
function pauseAll() external onlyOwner {
72+
uint256 totalDeployments = _deployments.length;
73+
// Iterate over all stored deployments
74+
for (uint256 i = 0; i < totalDeployments; ++i) {
75+
Deployment storage deployment = _deployments[i];
76+
// Only attempt to pause deployments marked as pausable
77+
if (deployment.config.pausable) {
78+
// Attempt to call pauseAll; if it fails, continue to the next deployment.
79+
// This ensures a single failure does not prevent us from pausing others in a timely manner.
80+
try IPausable(deployment.addr).pauseAll() {} catch {}
81+
}
5082
}
5183
}
5284

53-
/// @dev Internal function to set the version for a given address.
54-
function _setVersion(address addr, string calldata semver) internal {
55-
_semver[addr] = semver.toShortString();
56-
emit VersionSet(addr, semver);
85+
/**
86+
*
87+
* HELPER FUNCTIONS
88+
*
89+
*/
90+
91+
/// @dev Appends a deployment and it's corresponding implementations.
92+
function _appendDeployment(
93+
Deployment calldata deployment,
94+
address[] calldata implementations,
95+
string calldata semanticVersion
96+
) internal {
97+
// TODO: Prevent duplicates
98+
99+
// Append the deployment.
100+
_deployments.push(deployment);
101+
// Append the implementations for the deployment.
102+
_implementations[deployment.addr].push(implementations);
103+
// Emit the events.
104+
emit DeploymentShipped(deployment.addr, implementations, semanticVersion);
105+
emit DeploymentConfigured(deployment.addr, deployment.config);
57106
}
58107

59108
/**
@@ -63,17 +112,13 @@ contract ProtocolRegistry is Initializable, OwnableUpgradeable, ProtocolRegistry
63112
*/
64113

65114
/// @inheritdoc IProtocolRegistry
66-
function version(
67-
address addr
68-
) external view returns (string memory) {
69-
return _semver[addr].toString();
115+
function latestVersion() external view returns (string memory) {
116+
return _semanticVersions[_deployments.length - 1].toString();
70117
}
71118

72119
/// @inheritdoc IProtocolRegistry
73-
function majorVersion(
74-
address addr
75-
) external view returns (string memory) {
76-
bytes memory v = bytes(_semver[addr].toString());
120+
function latestMajorVersion() external view returns (string memory) {
121+
bytes memory v = bytes(_semanticVersions[_deployments.length - 1].toString());
77122
return string(abi.encodePacked(v[0]));
78123
}
79124
}

src/contracts/core/ProtocolRegistryStorage.sol

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,25 @@ pragma solidity ^0.8.27;
44
import "@openzeppelin-upgrades/contracts/utils/ShortStringsUpgradeable.sol";
55
import "../interfaces/IProtocolRegistry.sol";
66

7+
// 64 bytes remain, could also use a bitmap if more is needed.
8+
79
abstract contract ProtocolRegistryStorage is IProtocolRegistry {
8-
/// @notice Mapping from an address to its semantic version.
9-
mapping(address addr => ShortString semver) internal _semver;
10+
/// @notice Returns an append-only historical record of all semantic version identifiers for the protocol's deployments.
11+
/// @dev Each entry corresponds to a version used for a deployment in the order they occurred.
12+
/// The latest element is the semantic version for the most recent deployment.
13+
ShortString[] internal _semanticVersions;
14+
15+
/// @notice Returns an append-only list of all deployments (state holding contracts).
16+
Deployment[] internal _deployments;
17+
18+
/// @notice Returns the implementations for a given deployment.
19+
/// @dev We use a nested list to support split-contract patterns.
20+
mapping(address proxy => address[][] implementations) internal _implementations;
1021

1122
/**
1223
* @dev This empty reserved space is put in place to allow future versions to add new
1324
* variables without shifting down storage in the inheritance chain.
1425
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
1526
*/
16-
uint256[49] private __gap;
27+
uint256[47] private __gap;
1728
}

src/contracts/interfaces/IProtocolRegistry.sol

Lines changed: 77 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,47 @@ interface IProtocolRegistryErrors {
66
error InputArrayLengthMismatch();
77
}
88

9-
interface IProtocolRegistryTypes {}
9+
interface IProtocolRegistryTypes {
10+
/**
11+
* @notice Configuration for a protocol deployment.
12+
* @param pausable Whether this deployment can be paused.
13+
* @param upgradeable Whether this deployment is upgradeable.
14+
* @param splitContract Whether this deployment uses a split-contract pattern (two implementations).
15+
* @param deprecated Whether this deployment is deprecated.
16+
*/
17+
struct DeploymentConfig {
18+
bool pausable;
19+
bool upgradeable;
20+
bool splitContract;
21+
bool deprecated;
22+
}
23+
24+
/**
25+
* @notice Parameters describing a protocol deployment.
26+
* @param addr The address of the deployment (proxy address if upgradeable).
27+
* @param config The configuration for the deployment.
28+
*/
29+
struct Deployment {
30+
address addr;
31+
DeploymentConfig config;
32+
}
33+
}
1034

1135
interface IProtocolRegistryEvents is IProtocolRegistryTypes {
12-
/// @notice Emitted when the version is set for a given address.
13-
/// @param addr The address for which the version is set.
14-
/// @param semver The semantic version string set for the address.
15-
event VersionSet(address indexed addr, string semver);
36+
/**
37+
* @notice Emitted when a deployment is shipped.
38+
* @param addr The address of the deployment.
39+
* @param implementations The implementation addresses for the deployment.
40+
* @param semanticVersion The semantic version associated with the deployment.
41+
*/
42+
event DeploymentShipped(address indexed addr, address[] implementations, string semanticVersion);
43+
44+
/**
45+
* @notice Emitted when a deployment is configured.
46+
* @param addr The address of the deployment.
47+
* @param config The configuration for the deployment.
48+
*/
49+
event DeploymentConfigured(address indexed addr, DeploymentConfig config);
1650
}
1751

1852
interface IProtocolRegistry is IProtocolRegistryErrors, IProtocolRegistryEvents {
@@ -25,44 +59,55 @@ interface IProtocolRegistry is IProtocolRegistryErrors, IProtocolRegistryEvents
2559
) external;
2660

2761
/**
28-
* @notice Sets the semantic version for a single address.
29-
* @dev Only callable by the contract owner.
30-
* @param addr The address for which to set the version.
31-
* @param semver The semantic version string to set for the address.
62+
* @notice Ships a deployment and it's corresponding implementations.
63+
* @dev Only callable by the owner.
64+
* @param deployment The deployment to ship.
65+
* @param implementations The implementations to ship.
66+
* @param semanticVersion The semantic version to ship.
67+
*/
68+
function ship(
69+
Deployment calldata deployment,
70+
address[] calldata implementations,
71+
string calldata semanticVersion
72+
) external;
73+
74+
/**
75+
* @notice Ships a list of deployments and their corresponding implementations.
76+
* @dev Only callable by the owner.
77+
* @param deployments The deployments to ship.
78+
* @param implementations The implementations to ship.
79+
* @param semanticVersion The semantic version to ship.
3280
*/
33-
function setVersion(address addr, string calldata semver) external;
81+
function ship(
82+
Deployment[] calldata deployments,
83+
address[][] calldata implementations,
84+
string calldata semanticVersion
85+
) external;
3486

3587
/**
36-
* @notice Sets the same semantic version for each address in the provided array.
37-
* @dev Only callable by the contract owner.
38-
* @param addresses The addresses for which to set the version.
39-
* @param semver The semantic version string to set for all addresses.
88+
* @notice Configures a deployment.
89+
* @dev Only callable by the owner.
90+
* @param deploymentIndex The index of the deployment to configure.
91+
* @param config The configuration to set.
4092
*/
41-
function setVersions(address[] calldata addresses, string calldata semver) external;
93+
function configure(uint256 deploymentIndex, DeploymentConfig calldata config) external;
4294

4395
/**
44-
* @notice Sets a distinct semantic version for each address in the provided array.
45-
* @dev Only callable by the contract owner.
46-
* @param addresses The addresses for which to set the version.
47-
* @param semvers The semantic version strings to set, one for each address.
96+
* @notice Pauses all deployments that support pausing.
97+
* @dev Loops over all deployments and attempts to invoke `pauseAll()` on each contract that is marked as pausable.
98+
* Silently ignores errors during calls for rapid pausing in emergencies. Owner only.
4899
*/
49-
function setVersions(address[] calldata addresses, string[] calldata semvers) external;
100+
function pauseAll() external;
50101

51102
/**
52-
* @notice Returns the semantic version string for a given address.
53-
* @param addr The address to query.
54-
* @return The semantic version string associated with the address.
103+
* @notice Returns the semantic version string for the latest deployment.
104+
* @return The semantic version string associated with the latest deployment.
55105
*/
56-
function version(
57-
address addr
58-
) external view returns (string memory);
106+
function latestVersion() external view returns (string memory);
59107

60108
/**
61-
* @notice Returns the major version string for a given address.
62-
* @param addr The address to query.
63-
* @return The major version string associated with the address.
109+
* @notice Returns the major version string for the latest deployment.
110+
* @return The major version string associated with the latest deployment.
64111
*/
65-
function majorVersion(
66-
address addr
67-
) external view returns (string memory);
112+
function latestMajorVersion() external view returns (string memory);
68113
}

0 commit comments

Comments
 (0)