Skip to content

Commit a60aa95

Browse files
authored
chore(contracts): add acceptOwnership task for EOA new owner (#1212)
1 parent ee5b60f commit a60aa95

File tree

7 files changed

+110
-9
lines changed

7 files changed

+110
-9
lines changed

gateway-contracts/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ MNEMONIC="adapt mosquito move limb mobile illegal tree voyage juice mosquito bur
99

1010
# Private keys
1111
DEPLOYER_PRIVATE_KEY="0x7136d8dc72f873124f4eded25f3525a20f6cee4296564c76b44f1d582c57640f" # accounts[1], private key (bytes32)
12+
NEW_OWNER_PRIVATE_KEY="0x7ae52cf0d3011ef7fecbe22d9537aeda1a9e42a0596e8def5d49970eb59e7a40" # accounts[2], private key (bytes32)
1213

1314
# RPC URL
1415
RPC_URL="http://127.0.0.1:8757" # (string)

gateway-contracts/docs/getting-started/deployment/env_variables.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Here's the complete list of environment variables used for deploying the FHEVM g
5050
| `MNEMONIC` | "Mnemonic phrase for address generation | string | "adapt mosquito move limb mobile illegal tree voyage juice mosquito burger raise father hope layer" | - |
5151
| `RPC_URL` | URL of the RPC node | string | "http://127.0.0.1:8757" | - |
5252
| `GATEWAY_CONFIG_ADDRESS` | Address of the GatewayConfig contract | address | - | Only for production settings |
53+
| `NEW_OWNER_PRIVATE_KEY` | Private key for new owner acceptance | bytes32 | - | Only used in task that transfers ownership of the gateway to a new EAO owner |
5354

5455
## In details
5556

@@ -248,3 +249,11 @@ KMS_GENERATION_ADDRESS="0x87A5b1152AA51728258dbc1AA54B6a83DCd1d3dd" # (address)
248249
```
249250

250251
This (static) address is needed for generating the FHE key and CRS through the KMSGeneration contract. In a proper production setting, this environment variable needs to be dynamically set after deploying the contracts.
252+
253+
- New owner private key
254+
255+
```bash
256+
NEW_OWNER_PRIVATE_KEY="0x7136d8dc72f873124f4eded25f3525a20f6cee4296564c76b44f1d582c57640f" # (bytes32)
257+
```
258+
259+
This is the private key of the targeted new owner EAO, used to accept the ownership of the gateway contracts in case it is not directly transferred to a multisig account.

gateway-contracts/tasks/ownership.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,32 @@ task(
3535
The new owner needs to send an acceptOwnership transaction to validate the transfer`,
3636
);
3737
});
38+
39+
task(
40+
"task:acceptGatewayOwnership",
41+
"Accepts ownership of the gateway contracts. This can only be used if the account is an EOA.",
42+
).setAction(async function ({}, { ethers }) {
43+
// Get the new owner wallet.
44+
const newOwner = new Wallet(getRequiredEnvVar("NEW_OWNER_PRIVATE_KEY")).connect(ethers.provider);
45+
46+
// Get the GatewayConfig contract: its owner is the owner of all gateway contracts
47+
const gatewayConfigSnakeCase = pascalCaseToSnakeCase("GatewayConfig");
48+
const gatewayConfigAddressEnvVarName = `${gatewayConfigSnakeCase.toUpperCase()}_ADDRESS`;
49+
const gatewayConfigContractAddress = getRequiredEnvVar(gatewayConfigAddressEnvVarName);
50+
const gatewayConfigContract = await ethers.getContractAt("GatewayConfig", gatewayConfigContractAddress);
51+
52+
if ((await gatewayConfigContract.pendingOwner()) !== newOwner.address) {
53+
throw new Error(
54+
`The new owner account ${newOwner.address} is not the pending owner of the GatewayConfig contract ${gatewayConfigContractAddress}`,
55+
);
56+
}
57+
58+
// Transfer ownership of the GatewayConfig contract to the destination address.
59+
const tx = await gatewayConfigContract.connect(newOwner).acceptOwnership();
60+
61+
await tx.wait();
62+
63+
console.log(
64+
`Ownership of GatewayConfig contract ${gatewayConfigContractAddress} has been accepted by account ${newOwner.address}`,
65+
);
66+
});

gateway-contracts/test/tasks/ownership.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ import { expect } from "chai";
33
import { Wallet } from "ethers";
44
import hre from "hardhat";
55

6+
import { getRequiredEnvVar } from "../../tasks/utils/loadVariables";
67
import { GatewayConfig } from "../../typechain-types";
78
import { loadTestVariablesFixture } from "../utils";
89

