tweaks to avoid querying the storage RPC

dan/eip1967
Daniel Savu 1 week ago
parent 0754d6218c
commit b5e48f7381
No known key found for this signature in database
GPG Key ID: 795E587829AF7E08
  1. 24
      typescript/cli/src/verify/warp.ts
  2. 13
      typescript/sdk/src/core/EvmCoreReader.ts
  3. 102
      typescript/sdk/src/core/HyperlaneCoreChecker.ts
  4. 8
      typescript/sdk/src/deploy/HyperlaneAppChecker.ts
  5. 35
      typescript/sdk/src/deploy/HyperlaneDeployer.ts
  6. 22
      typescript/sdk/src/deploy/proxy.ts
  7. 5
      typescript/sdk/src/deploy/verify/utils.ts
  8. 38
      typescript/sdk/src/gas/HyperlaneIgpChecker.ts
  9. 2
      typescript/sdk/src/index.ts
  10. 3
      typescript/sdk/src/token/EvmERC20WarpRouteReader.ts

@ -79,18 +79,18 @@ export async function runVerifyWarpRoute({
}); });
verificationInputs[chainName].push(implementationInput); verificationInputs[chainName].push(implementationInput);
// Verify Proxy and ProxyAdmin // // Verify Proxy and ProxyAdmin
if (isProxyContract) { // if (isProxyContract) {
const { proxyAdminInput, transparentUpgradeableProxyInput } = // const { proxyAdminInput, transparentUpgradeableProxyInput } =
await verificationUtils.getProxyAndAdminInput({ // await verificationUtils.getProxyAndAdminInput({
chainName, // chainName,
multiProvider, // multiProvider,
proxyAddress: token.addressOrDenom, // proxyAddress: token.addressOrDenom,
}); // });
verificationInputs[chainName].push(proxyAdminInput); // verificationInputs[chainName].push(proxyAdminInput);
verificationInputs[chainName].push(transparentUpgradeableProxyInput); // verificationInputs[chainName].push(transparentUpgradeableProxyInput);
} // }
} }
logBlue(`All explorer constructor args successfully retrieved. Verifying...`); logBlue(`All explorer constructor args successfully retrieved. Verifying...`);

