-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'pzelazko/deployed-contract-checkers' into 'develop'
OCT-794 Add deployed contract simple checkers See merge request wildland/governance/octant!562
- Loading branch information
Showing
7 changed files
with
377 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { subtask, task } from 'hardhat/config'; | ||
import { exit } from 'process'; | ||
|
||
import { verify } from './verification/verifiable'; | ||
|
||
/* eslint no-console: 0 */ | ||
import { AUTH, ZERO_ADDRESS } from '../helpers/constants'; | ||
import { Auth } from '../typechain'; | ||
|
||
task('auth-check', 'Check auth at particular addres') | ||
.addParam('address', 'Auth contract address') | ||
.addParam('contractName', 'Name of the contract', AUTH) | ||
.addFlag('verify', 'Verifies contract storage against expected values') | ||
.addOptionalParam('multisig', 'Expected multisig address') | ||
.addOptionalParam('pendingowner', 'Expected pending owner', ZERO_ADDRESS) | ||
.setAction(async (taskArgs, { ethers, getNamedAccounts, run }) => { | ||
console.log('Querying contract deployed at:', taskArgs.address); | ||
const { deployer } = await getNamedAccounts(); | ||
const target: Auth = await ethers.getContractAt( | ||
taskArgs.contractName, | ||
taskArgs.address, | ||
deployer, | ||
); | ||
|
||
const multisig = await target.multisig(); | ||
const pendingOwner = await target.pendingOwner(); | ||
|
||
console.log('multisig: ', multisig); | ||
console.log('pendingOwner: ', pendingOwner); | ||
|
||
if (taskArgs.verify) { | ||
const result = await run('auth-check:verify'); | ||
exit(result); | ||
} | ||
}); | ||
|
||
subtask('auth-check:verify', 'Verify auth contract') | ||
.addParam('address', 'Auth contract address') | ||
.addParam('multisig', 'Expected multisig address') | ||
.addParam('pendingowner', 'Expected pending owner', ZERO_ADDRESS) | ||
.setAction(async (taskArgs, hre) => { | ||
console.log('Veryfing Auth contract'); | ||
|
||
const res = await verify( | ||
{ | ||
address: taskArgs.address, | ||
contractName: AUTH, | ||
properties: [ | ||
['multisig', taskArgs.multisig], | ||
['pendingOwner', taskArgs.pendingowner], | ||
], | ||
}, | ||
hre, | ||
); | ||
|
||
if (res === 0) { | ||
console.log('Auth contract successfully verified! 👍'); | ||
} | ||
|
||
return res; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { subtask, task } from 'hardhat/config'; | ||
import { exit } from 'process'; | ||
|
||
/* eslint no-console: 0 */ | ||
import { verify } from './verification/verifiable'; | ||
|
||
import { GLM_ADDRESS } from '../env'; | ||
import { DEPOSITS } from '../helpers/constants'; | ||
import { Deposits } from '../typechain'; | ||
|
||
task('deposits-check', 'Check deposits at particular addres') | ||
.addParam('address', 'Deposits contract address') | ||
.addParam('contractName', 'Name of the contract', DEPOSITS) | ||
.addFlag('verify', 'Verifies contract storage against expected values') | ||
.addOptionalParam('auth', 'Expected Auth contract address') | ||
.addOptionalParam('glm', 'Expected GLM contract address') | ||
.setAction(async (taskArgs, { ethers, getNamedAccounts, run }) => { | ||
console.log('Querying contract deployed at:', taskArgs.address); | ||
const { deployer } = await getNamedAccounts(); | ||
const target: Deposits = await ethers.getContractAt( | ||
taskArgs.contractName, | ||
taskArgs.address, | ||
deployer, | ||
); | ||
|
||
const auth = await target.auth(); | ||
const glm = await target.glm(); | ||
|
||
console.log('auth: ', auth); | ||
console.log('glm: ', glm); | ||
|
||
if (taskArgs.verify) { | ||
const result = await run('deposits-check:verify', taskArgs); | ||
exit(result); | ||
} | ||
}); | ||
|
||
subtask('deposits-check:verify', 'Verify deposits contract') | ||
.addParam('address', 'Deposits contract address') | ||
.addParam('auth', 'Expected Auth contract address') | ||
.addParam('glm', 'Expected GLM contract address', GLM_ADDRESS) | ||
.setAction(async (taskArgs, hre) => { | ||
console.log('Veryfing Deposits contract'); | ||
|
||
const res = await verify( | ||
{ | ||
address: taskArgs.address, | ||
contractName: DEPOSITS, | ||
properties: [ | ||
['auth', taskArgs.auth], | ||
['glm', taskArgs.glm], | ||
], | ||
}, | ||
hre, | ||
); | ||
|
||
if (res === 0) { | ||
console.log('Deposits contract successfully verified! 👍'); | ||
} | ||
|
||
return res; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/* eslint no-console: 0 */ | ||
import { subtask, task, types } from 'hardhat/config'; | ||
import { exit } from 'process'; | ||
|
||
import { verify, arraysEqualPredicate } from './verification/verifiable'; | ||
|
||
import { PROPOSALS_CID } from '../env'; | ||
import { PROPOSALS, ZERO_ADDRESS } from '../helpers/constants'; | ||
import { Proposals } from '../typechain'; | ||
|
||
task('proposals-check', 'Check proposals at particular addres') | ||
.addParam('address', 'Proposals contracts address') | ||
.addParam('contractName', 'Name of the contract', PROPOSALS) | ||
.addFlag('verify', 'Verifies contract storage against expected values') | ||
.addOptionalParam('auth', 'Expected Auth contract address') | ||
.addOptionalParam('cid', 'Expected cid', PROPOSALS_CID) | ||
.addOptionalParam('epochs', 'Expected epochs contract address', ZERO_ADDRESS) | ||
.addOptionalParam( | ||
'epoch', | ||
'Epoch for which to query for proposal addresses', | ||
undefined, | ||
types.int, | ||
) | ||
.addParam('proposals', 'Comma separated list of expected proposals') | ||
.setAction(async (taskArgs, { ethers, getNamedAccounts, run }) => { | ||
console.log('Querying contract deployed at:', taskArgs.address); | ||
const { deployer } = await getNamedAccounts(); | ||
const target: Proposals = await ethers.getContractAt( | ||
taskArgs.contractName, | ||
taskArgs.address, | ||
deployer, | ||
); | ||
|
||
const auth = await target.auth(); | ||
const cid = await target.cid(); | ||
const epochs = await target.epochs(); | ||
|
||
console.log('auth: ', auth); | ||
console.log('cid: ', cid); | ||
console.log('epochs: ', epochs); | ||
|
||
if (taskArgs.epoch !== undefined) { | ||
console.log( | ||
`proposals at epoch ${taskArgs.epoch}: `, | ||
await target.getProposalAddresses(taskArgs.epoch), | ||
); | ||
} | ||
|
||
if (taskArgs.verify) { | ||
const result = await run('proposals-check:verify', taskArgs); | ||
exit(result); | ||
} | ||
}); | ||
|
||
subtask('proposals-check:verify', 'Verify Proposals contract') | ||
.addParam('address', 'proposals contract address') | ||
.addParam('auth', 'Expected Auth contract address') | ||
.addParam('epochs', 'Expected Epochs contract address') | ||
.addParam('cid', 'Expected cid') | ||
.addParam('epoch', 'Epoch at which to query for proposals', 100, types.int) | ||
.addParam('proposals', 'Comma separated list of expected proposals') | ||
.setAction(async (taskArgs, hre) => { | ||
console.log('Veryfing Proposals contract'); | ||
|
||
const res = await verify( | ||
{ | ||
address: taskArgs.address, | ||
contractName: PROPOSALS, | ||
properties: [ | ||
['auth', taskArgs.auth], | ||
['cid', taskArgs.cid], | ||
['epochs', taskArgs.epochs], | ||
[ | ||
['getProposalAddresses', [taskArgs.epoch]], | ||
arraysEqualPredicate(taskArgs.proposals.split(',')), | ||
], | ||
], | ||
}, | ||
hre, | ||
); | ||
|
||
if (res === 0) { | ||
console.log('Proposals contract successfully verified! 👍'); | ||
} | ||
|
||
return res; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/* eslint no-console: 0 */ | ||
import { Contract } from 'ethers'; | ||
import { HardhatRuntimeEnvironment } from 'hardhat/types'; | ||
|
||
type PropertyPredicateT = (value: any) => boolean; | ||
type VerifiablePropertyT = [string | [string, [any]], PropertyPredicateT | any]; | ||
|
||
interface Verifiable { | ||
address: string; | ||
contractName: string; | ||
properties: Array<VerifiablePropertyT>; | ||
} | ||
|
||
async function getContract<ContractT extends Contract>( | ||
verifiable: Verifiable, | ||
hre: HardhatRuntimeEnvironment, | ||
): Promise<ContractT> { | ||
return hre.ethers.getContractAt(verifiable.contractName, verifiable.address); | ||
} | ||
|
||
function propertyOf<ContractT>(property: keyof ContractT) { | ||
return property; | ||
} | ||
|
||
function defaultPredicate(expected: any) { | ||
return (actual: any) => { | ||
return actual === expected; | ||
}; | ||
} | ||
|
||
export function arraysEqualPredicate(expected: [any], shouldCheckOrder = false) { | ||
return (a: [any]): boolean => { | ||
const actual = [...a]; // make a copy | ||
|
||
if (expected.length !== actual.length) return false; | ||
|
||
if (!shouldCheckOrder) { | ||
expected.sort(); | ||
actual.sort(); | ||
} | ||
|
||
return expected.every((elem, index) => { | ||
console.debug('Expected: %s, actual: %s', elem, actual[index]); | ||
return elem === actual[index]; | ||
}); | ||
}; | ||
} | ||
|
||
function predicateToStr(p: PropertyPredicateT | any): string { | ||
if (p instanceof Function) { | ||
return '<custom predicate>'; | ||
} | ||
|
||
return p.toString(); | ||
} | ||
|
||
/* eslint-disable no-console */ | ||
export async function verify<ContractT extends Contract>( | ||
verifiable: Verifiable, | ||
hre: HardhatRuntimeEnvironment, | ||
): Promise<number> { | ||
const contract: ContractT = await getContract(verifiable, hre); | ||
|
||
let errors = 0; | ||
|
||
for await (const [property, predicateOrVal] of verifiable.properties) { | ||
let propertyFunc; | ||
let propertyName: string; | ||
if (typeof property === 'string') { | ||
propertyName = property as string; | ||
propertyFunc = async () => contract[propertyOf<ContractT>(propertyName)](); | ||
} else { | ||
let args: [any]; | ||
[propertyName, args] = property as [string, [any]]; | ||
propertyFunc = async () => contract[propertyOf<ContractT>(propertyName)](...args); | ||
} | ||
|
||
const propertyValue = await propertyFunc(); | ||
const predicate = | ||
predicateOrVal instanceof Function ? predicateOrVal : defaultPredicate(predicateOrVal); | ||
|
||
console.debug( | ||
'Checking %s. Expected: %s. Value: %s', | ||
propertyName, | ||
predicateToStr(predicateOrVal), | ||
propertyValue, | ||
); | ||
|
||
if (!predicate(propertyValue)) { | ||
console.error('Verification failed for %s.', propertyName); | ||
errors += 1; | ||
} | ||
} | ||
|
||
return errors; | ||
} |
Oops, something went wrong.