Skip to content

Commit 8032690

Browse files
committed
tempo
1 parent c84d450 commit 8032690

File tree

4 files changed

+57
-17
lines changed

4 files changed

+57
-17
lines changed

contract_manager/scripts/check_proposal.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import { createHash } from "node:crypto";
99

10-
import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
10+
import { Wallet } from "@coral-xyz/anchor";
1111
import type { PythCluster } from "@pythnetwork/client/lib/cluster";
1212
import { getPythClusterApiUrl } from "@pythnetwork/client/lib/cluster";
1313
import {
@@ -21,7 +21,7 @@ import {
2121
} from "@pythnetwork/xc-admin-common";
2222
import type { AccountMeta } from "@solana/web3.js";
2323
import { Keypair, PublicKey } from "@solana/web3.js";
24-
import SquadsMesh from "@sqds/mesh";
24+
import SquadsMeshClass from "@sqds/mesh";
2525
import Web3 from "web3";
2626
import yargs from "yargs";
2727
import { hideBin } from "yargs/helpers";
@@ -32,9 +32,16 @@ import {
3232
EvmPriceFeedContract,
3333
getCodeDigestWithoutAddress,
3434
EvmWormholeContract,
35+
EvmLazerContract,
3536
} from "../src/core/contracts/evm";
3637
import { DefaultStore } from "../src/node/utils/store";
3738

39+
function getSquadsMesh() {
40+
// Handle nested default export from @sqds/mesh
41+
return (SquadsMeshClass as { default?: typeof SquadsMeshClass }).default ??
42+
SquadsMeshClass;
43+
}
44+
3845
const parser = yargs(hideBin(process.argv))
3946
.usage("Usage: $0 --cluster <cluster_id> --proposal <proposal_address>")
4047
.options({
@@ -48,14 +55,21 @@ const parser = yargs(hideBin(process.argv))
4855
demandOption: true,
4956
desc: "The proposal address to check",
5057
},
58+
"contract-type": {
59+
type: "string",
60+
demandOption: false,
61+
desc: "Type of EVM contract to verify (entropy or lazer). Required when checking EvmExecute instructions.",
62+
choices: ["entropy", "lazer"],
63+
},
5164
});
5265