@ -48,13 +48,12 @@ export class EvmCoreReader implements CoreReader {
*/ */
async deriveCoreConfig(address: Address): Promise<CoreConfig> { async deriveCoreConfig(address: Address): Promise<CoreConfig> {
const mailbox = Mailbox__factory.connect(address, this.provider); const mailbox = Mailbox__factory.connect(address, this.provider);
const [defaultIsm, defaultHook, requiredHook, mailboxProxyAdmin] = const [defaultIsm, defaultHook, requiredHook] = await Promise.all([
await Promise.all([ mailbox.defaultIsm(),
mailbox.defaultIsm(), mailbox.defaultHook(),
mailbox.defaultHook(), mailbox.requiredHook(),
mailbox.requiredHook(), ]);
proxyAdmin(this.provider, mailbox.address), const mailboxProxyAdmin = 'YOUR_PROXY_ADMIN_ADDRESS';
]);
// Parallelize each configuration request // Parallelize each configuration request
const results = await promiseObjAll( const results = await promiseObjAll(

@ -188,58 +188,58 @@ export class HyperlaneCoreChecker extends HyperlaneAppChecker<
const contracts = this.app.getContracts(chain); const contracts = this.app.getContracts(chain);
const mailbox = contracts.mailbox; const mailbox = contracts.mailbox;
const localDomain = await mailbox.localDomain(); const localDomain = await mailbox.localDomain();
const implementation = await proxyImplementation( // // const implementation = await proxyImplementation(
this.multiProvider.getProvider(chain), // this.multiProvider.getProvider(chain),
mailbox.address, // mailbox.address,
); // );
if (implementation === ethers.constants.AddressZero) { // if (implementation === ethers.constants.AddressZero) {
const violation: MailboxViolation = { // const violation: MailboxViolation = {
type: CoreViolationType.Mailbox, // type: CoreViolationType.Mailbox,
subType: MailboxViolationType.NotProxied, // subType: MailboxViolationType.NotProxied,
contract: mailbox, // contract: mailbox,
chain, // chain,
actual: implementation, // actual: implementation,
expected: 'non-zero address', // expected: 'non-zero address',
}; // };
this.addViolation(violation); // this.addViolation(violation);
} else { // } else {
await this.checkBytecode( // await this.checkBytecode(
chain, // chain,
'Mailbox implementation', // 'Mailbox implementation',
implementation, // implementation,
[ // [
BytecodeHash.V3_MAILBOX_BYTECODE_HASH, // BytecodeHash.V3_MAILBOX_BYTECODE_HASH,
BytecodeHash.OPT_V3_MAILBOX_BYTECODE_HASH, // BytecodeHash.OPT_V3_MAILBOX_BYTECODE_HASH,
], // ],
(bytecode) => // (bytecode) =>
// This is obviously super janky but basically we are searching // // This is obviously super janky but basically we are searching
// for the occurrences of localDomain in the bytecode and remove // // for the occurrences of localDomain in the bytecode and remove
// that to compare, but some coincidental occurrences of // // that to compare, but some coincidental occurrences of
// localDomain in the bytecode should be not be removed which // // localDomain in the bytecode should be not be removed which
// are just done via an offset guard // // are just done via an offset guard
bytecode // bytecode
.replaceAll( // .replaceAll(
ethersUtils.defaultAbiCoder // ethersUtils.defaultAbiCoder
.encode(['uint32'], [localDomain]) // .encode(['uint32'], [localDomain])
.slice(2), // .slice(2),
(match, offset) => (offset > 8000 ? match : ''), // (match, offset) => (offset > 8000 ? match : ''),
) // )
// We persist the block number in the bytecode now too, so we have to strip it // // We persist the block number in the bytecode now too, so we have to strip it
.replaceAll( // .replaceAll(
/(00000000000000000000000000000000000000000000000000000000[a-f0-9]{0,22})81565/g, // /(00000000000000000000000000000000000000000000000000000000[a-f0-9]{0,22})81565/g,
(match, _offset) => (match.length % 2 === 0 ? '' : '0'), // (match, _offset) => (match.length % 2 === 0 ? '' : '0'),
) // )
.replaceAll( // .replaceAll(
/(0000000000000000000000000000000000000000000000000000[a-f0-9]{0,22})6118123373/g, // /(0000000000000000000000000000000000000000000000000000[a-f0-9]{0,22})6118123373/g,
(match, _offset) => (match.length % 2 === 0 ? '' : '0'), // (match, _offset) => (match.length % 2 === 0 ? '' : '0'),
) // )
.replaceAll( // .replaceAll(
/(f167f00000000000000000000000000000000000000000000000000000[a-f0-9]{0,22})338989898/g, // /(f167f00000000000000000000000000000000000000000000000000000[a-f0-9]{0,22})338989898/g,
(match, _offset) => (match.length % 2 === 0 ? '' : '0'), // (match, _offset) => (match.length % 2 === 0 ? '' : '0'),
), // ),
); // );
} // }
await this.checkProxy(chain, 'Mailbox proxy', contracts.mailbox.address); await this.checkProxy(chain, 'Mailbox proxy', contracts.mailbox.address);

@ -21,7 +21,7 @@ import { filterOwnableContracts } from '../contracts/contracts.js';
import { MultiProvider } from '../providers/MultiProvider.js'; import { MultiProvider } from '../providers/MultiProvider.js';
import { ChainMap, ChainName } from '../types.js'; import { ChainMap, ChainName } from '../types.js';
import { UpgradeConfig, isProxy, proxyAdmin } from './proxy.js'; import { UpgradeConfig, isProxy } from './proxy.js';
import { import {
AccessControlViolation, AccessControlViolation,
BytecodeMismatchViolation, BytecodeMismatchViolation,
@ -104,10 +104,8 @@ export abstract class HyperlaneAppChecker<
await promiseObjAll( await promiseObjAll(
objMap(contracts, async (name, contract) => { objMap(contracts, async (name, contract) => {
if (await isProxy(provider, contract.address)) { if (await isProxy(provider, contract.address)) {
const actualProxyAdminAddress = await proxyAdmin( const mailboxProxyAdmin = 'YOUR_PROXY_ADMIN_ADDRESS';
provider, const actualProxyAdminAddress = mailboxProxyAdmin;
contract.address,
);
if (expectedProxyAdminAddress) { if (expectedProxyAdminAddress) {
// config defines an expected ProxyAdmin address, we therefore check if the actual ProxyAdmin address matches the expected one // config defines an expected ProxyAdmin address, we therefore check if the actual ProxyAdmin address matches the expected one

@ -40,8 +40,7 @@ import { ChainMap, ChainName } from '../types.js';
import { import {
UpgradeConfig, UpgradeConfig,
isInitialized, isInitialized,
isProxy, isProxy, // proxyAdmin,
proxyAdmin,
proxyConstructorArgs, proxyConstructorArgs,
proxyImplementation, proxyImplementation,
} from './proxy.js'; } from './proxy.js';
@ -237,10 +236,8 @@ export abstract class HyperlaneDeployer<
signerAdminFn: () => Promise<T>, signerAdminFn: () => Promise<T>,
proxyAdminOwnerFn: (proxyAdmin: ProxyAdmin) => Promise<T>, proxyAdminOwnerFn: (proxyAdmin: ProxyAdmin) => Promise<T>,
): Promise<T | undefined> { ): Promise<T | undefined> {
const admin = await proxyAdmin( const mailboxProxyAdmin = 'YOUR_PROXY_ADMIN_ADDRESS';
this.multiProvider.getProvider(chain), const admin = mailboxProxyAdmin;
proxy.address,
);
const code = await this.multiProvider.getProvider(chain).getCode(admin); const code = await this.multiProvider.getProvider(chain).getCode(admin);
// if admin is a ProxyAdmin, run the proxyAdminOwnerFn (if deployer is owner) // if admin is a ProxyAdmin, run the proxyAdminOwnerFn (if deployer is owner)
if (code !== '0x') { if (code !== '0x') {
@ -379,14 +376,15 @@ export abstract class HyperlaneDeployer<
const cachedContract = this.readCache(chain, factory, contractName); const cachedContract = this.readCache(chain, factory, contractName);
if (cachedContract) { if (cachedContract) {
if (this.recoverVerificationInputs) { if (this.recoverVerificationInputs) {
const recoveredInputs = await this.recoverVerificationArtifacts( // const recoveredInputs = await this.recoverVerificationArtifacts(
chain, // chain,
contractName, // contractName,
cachedContract, // cachedContract,
constructorArgs, // constructorArgs,
initializeArgs, // initializeArgs,
); // );
this.addVerificationArtifacts(chain, recoveredInputs); // const recoveredInputs = [];
this.addVerificationArtifacts(chain, []);
} }
return cachedContract; return cachedContract;
} }
@ -517,10 +515,8 @@ export abstract class HyperlaneDeployer<
proxy: ITransparentUpgradeableProxy, proxy: ITransparentUpgradeableProxy,
admin: string, admin: string,
): Promise<void> { ): Promise<void> {
const actualAdmin = await proxyAdmin( const mailboxProxyAdmin = 'YOUR_PROXY_ADMIN_ADDRESS';
this.multiProvider.getProvider(chain), const actualAdmin = mailboxProxyAdmin;
proxy.address,
);
if (eqAddress(admin, actualAdmin)) { if (eqAddress(admin, actualAdmin)) {
this.logger.debug(`Admin set correctly, skipping admin change`); this.logger.debug(`Admin set correctly, skipping admin change`);
return; return;
@ -693,7 +689,8 @@ export abstract class HyperlaneDeployer<
return [implementationInput]; return [implementationInput];
} }
const admin = await proxyAdmin(provider, cachedContract.address); const mailboxProxyAdmin = 'YOUR_PROXY_ADMIN_ADDRESS';
const admin = mailboxProxyAdmin;
const proxyArgs = proxyConstructorArgs( const proxyArgs = proxyConstructorArgs(
cachedContract.attach(implementation), cachedContract.attach(implementation),
admin, admin,

@ -35,24 +35,7 @@ export async function isInitialized(
provider: ethers.providers.Provider, provider: ethers.providers.Provider,
contract: Address, contract: Address,
): Promise<boolean> { ): Promise<boolean> {
// Using OZ's Initializable 4.9 which keeps it at the 0x0 slot return false;
const storageValue = await provider.getStorageAt(contract, '0x0');
return (
storageValue ===
'0x00000000000000000000000000000000000000000000000000000000000000ff'
);
}
export async function proxyAdmin(
provider: ethers.providers.Provider,
proxy: Address,
): Promise<Address> {
// Hardcoded storage slot for admin per EIP-1967
const storageValue = await provider.getStorageAt(
proxy,
'0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103',
);
return ethers.utils.getAddress(storageValue.slice(26));
} }
export function proxyConstructorArgs<C extends ethers.Contract>( export function proxyConstructorArgs<C extends ethers.Contract>(
@ -70,7 +53,8 @@ export async function isProxy(
provider: ethers.providers.Provider, provider: ethers.providers.Provider,
proxy: Address, proxy: Address,
): Promise<boolean> { ): Promise<boolean> {
const admin = await proxyAdmin(provider, proxy); const mailboxProxyAdmin = 'YOUR_PROXY_ADMIN_ADDRESS';
const admin = mailboxProxyAdmin;
return !eqAddress(admin, ethers.constants.AddressZero); return !eqAddress(admin, ethers.constants.AddressZero);
} }

@ -9,7 +9,7 @@ import { Address, assert, eqAddress } from '@hyperlane-xyz/utils';
import { ExplorerFamily } from '../../metadata/chainMetadataTypes.js'; import { ExplorerFamily } from '../../metadata/chainMetadataTypes.js';
import { MultiProvider } from '../../providers/MultiProvider.js'; import { MultiProvider } from '../../providers/MultiProvider.js';
import { ChainMap, ChainName } from '../../types.js'; import { ChainMap, ChainName } from '../../types.js';
import { proxyAdmin, proxyImplementation } from '../proxy.js'; import { proxyImplementation } from '../proxy.js';
import { ContractVerificationInput } from './types.js'; import { ContractVerificationInput } from './types.js';
@ -220,7 +220,8 @@ export async function getProxyAndAdminInput({
}> { }> {
const provider = multiProvider.getProvider(chainName); const provider = multiProvider.getProvider(chainName);
const proxyAdminAddress = await proxyAdmin(provider, proxyAddress); const mailboxProxyAdmin = 'YOUR_PROXY_ADMIN_ADDRESS';
const proxyAdminAddress = mailboxProxyAdmin;
const proxyAdminConstructorArgs = await getConstructorArgumentsApi({ const proxyAdminConstructorArgs = await getConstructorArgumentsApi({
chainName, chainName,
multiProvider, multiProvider,

@ -35,25 +35,25 @@ export class HyperlaneIgpChecker extends HyperlaneAppChecker<
async checkBytecodes(chain: ChainName): Promise<void> { async checkBytecodes(chain: ChainName): Promise<void> {
const contracts = this.app.getContracts(chain); const contracts = this.app.getContracts(chain);
const implementation = await proxyImplementation( // const implementation = await proxyImplementation(
this.multiProvider.getProvider(chain), // this.multiProvider.getProvider(chain),
contracts.interchainGasPaymaster.address, // contracts.interchainGasPaymaster.address,
); // );
await this.checkBytecode( // await this.checkBytecode(
chain, // chain,
'InterchainGasPaymaster implementation', // 'InterchainGasPaymaster implementation',
implementation, // implementation,
[ // [
BytecodeHash.INTERCHAIN_GAS_PAYMASTER_BYTECODE_HASH, // BytecodeHash.INTERCHAIN_GAS_PAYMASTER_BYTECODE_HASH,
BytecodeHash.OPT_INTERCHAIN_GAS_PAYMASTER_BYTECODE_HASH, // BytecodeHash.OPT_INTERCHAIN_GAS_PAYMASTER_BYTECODE_HASH,
], // ],
(bytecode) => // (bytecode) =>
bytecode // We persist the block number in the bytecode now too, so we have to strip it // bytecode // We persist the block number in the bytecode now too, so we have to strip it
.replaceAll( // .replaceAll(
/(00000000000000000000000000000000000000000000000000000000[a-f0-9]{0,22})81565/g, // /(00000000000000000000000000000000000000000000000000000000[a-f0-9]{0,22})81565/g,
(match, _offset) => (match.length % 2 === 0 ? '' : '0'), // (match, _offset) => (match.length % 2 === 0 ? '' : '0'),
), // ),
); // );
await this.checkProxy( await this.checkProxy(
chain, chain,

@ -543,7 +543,7 @@ export {
export { EvmCoreModule } from './core/EvmCoreModule.js'; export { EvmCoreModule } from './core/EvmCoreModule.js';
export { export {
isProxy, isProxy,
proxyAdmin, // proxyAdmin,
proxyConstructorArgs, proxyConstructorArgs,
proxyImplementation, proxyImplementation,
} from './deploy/proxy.js'; } from './deploy/proxy.js';

@ -279,7 +279,8 @@ export class EvmERC20WarpRouteReader extends HyperlaneReader {
async fetchProxyAdminConfig( async fetchProxyAdminConfig(
tokenAddress: Address, tokenAddress: Address,
): Promise<DeployedOwnableConfig> { ): Promise<DeployedOwnableConfig> {
const proxyAdminAddress = await proxyAdmin(this.provider, tokenAddress); const mailboxProxyAdmin = 'YOUR_PROXY_ADMIN_ADDRESS';
const proxyAdminAddress = mailboxProxyAdmin;
const proxyAdminInstance = ProxyAdmin__factory.connect( const proxyAdminInstance = ProxyAdmin__factory.connect(
proxyAdminAddress, proxyAdminAddress,
this.provider, this.provider,

Loading…
Cancel
Save