910
describe("Ownership tasks", function () {
10-
// Define the private key of the new owner (Account 2)
11-
const newOwnerPrivateKey = "0x7ae52cf0d3011ef7fecbe22d9537aeda1a9e42a0596e8def5d49970eb59e7a40";
11+
// Get the private key of the new owner
12+
const newOwnerPrivateKey = getRequiredEnvVar("NEW_OWNER_PRIVATE_KEY");
1213
const newOwner = new Wallet(newOwnerPrivateKey).connect(hre.ethers.provider);
1314

1415
let gatewayConfig: GatewayConfig;
@@ -23,10 +24,7 @@ describe("Ownership tasks", function () {
2324
it("Should ask transfer ownership of the GatewayConfig contract", async function () {
2425
expect(await gatewayConfig.owner()).to.eq(owner.address);
2526

26-
await hre.run("task:transferGatewayOwnership", {
27-
currentOwnerPrivateKey: owner.privateKey,
28-
newOwnerAddress: newOwner.address,
29-
});
27+
await hre.run("task:transferGatewayOwnership", { newOwnerAddress: newOwner.address });
3028

3129
// Check that the ownership has not been transferred as the transfer is only pending since the
3230
// new owner has not accepted it yet.
@@ -35,4 +33,11 @@ describe("Ownership tasks", function () {
3533
// Check that the pending owner is the new owner.
3634
expect(await gatewayConfig.pendingOwner()).to.eq(newOwner.address);
3735
});
36+
37+
it("Should accept ownership of the GatewayConfig contract", async function () {
38+
await hre.run("task:acceptGatewayOwnership");
39+
40+
// Check that the ownership has been transferred to the new owner.
41+
expect(await gatewayConfig.owner()).to.eq(newOwner.address);
42+
});
3843
});

host-contracts/.env.example

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,8 @@ PAUSER_SET_CONTRACT_ADDRESS="0x44aA028fd264C76BF4A8f8B4d8A5272f6AE25CAc" # (addr
3939

4040
# The first pauser's private key
4141
# This is required for local tests and running the pausing task. It must correspond to one of the pauser's private key
42-
PAUSER_PRIVATE_KEY="0x7ae52cf0d3011ef7fecbe22d9537aeda1a9e42a0596e8def5d49970eb59e7a40" # accounts[2], private key (bytes32)
42+
PAUSER_PRIVATE_KEY="0x7ae52cf0d3011ef7fecbe22d9537aeda1a9e42a0596e8def5d49970eb59e7a40" # accounts[2], private key (bytes32)
43+
44+
# This is the private key of the targeted new owner EAO, used to accept the ownership of the host
45+
# contracts in case it is not directly transferred to a multisig account.
46+
NEW_OWNER_PRIVATE_KEY="0x7ae52cf0d3011ef7fecbe22d9537aeda1a9e42a0596e8def5d49970eb59e7a40" # accounts[2], private key (bytes32)

host-contracts/tasks/ownership.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,29 @@ task('task:transferHostOwnership', "Transfers the deployer's ownership of the ho
3030
The new owner needs to send an acceptOwnership transaction to validate the transfer`,
3131
);
3232
});
33+
34+
task(
35+
'task:acceptHostOwnership',
36+
'Accepts ownership of the host contracts. This can only be used if the account is an EOA.',
37+
).setAction(async function ({}, { ethers }) {
38+
// Get the new owner wallet.
39+
const newOwner = new Wallet(getRequiredEnvVar('NEW_OWNER_PRIVATE_KEY')).connect(ethers.provider);
40+
41+
// Get the ACL contract: its owner is the owner of all host contracts
42+
const contractName = 'ACL';
43+
const aclContractAddress = getRequiredEnvVar(`${contractName}_CONTRACT_ADDRESS`);
44+
const aclContract = await ethers.getContractAt(contractName, aclContractAddress);
45+
46+
if ((await aclContract.pendingOwner()) !== newOwner.address) {
47+
throw new Error(
48+
`The new owner account ${newOwner.address} is not the pending owner of the ACL contract ${aclContractAddress}`,
49+
);
50+
}
51+
52+
// Accept ownership of the ACL contract.
53+
const tx = await aclContract.connect(newOwner).acceptOwnership();
54+
55+
await tx.wait();
56+
57+
console.log(`Ownership of ACL contract ${aclContractAddress} has been accepted by account ${newOwner.address}`);
58+
});

host-contracts/test/tasks/ownership.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ describe('Ownership tasks', function () {
1313
const deployerPrivateKey = getRequiredEnvVar('DEPLOYER_PRIVATE_KEY');
1414
const deployer = new ethers.Wallet(deployerPrivateKey).connect(ethers.provider);
1515

16-
// Define the private key of the new owner (Account 2)
17-
const newOwnerPrivateKey = '0x7ae52cf0d3011ef7fecbe22d9537aeda1a9e42a0596e8def5d49970eb59e7a40';
16+
// Get the private key of the new owner
17+
const newOwnerPrivateKey = getRequiredEnvVar('NEW_OWNER_PRIVATE_KEY');
1818
const newOwner = new ethers.Wallet(newOwnerPrivateKey).connect(ethers.provider);
1919

2020
before(async function () {
@@ -37,4 +37,31 @@ describe('Ownership tasks', function () {
3737
// Check that the pending owner is the new owner.
3838
expect(await acl.pendingOwner()).to.eq(newOwner.address);
3939
});
40+
41+
it('Should accept ownership of the ACL contract', async function () {
42+
await run('task:acceptHostOwnership');
43+
44+
// Check that the ownership has been transferred to the new owner.
45+
expect(await acl.owner()).to.eq(newOwner.address);
46+
});
47+
48+
// This is to avoid to break other tests
49+
it('Should put back ownership of the ACL contract to the deployer', async function () {
50+
// Temporarily swap the deployer and the new owner private keys
51+
process.env.DEPLOYER_PRIVATE_KEY = newOwnerPrivateKey;
52+
process.env.NEW_OWNER_PRIVATE_KEY = deployerPrivateKey;
53+
54+
// Transfer ownership to the deployer and accept it
55+
await run('task:transferHostOwnership', {
56+
newOwnerAddress: deployer.address,
57+
});
58+
await run('task:acceptHostOwnership');
59+
60+
// Check that the ownership has been transferred back to the deployer.
61+
expect(await acl.owner()).to.eq(deployer.address);
62+
63+
// Restore the original private keys
64+
process.env.DEPLOYER_PRIVATE_KEY = deployerPrivateKey;
65+
process.env.NEW_OWNER_PRIVATE_KEY = newOwnerPrivateKey;
66+
});
4067
});

0 commit comments

Comments
 (0)