Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test administrator features with multisig #984

Merged
merged 19 commits into from
Sep 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions cli/lib/nf3.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,19 @@ class Nf3 {
return res.data.address.toLowerCase();
}

/**
Returns the abi of a Nightfall_3 contract calling the client.
@method
@async
@param {string} contractName - the name of the smart contract in question. Possible
values are 'Shield', 'State', 'Proposers', 'Challengers'.
@returns {Promise} Resolves into the Ethereum abi of the contract
*/
async getContractAbi(contractName) {
const res = await axios.get(`${this.clientBaseUrl}/contract-abi/${contractName}`);
return res.data.abi;
}

/**
Returns the address of a Nightfall_3 contract calling the optimist.
@method
Expand Down
26 changes: 19 additions & 7 deletions nightfall-administrator/src/services/contract-transactions.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import config from 'config';
import { waitForContract, web3 } from '../../../common-files/utils/contract.mjs';
import logger from '../../../common-files/utils/logger.mjs';
import constants from '../../../common-files/constants/index.mjs';
import { addMultiSigSignature } from './helpers.mjs';
import { addMultiSigSignature, getMultiSigNonce } from './helpers.mjs';

const { RESTRICTIONS } = config;
const { SHIELD_CONTRACT_NAME } = constants;
Expand Down Expand Up @@ -40,7 +40,9 @@ export async function setTokenRestrictions(
return false;
}

export async function removeTokenRestrictions(tokenName, signingKey, executorAddress, nonce) {
export async function removeTokenRestrictions(tokenName, signingKey, executorAddress, _nonce) {
let nonce = _nonce;
if (!Number.isInteger(nonce)) nonce = await getMultiSigNonce();
const shieldContractInstance = await waitForContract(SHIELD_CONTRACT_NAME);
for (const token of RESTRICTIONS.tokens[process.env.ETH_NETWORK]) {
if (token.name === tokenName) {
Expand All @@ -59,8 +61,10 @@ export async function removeTokenRestrictions(tokenName, signingKey, executorAdd
return false;
}

export function pauseContracts(signingKey, executorAddress, nonce) {
export async function pauseContracts(signingKey, executorAddress, _nonce) {
logger.info('All pausable contracts being paused');
let nonce = _nonce;
if (!Number.isInteger(nonce)) nonce = await getMultiSigNonce();
return Promise.all(
pausables.map(async (pausable, i) => {
const contractInstance = await waitForContract(pausable);
Expand All @@ -76,8 +80,10 @@ export function pauseContracts(signingKey, executorAddress, nonce) {
);
}

export function unpauseContracts(signingKey, executorAddress, nonce) {
export async function unpauseContracts(signingKey, executorAddress, _nonce) {
logger.info('All pausable contracts being unpaused');
let nonce = _nonce;
if (!Number.isInteger(nonce)) nonce = await getMultiSigNonce();
return Promise.all(
pausables.map(async (pausable, i) => {
const contractInstance = await waitForContract(pausable);
Expand All @@ -93,7 +99,9 @@ export function unpauseContracts(signingKey, executorAddress, nonce) {
);
}

export function transferOwnership(newOwnerPrivateKey, signingKey, executorAddress, nonce) {
export async function transferOwnership(newOwnerPrivateKey, signingKey, executorAddress, _nonce) {
let nonce = _nonce;
if (!Number.isInteger(nonce)) nonce = await getMultiSigNonce();
const newOwner = web3.eth.accounts.privateKeyToAccount(newOwnerPrivateKey, true).address;
return Promise.all(
ownables.map(async (ownable, i) => {
Expand All @@ -110,7 +118,9 @@ export function transferOwnership(newOwnerPrivateKey, signingKey, executorAddres
);
}

export async function setBootProposer(newProposerPrivateKey, signingKey, executorAddress, nonce) {
export async function setBootProposer(newProposerPrivateKey, signingKey, executorAddress, _nonce) {
let nonce = _nonce;
if (!Number.isInteger(nonce)) nonce = await getMultiSigNonce();
const newProposer = web3.eth.accounts.privateKeyToAccount(newProposerPrivateKey, true).address;
const shieldContractInstance = await waitForContract(SHIELD_CONTRACT_NAME);
const data = shieldContractInstance.methods.setBootProposer(newProposer).encodeABI();
Expand All @@ -129,8 +139,10 @@ export async function setBootChallenger(
newChallengerPrivateKey,
signingKey,
executorAddress,
nonce,
_nonce,
) {
let nonce = _nonce;
if (!Number.isInteger(nonce)) nonce = await getMultiSigNonce();
const newChallenger = web3.eth.accounts.privateKeyToAccount(
newChallengerPrivateKey,
true,
Expand Down
18 changes: 14 additions & 4 deletions nightfall-administrator/src/services/helpers.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ import { checkThreshold, saveSigned, getSigned } from './database.mjs';
const { RESTRICTIONS, WEB3_OPTIONS, MULTISIG } = config;
const { SIGNATURE_THRESHOLD } = MULTISIG;
const MULTISIG_CONSTANTS = {};

/**
Read the nonce from the multisig contract
*/
export async function getMultiSigNonce() {
const { multiSigInstance } = MULTISIG_CONSTANTS;
if (!multiSigInstance) throw new Error('No multisig instance');
const nonce = await multiSigInstance.methods.nonce().call();
return Number(nonce);
}