5366
async function main() {
5467
const argv = await parser.argv;
5568
const cluster = argv.cluster as PythCluster;
56-
const squad = SquadsMesh.endpoint(
69+
const mesh = getSquadsMesh();
70+
const squad = mesh.endpoint(
5771
getPythClusterApiUrl(cluster),
58-
new NodeWallet(Keypair.generate()), // dummy wallet
72+
new Wallet(Keypair.generate()), // dummy wallet
5973
);
6074
const transaction = await squad.getTransaction(new PublicKey(argv.proposal));
6175
const instructions = await getProposalInstructions(squad, transaction);
@@ -148,7 +162,7 @@ async function main() {
148162
if (instruction.governanceAction instanceof EvmExecute) {
149163
// Note: it only checks for upgrade entropy contracts right now
150164
console.log(
151-
`Verifying EVMExecute on ${instruction.governanceAction.targetChainId}`,
165+
`\nVerifying EVMExecute on ${instruction.governanceAction.targetChainId}`,
152166
);
153167
for (const chain of Object.values(DefaultStore.chains)) {
154168
if (
@@ -161,9 +175,13 @@ async function main() {
161175
const callAddress = instruction.governanceAction.callAddress;
162176
const calldata = instruction.governanceAction.calldata;
163177

164-
// TODO: If we add additional EVM contracts using the executor, we need to
165-
// add some logic here to identify what kind of contract is at the call address.
166-
const contract = new EvmEntropyContract(chain, callAddress);
178+
// Get contract type from flag, default to "entropy" for backward compatibility
179+
const contractType = argv["contract-type"] ?? "entropy";
180+
181+
const contract: EvmEntropyContract | EvmLazerContract =
182+
contractType === "lazer"
183+
? new EvmLazerContract(chain, callAddress)
184+
: new EvmEntropyContract(chain, callAddress);
167185
const owner = await contract.getOwner();
168186

169187
if (

contract_manager/src/core/contracts/evm.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,43 @@ import { WormholeContract } from "./wormhole";
2929

3030
/**
3131
* Returns the keccak256 digest of the contract bytecode at the given address after replacing
32-
* any occurrences of the contract addr in the bytecode with 0.The bytecode stores the deployment
33-
* address as an immutable variable. This behavior is inherited from OpenZeppelin's implementation
34-
* of UUPSUpgradeable contract. You can read more about verification with immutable variables here:
35-
* https://docs.sourcify.dev/docs/immutables/
32+
* any occurrences of the contract addr in the bytecode with 0 and removing the metadata hash.
33+
* The bytecode stores the deployment address as an immutable variable. This behavior is inherited
34+
* from OpenZeppelin's implementation of UUPSUpgradeable contract. You can read more about
35+
* verification with immutable variables here: https://docs.sourcify.dev/docs/immutables/
36+
*
37+
* The metadata hash (last 53 bytes) is removed to allow comparison of functional bytecode only,
38+
* as metadata can differ between builds even when the contract logic is identical.
39+
*
3640
* This function can be used to verify that the contract code is the same on all chains and matches
37-
* with the deployedCode property generated by truffle builds
41+
* with the deployedCode property generated by truffle builds (excluding metadata).
3842
*/
3943
export async function getCodeDigestWithoutAddress(
4044
web3: Web3,
4145
address: string,
4246
): Promise<string> {
4347
const code = await web3.eth.getCode(address);
44-
const strippedCode = code.replaceAll(
48+
// Remove 0x prefix for processing
49+
const codeWithoutPrefix = code.replace("0x", "");
50+
51+
// Strip address occurrences (40 hex chars = 20 bytes)
52+
const strippedCode = codeWithoutPrefix.replaceAll(
4553
address.toLowerCase().replace("0x", ""),
4654
"0000000000000000000000000000000000000000",
4755
);
48-
return Web3.utils.keccak256(strippedCode);
56+
57+
// Remove metadata hash (last 53 bytes = 106 hex characters)
58+
// Metadata format: 0xa2 0x64 'i' 'p' 'f' 's' 0x58 0x20 <32 bytes hash>
59+
// Total: 53 bytes including CBOR encoding
60+
// Only remove if bytecode is long enough (at least 106 hex chars = 53 bytes)
61+
const METADATA_LENGTH_HEX = 106; // 53 bytes * 2 hex chars per byte
62+
const functionalBytecode =
63+
strippedCode.length > METADATA_LENGTH_HEX
64+
? strippedCode.slice(0, -METADATA_LENGTH_HEX)
65+
: strippedCode;
66+
67+
// Add 0x prefix back for keccak256
68+
return Web3.utils.keccak256(`0x${functionalBytecode}`);
4969
}
5070

5171
export class EvmWormholeContract extends WormholeContract {

contract_manager/src/node/utils/governance.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,9 @@ export class WormholeMultisigProposal {
282282
type SquadsMeshInstance = InstanceType<typeof SquadsMeshClass>;
283283

284284
function getSquadsMesh() {
285-
return SquadsMeshClass;
285+
// Handle nested default export from @sqds/mesh
286+
return (SquadsMeshClass as { default?: typeof SquadsMeshClass }).default ??
287+
SquadsMeshClass;
286288
}
287289

288290
export class Vault extends Storable {

governance/xc_admin/packages/xc_admin_common/src/chains.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export const RECEIVER_CHAINS = {
120120
zero_gravity: 60088,
121121
itsnotreal: 60089, // Deprecated
122122
plasma: 60090,
123-
itsnotreal2: 60091,
123+
ethereal: 60091,
124124
injective_evm: 60092,
125125
orange: 60093,
126126

0 commit comments

Comments
 (0)