Skip to content

Commit

Permalink
registerOperator can set privacy status
Browse files Browse the repository at this point in the history
  • Loading branch information
mtabasco committed Jun 6, 2024
1 parent dada02c commit d078a87
Show file tree
Hide file tree
Showing 14 changed files with 134 additions and 38 deletions.
2 changes: 1 addition & 1 deletion contracts/SSVNetwork.sol
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ contract SSVNetwork is
/* Operator External Functions */
/*******************************/

function registerOperator(bytes calldata publicKey, uint256 fee) external override returns (uint64 id) {
function registerOperator(bytes calldata publicKey, uint256 fee, bool setPrivate) external override returns (uint64 id) {
_delegate(SSVStorage.load().ssvContracts[SSVModules.SSV_OPERATORS]);
}

Expand Down
3 changes: 2 additions & 1 deletion contracts/interfaces/ISSVOperators.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ interface ISSVOperators is ISSVNetworkCore {
/// @notice Registers a new operator
/// @param publicKey The public key of the operator
/// @param fee The operator's fee (SSV)
function registerOperator(bytes calldata publicKey, uint256 fee) external returns (uint64);
/// @param setPrivate Flag indicating whether the operator should be set as private or not
function registerOperator(bytes calldata publicKey, uint256 fee, bool setPrivate) external returns (uint64);

/// @notice Removes an existing operator
/// @param operatorId The ID of the operator to be removed
Expand Down
12 changes: 10 additions & 2 deletions contracts/modules/SSVOperators.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ contract SSVOperators is ISSVOperators {
/* Operator External Functions */
/*******************************/

function registerOperator(bytes calldata publicKey, uint256 fee) external override returns (uint64 id) {
function registerOperator(
bytes calldata publicKey,
uint256 fee,
bool setPrivate
) external override returns (uint64 id) {
if (fee != 0 && fee < MINIMAL_OPERATOR_FEE) {
revert ISSVNetworkCore.FeeTooLow();
}
Expand All @@ -43,11 +47,15 @@ contract SSVOperators is ISSVOperators {
snapshot: ISSVNetworkCore.Snapshot({block: uint32(block.number), index: 0, balance: 0}),
validatorCount: 0,
fee: fee.shrink(),
whitelisted: false
whitelisted: setPrivate
});
s.operatorsPKs[hashedPk] = id;

uint64[] memory operatorIds = new uint64[](1);
operatorIds[0] = id;

emit OperatorAdded(id, msg.sender, publicKey, fee);
emit OperatorPrivacyStatusUpdated(operatorIds, setPrivate);
}

function removeOperator(uint64 operatorId) external override {
Expand Down
4 changes: 2 additions & 2 deletions contracts/test/SSVNetworkUpgrade.sol
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ contract SSVNetworkUpgrade is
/* Operator External Functions */
/*******************************/

function registerOperator(bytes calldata publicKey, uint256 fee) external override returns (uint64 id) {
function registerOperator(bytes calldata publicKey, uint256 fee, bool setPrivate) external override returns (uint64 id) {
bytes memory result = _delegateCall(
SSVStorage.load().ssvContracts[SSVModules.SSV_OPERATORS],
abi.encodeWithSignature("registerOperator(bytes,uint256)", publicKey, fee)
abi.encodeWithSignature("registerOperator(bytes,uint256)", publicKey, fee, setPrivate)
);
return abi.decode(result, (uint64));
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/test/mocks/BeneficiaryContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ contract BeneficiaryContract {
}

function registerOperator() external returns (uint64 operatorId) {
return ISSVOperators(ssvContract).registerOperator("0xcafecafe", 100000000);
return ISSVOperators(ssvContract).registerOperator("0xcafecafe", 100000000, false);
}
}
12 changes: 10 additions & 2 deletions contracts/test/modules/SSVOperatorsUpdate.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ contract SSVOperatorsUpdate is ISSVOperators {
/* Operator External Functions */
/*******************************/

function registerOperator(bytes calldata publicKey, uint256 fee) external override returns (uint64 id) {
function registerOperator(
bytes calldata publicKey,
uint256 fee,
bool setPrivate
) external override returns (uint64 id) {
if (fee != 0 && fee < MINIMAL_OPERATOR_FEE) {
revert ISSVNetworkCore.FeeTooLow();
}
Expand All @@ -39,11 +43,15 @@ contract SSVOperatorsUpdate is ISSVOperators {
snapshot: ISSVNetworkCore.Snapshot({block: uint32(block.number), index: 0, balance: 0}),
validatorCount: 0,
fee: fee.shrink(),
whitelisted: false
whitelisted: setPrivate
});
s.operatorsPKs[hashedPk] = id;

uint64[] memory operatorIds = new uint64[](1);
operatorIds[0] = id;

emit OperatorAdded(id, msg.sender, publicKey, fee);
emit OperatorPrivacyStatusUpdated(operatorIds, setPrivate);
}

function removeOperator(uint64 operatorId) external override {
Expand Down
2 changes: 1 addition & 1 deletion test/deployment/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('Deployment tests', () => {
});

it('Upgrade SSVNetwork contract. Check new function execution', async () => {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee], {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee, false], {
account: owners[1].account,
});

Expand Down
2 changes: 1 addition & 1 deletion test/helpers/contract-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ export const registerOperators = async function (
operator.publicKey = keccak256(toBytes(operator.operatorKey));

const { eventsByName } = await trackGas(
ssvNetwork.write.registerOperator([operator.publicKey, fee], {
ssvNetwork.write.registerOperator([operator.publicKey, fee, false], {
account: owners[ownerId].account,
}),
gasGroups,
Expand Down
2 changes: 1 addition & 1 deletion test/helpers/gas-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export enum GasGroup {

const MAX_GAS_PER_GROUP: any = {
/* REAL GAS LIMITS */
[GasGroup.REGISTER_OPERATOR]: 134500,
[GasGroup.REGISTER_OPERATOR]: 137000,
[GasGroup.REMOVE_OPERATOR]: 70500,
[GasGroup.REMOVE_OPERATOR_WITH_WITHDRAW]: 70500,
[GasGroup.SET_OPERATOR_WHITELISTING_CONTRACT]: 95500,
Expand Down
107 changes: 93 additions & 14 deletions test/operators/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ describe('Register Operator Tests', () => {
ssvViews = metadata.ssvNetworkViews;
});

it('Register operator emits "OperatorAdded"', async () => {
it('Register operator emits "OperatorAdded" and "OperatorPrivacyStatusUpdated" if setPrivate is true', async () => {
const publicKey = DataGenerator.publicKey(0);

await assertEvent(
ssvNetwork.write.registerOperator([publicKey, CONFIG.minimalOperatorFee], {
ssvNetwork.write.registerOperator([publicKey, CONFIG.minimalOperatorFee, true], {
account: owners[1].account,
}),
[
Expand All @@ -31,21 +31,58 @@ describe('Register Operator Tests', () => {
argNames: ['operatorId', 'owner', 'publicKey', 'fee'],
argValuesList: [[1, owners[1].account.address, publicKey, CONFIG.minimalOperatorFee]],
},
{
contract: ssvNetwork,
eventName: 'OperatorPrivacyStatusUpdated',
argNames: ['operatorIds', 'toPrivate'],
argValuesList: [[[1], true]],
},
],
);
});

it('Register operator emits "OperatorAdded" and "OperatorPrivacyStatusUpdated" if setPrivate is false', async () => {
const publicKey = DataGenerator.publicKey(0);

await assertEvent(
ssvNetwork.write.registerOperator([publicKey, CONFIG.minimalOperatorFee, false], {
account: owners[1].account,
}),
[
{
contract: ssvNetwork,
eventName: 'OperatorAdded',
argNames: ['operatorId', 'owner', 'publicKey', 'fee'],
argValuesList: [[1, owners[1].account.address, publicKey, CONFIG.minimalOperatorFee]],
},
{
contract: ssvNetwork,
eventName: 'OperatorPrivacyStatusUpdated',
argNames: ['operatorIds', 'toPrivate'],
argValuesList: [[[1], false]],
},
],
);
});

it('Register operator gas limits', async () => {
await trackGas(
ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee], {
ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee, false], {
account: owners[1].account,
}),
[GasGroup.REGISTER_OPERATOR],
);

await trackGas(
ssvNetwork.write.registerOperator([DataGenerator.publicKey(1), CONFIG.minimalOperatorFee, true], {
account: owners[1].account,
}),
[GasGroup.REGISTER_OPERATOR],
);
});

it('Get operator by id', async () => {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee], {
it('Get operator by id with setPrivate false', async () => {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee, false], {
account: owners[1].account,
});

Expand All @@ -59,8 +96,23 @@ describe('Register Operator Tests', () => {
]);
});

it('Get operator by id with setPrivate true', async () => {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee, true], {
account: owners[1].account,
});

expect(await ssvViews.read.getOperatorById([1])).to.deep.equal([
owners[1].account.address, // owner
CONFIG.minimalOperatorFee, // fee
0, // validatorCount
ethers.ZeroAddress, // whitelisting contract address
true, // isPrivate
true, // active
]);
});

it('Get non-existent operator by id', async () => {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee], {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee, false], {
account: owners[1].account,
});

Expand All @@ -75,7 +127,7 @@ describe('Register Operator Tests', () => {
});

it('Get operator removed by id', async () => {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee], {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee, false], {
account: owners[1].account,
});
await ssvNetwork.write.removeOperator([1], {
Expand All @@ -92,24 +144,51 @@ describe('Register Operator Tests', () => {
]);
});

it('Register an operator with a fee thats too low reverts "FeeTooLow"', async () => {
await expect(ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), '10'])).to.be.rejectedWith('FeeTooLow');
it('Register an operator with a fee thats too low reverts "FeeTooLow", setPrivate false', async () => {
await expect(ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), '10', false])).to.be.rejectedWith(
'FeeTooLow',
);
});

it('Register an operator with a fee thats too low reverts "FeeTooLow", setPrivate true', async () => {
await expect(ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), '10', true])).to.be.rejectedWith(
'FeeTooLow',
);
});

it('Register an operator with a fee thats too high reverts "FeeTooHigh"', async () => {
await expect(ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), 2e14])).to.be.rejectedWith(
it('Register an operator with a fee thats too high reverts "FeeTooHigh", setPrivate false', async () => {
await expect(ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), 2e14, false])).to.be.rejectedWith(
'FeeTooHigh',
);
});

it('Register same operator twice reverts "OperatorAlreadyExists"', async () => {
it('Register an operator with a fee thats too high reverts "FeeTooHigh", setPrivate false', async () => {
await expect(ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), 2e14, true])).to.be.rejectedWith(
'FeeTooHigh',
);
});

it('Register same operator twice reverts "OperatorAlreadyExists", setPrivate false', async () => {
const publicKey = DataGenerator.publicKey(1);
await ssvNetwork.write.registerOperator([publicKey, CONFIG.minimalOperatorFee, false], {
account: owners[1].account,
});

await expect(
ssvNetwork.write.registerOperator([publicKey, CONFIG.minimalOperatorFee, false], {
account: owners[1].account,
}),
).to.be.rejectedWith('OperatorAlreadyExists');
});

it('Register same operator twice reverts "OperatorAlreadyExists", setPrivate true', async () => {
const publicKey = DataGenerator.publicKey(1);
await ssvNetwork.write.registerOperator([publicKey, CONFIG.minimalOperatorFee], {
await ssvNetwork.write.registerOperator([publicKey, CONFIG.minimalOperatorFee, true], {
account: owners[1].account,
});

await expect(
ssvNetwork.write.registerOperator([publicKey, CONFIG.minimalOperatorFee], {
ssvNetwork.write.registerOperator([publicKey, CONFIG.minimalOperatorFee, true], {
account: owners[1].account,
}),
).to.be.rejectedWith('OperatorAlreadyExists');
Expand Down
4 changes: 2 additions & 2 deletions test/operators/remove.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ describe('Remove Operator Tests', () => {

it('Remove private operator emits "OperatorRemoved"', async () => {
const result = await trackGas(
ssvNetwork.write.registerOperator([DataGenerator.publicKey(22), CONFIG.minimalOperatorFee]),
ssvNetwork.write.registerOperator([DataGenerator.publicKey(22), CONFIG.minimalOperatorFee, true]),
);
const { operatorId } = result.eventsByName.OperatorAdded[0].args;

Expand All @@ -66,7 +66,7 @@ describe('Remove Operator Tests', () => {
0, // fee
0, // validatorCount
ethers.ZeroAddress, // whitelisting contract address
false, // isPrivate
true, // isPrivate
false, // active
]);
});
Expand Down
4 changes: 2 additions & 2 deletions test/operators/update-fee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ describe('Operator Fee Tests', () => {
});

it('Declare fee after registering an operator with zero fee reverts "FeeIncreaseNotAllowed"', async () => {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(2), 0], {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(2), 0, false], {
account: owners[2].account,
});

Expand All @@ -218,7 +218,7 @@ describe('Operator Fee Tests', () => {
const maxOperatorFee = 8e14;
await ssvNetwork.write.updateMaximumOperatorFee([maxOperatorFee]);

await ssvNetwork.write.registerOperator([DataGenerator.publicKey(10), maxOperatorFee], {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(10), maxOperatorFee, false], {
account: owners[3].account,
});

Expand Down
12 changes: 6 additions & 6 deletions test/operators/whitelist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('Whitelisting Operator Tests', () => {

/* GAS LIMITS */
it('Set operator whitelisting contract (1 operator) gas limits', async () => {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee], {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee, true], {
account: owners[1].account,
});
await trackGas(
Expand All @@ -39,7 +39,7 @@ describe('Whitelisting Operator Tests', () => {
});

it('Update operator whitelisting contract (1 operator) gas limits', async () => {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee], {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee, true], {
account: owners[1].account,
});

Expand Down Expand Up @@ -75,7 +75,7 @@ describe('Whitelisting Operator Tests', () => {
});

it('Remove operator whitelisting contract (1 operator) gas limits', async () => {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee], {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee, true], {
account: owners[1].account,
});

Expand Down Expand Up @@ -116,7 +116,7 @@ describe('Whitelisting Operator Tests', () => {
account: owners[1].account,
}),
[GasGroup.SET_MULTIPLE_OPERATOR_WHITELIST_10_10],
);ƒ
);
});

it('Remove 10 whitelist addresses (EOAs) for 10 operators gas limits', async () => {
Expand Down Expand Up @@ -547,7 +547,7 @@ describe('Whitelisting Operator Tests', () => {
});

it('Get private operator by id', async () => {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee], {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee, false], {
account: owners[1].account,
});

Expand All @@ -570,7 +570,7 @@ describe('Whitelisting Operator Tests', () => {
});

it('Get removed private operator by id', async () => {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee], {
await ssvNetwork.write.registerOperator([DataGenerator.publicKey(0), CONFIG.minimalOperatorFee, false], {
account: owners[1].account,
});

Expand Down
4 changes: 2 additions & 2 deletions test/validators/whitelist-register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,11 +356,11 @@ describe('Register Validator Tests', () => {
address: await ssvNetwork.address,
abi: ssvNetwork.abi,
functionName: 'registerOperator',
args: ['0xabcd', CONFIG.minimalOperatorFee],
args: ['0xabcd', CONFIG.minimalOperatorFee, true],
account: owners[0].account,
});

await ssvNetwork.write.registerOperator(['0xabcd', CONFIG.minimalOperatorFee]);
await ssvNetwork.write.registerOperator(['0xabcd', CONFIG.minimalOperatorFee, true]);
// Whitelist the new operator with the attacker contract
await ssvNetwork.write.setOperatorsWhitelistingContract(
[[goodOperatorId], await badOperatorWhitelistingContract.address],
Expand Down

0 comments on commit d078a87

Please sign in to comment.