/**
* Read the names of tokens from the config
*/
Expand Down Expand Up @@ -67,11 +78,10 @@ export async function addSignedTransaction(signed) {
* This function creates the multisig message hash, which is signed (approved) by the key-holders.
* It's worth looking at the multisig contract to see where this all comes from.
*/
async function createMultiSigMessageHash(destination, value, data, _nonce, executor, gasLimit) {
const { domainSeparator, txTypeHash, multiSigInstance, txInputHashABI } = MULTISIG_CONSTANTS;
let nonce = _nonce;
async function createMultiSigMessageHash(destination, value, data, nonce, executor, gasLimit) {
const { domainSeparator, txTypeHash, txInputHashABI } = MULTISIG_CONSTANTS;
// get the current multisig nonce if it's not provided (requires blockchain connection)
if (!_nonce) nonce = await multiSigInstance.methods.nonce().call();
if (!Number.isInteger(nonce)) throw new Error(`Nonce is not an integer: ${nonce}`);
// compute the hashes to sign over note, sometimes we want a keccak hash over encoded parameter
// and sometimes over encodedPacked parameters. Hence the two slightly different approaches used.
const dataHash = web3.utils.soliditySha3({ t: 'bytes', v: data });
Expand Down
5 changes: 0 additions & 5 deletions nightfall-administrator/src/ui/get-info.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ async function start() {
tokenName,
depositRestriction,
withdrawRestriction,
pause,
unpause,
newEthereumSigningKey,
executorAddress,
nonce,
Expand Down Expand Up @@ -73,13 +71,10 @@ async function start() {
break;
}
case 'Unpause contracts': {
if (!unpause) break;
logger.info('CALLING unpauseContracts');
approved = await unpauseContracts(ethereumSigningKey, executorAddress, nonce);
break;
}
case 'Pause contracts': {
if (!pause) break;
approved = await pauseContracts(ethereumSigningKey, executorAddress, nonce);
break;
}
Expand Down
12 changes: 0 additions & 12 deletions nightfall-administrator/src/ui/menu.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -113,18 +113,6 @@ export async function askQuestions(approved) {
when: answers => answers.task === 'Set token restrictions',
validate: input => Number.isInteger(Number(input)) && Number(input) > 0,
},
{
name: 'pause',
type: 'confirm',
message: 'Pause contracts?',
when: answers => answers.task === 'Pause contracts',
},
{
name: 'unpause',
type: 'confirm',
message: 'Unpause contracts?',
when: answers => answers.task === 'Unpause contracts',
},
{
name: 'amount',
type: 'input',
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"test-erc1155-tokens": "npx hardhat test --bail --no-compile --grep ERC1155",
"test-erc20-cli": "npx hardhat test --no-compile --bail test/client/erc20.test.mjs ",
"ping-pong": "npx hardhat test --bail --no-compile test/ping-pong/ping-pong.test.mjs",
"test-administrator": "npx hardhat test --bail --no-compile test/multisig/administrator.test.mjs ",
"test-optimist-sync": "npx hardhat test --no-compile --bail test/optimist-resync.test.mjs",
"test-adversary": "CHALLENGE_TYPE=${CHALLENGE_TYPE} npx hardhat test --no-compile --bail test/adversary.test.mjs",
"test-all-adversary": "for CHALLENGE_TYPE in IncorrectTreeRoot IncorrectLeafCount IncorrectTreeRoot IncorrectLeafCount; do CHALLENGE_TYPE=${CHALLENGE_TYPE} npm run test-adversary; sleep 5; done",
Expand Down
Loading