Skip to content

Commit

Permalink
feat: embed package version in deployed bytecode (#4518)
Browse files Browse the repository at this point in the history
### Description

Embed NPM package version in all deployed contracts bytecode. Follows
[similar pattern to published CLI
version](https://github.com/hyperlane-xyz/hyperlane-monorepo/blob/3010e36ec9ac981fb0e760841c2e9b6a4dde1691/typescript/cli/src/version.ts#L0-L1).

Should not be conflated with `Mailbox.VERSION` used for message
encoding.

### Drive-by Changes

Unfixes solidity NPM package version from typescript packages

### Backward compatibility

No, only applies to new deployments or upgrades

### Testing

Tested [changeset
glob](https://changesets-docs.vercel.app/fixed-packages#using-glob-expressions)
```ts
console.log(micromatch(['@hyperlane-xyz/sdk', '@hyperlane-xyz/core', '@hyperlane-xyz/cli'], ['@hyperlane-xyz/!(core)|*']));
['@hyperlane-xyz/sdk', '@hyperlane-xyz/cli']
```

Added test that version function is on ABI
  • Loading branch information
yorhodes authored Oct 3, 2024
1 parent e2b5a4c commit c5c217f
Show file tree
Hide file tree
Showing 27 changed files with 443 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [["@hyperlane-xyz/*"]],
"fixed": [["@hyperlane-xyz/!(core)|*"]],
"linked": [],
"access": "public",
"baseBranch": "main",
Expand Down
5 changes: 5 additions & 0 deletions .changeset/silent-crabs-visit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperlane-xyz/core': minor
---

Embed NPM package version in bytecode constant
16 changes: 16 additions & 0 deletions solidity/bytecodeversion.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash

FILEPATH="contracts/PackageVersioned.sol"
TEMPFILE=$(mktemp)

# writes all but the last 2 lines to the temp file
head -n $(($(wc -l < $FILEPATH) - 2)) $FILEPATH > $TEMPFILE

# writes generated last 2 lines to the temp file
cat <<EOF >> $TEMPFILE
string public constant PACKAGE_VERSION = "$npm_package_version";
}
EOF

# overwrite the original file with the temp file
cat $TEMPFILE > $FILEPATH
4 changes: 3 additions & 1 deletion solidity/contracts/AttributeCheckpointFraud.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

import {PackageVersioned} from "contracts/PackageVersioned.sol";
import {TREE_DEPTH} from "./libs/Merkle.sol";
import {CheckpointLib, Checkpoint} from "./libs/CheckpointLib.sol";
import {CheckpointFraudProofs} from "./CheckpointFraudProofs.sol";
Expand All @@ -26,7 +27,8 @@ struct Attribution {
* @title AttributeCheckpointFraud
* @dev The AttributeCheckpointFraud contract is used to attribute fraud to a specific ECDSA checkpoint signer.
*/
contract AttributeCheckpointFraud is Ownable {

contract AttributeCheckpointFraud is Ownable, PackageVersioned {
using CheckpointLib for Checkpoint;
using Address for address;

Expand Down
4 changes: 3 additions & 1 deletion solidity/contracts/CheckpointFraudProofs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import {MerkleLib, TREE_DEPTH} from "./libs/Merkle.sol";
import {MerkleTreeHook} from "./hooks/MerkleTreeHook.sol";
import {IMailbox} from "./interfaces/IMailbox.sol";

import {PackageVersioned} from "./PackageVersioned.sol";

struct StoredIndex {
uint32 index;
bool exists;
}

contract CheckpointFraudProofs {
contract CheckpointFraudProofs is PackageVersioned {
using CheckpointLib for Checkpoint;
using Address for address;

Expand Down
9 changes: 8 additions & 1 deletion solidity/contracts/Mailbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,19 @@ import {IInterchainSecurityModule, ISpecifiesInterchainSecurityModule} from "./i
import {IPostDispatchHook} from "./interfaces/hooks/IPostDispatchHook.sol";
import {IMessageRecipient} from "./interfaces/IMessageRecipient.sol";
import {IMailbox} from "./interfaces/IMailbox.sol";
import {PackageVersioned} from "contracts/PackageVersioned.sol";

// ============ External Imports ============
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract Mailbox is IMailbox, Indexed, Versioned, OwnableUpgradeable {
contract Mailbox is
IMailbox,
Indexed,
Versioned,
OwnableUpgradeable,
PackageVersioned
{
// ============ Libraries ============

using Message for bytes;
Expand Down
11 changes: 11 additions & 0 deletions solidity/contracts/PackageVersioned.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.6.11;

/**
* @title PackageVersioned
* @notice Package version getter for contracts
**/
abstract contract PackageVersioned {
// GENERATED CODE - DO NOT EDIT
string public constant PACKAGE_VERSION = "5.3.0";
}
5 changes: 4 additions & 1 deletion solidity/contracts/avs/ECDSAStakeRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {IDelegationManager} from "../interfaces/avs/vendored/IDelegationManager.
import {ISignatureUtils} from "../interfaces/avs/vendored/ISignatureUtils.sol";
import {IServiceManager} from "../interfaces/avs/vendored/IServiceManager.sol";

import {PackageVersioned} from "../PackageVersioned.sol";

import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {CheckpointsUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/CheckpointsUpgradeable.sol";
import {SignatureCheckerUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/SignatureCheckerUpgradeable.sol";
Expand All @@ -19,7 +21,8 @@ import {IERC1271Upgradeable} from "@openzeppelin/contracts-upgradeable/interface
contract ECDSAStakeRegistry is
IERC1271Upgradeable,
OwnableUpgradeable,
ECDSAStakeRegistryStorage
ECDSAStakeRegistryStorage,
PackageVersioned
{
using SignatureCheckerUpgradeable for address;
using CheckpointsUpgradeable for CheckpointsUpgradeable.History;
Expand Down
3 changes: 2 additions & 1 deletion solidity/contracts/avs/HyperlaneServiceManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ import {IAVSDirectory} from "../interfaces/avs/vendored/IAVSDirectory.sol";
import {IRemoteChallenger} from "../interfaces/avs/IRemoteChallenger.sol";
import {ISlasher} from "../interfaces/avs/vendored/ISlasher.sol";
import {ECDSAServiceManagerBase} from "./ECDSAServiceManagerBase.sol";
import {PackageVersioned} from "contracts/PackageVersioned.sol";

contract HyperlaneServiceManager is ECDSAServiceManagerBase {
contract HyperlaneServiceManager is ECDSAServiceManagerBase, PackageVersioned {
// ============ Libraries ============

using EnumerableMapEnrollment for EnumerableMapEnrollment.AddressToEnrollmentMap;
Expand Down
3 changes: 2 additions & 1 deletion solidity/contracts/client/MailboxClient.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import {IMailbox} from "../interfaces/IMailbox.sol";
import {IPostDispatchHook} from "../interfaces/hooks/IPostDispatchHook.sol";
import {IInterchainSecurityModule} from "../interfaces/IInterchainSecurityModule.sol";
import {Message} from "../libs/Message.sol";
import {PackageVersioned} from "../PackageVersioned.sol";

// ============ External Imports ============
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

abstract contract MailboxClient is OwnableUpgradeable {
abstract contract MailboxClient is OwnableUpgradeable, PackageVersioned {
using Message for bytes;

IMailbox public immutable mailbox;
Expand Down
3 changes: 2 additions & 1 deletion solidity/contracts/hooks/igp/StorageGasOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity >=0.8.0;

// ============ Internal Imports ============
import {IGasOracle} from "../../interfaces/IGasOracle.sol";
import {PackageVersioned} from "../../PackageVersioned.sol";

// ============ External Imports ============
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
Expand All @@ -12,7 +13,7 @@ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
* @dev This contract is intended to be owned by an address that will
* update the stored remote gas data.
*/
contract StorageGasOracle is IGasOracle, Ownable {
contract StorageGasOracle is IGasOracle, Ownable, PackageVersioned {
// ============ Public Storage ============

/// @notice Keyed by remote domain, gas data on that remote domain.
Expand Down
6 changes: 5 additions & 1 deletion solidity/contracts/hooks/libs/AbstractPostDispatchHook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ pragma solidity >=0.8.0;
// ============ Internal Imports ============
import {StandardHookMetadata} from "./StandardHookMetadata.sol";
import {IPostDispatchHook} from "../../interfaces/hooks/IPostDispatchHook.sol";
import {PackageVersioned} from "../../PackageVersioned.sol";

/**
* @title AbstractPostDispatch
* @notice Abstract post dispatch hook supporting the current global hook metadata variant.
*/
abstract contract AbstractPostDispatchHook is IPostDispatchHook {
abstract contract AbstractPostDispatchHook is
IPostDispatchHook,
PackageVersioned
{
using StandardHookMetadata for bytes;

// ============ External functions ============
Expand Down
3 changes: 2 additions & 1 deletion solidity/contracts/isms/NoopIsm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
pragma solidity >=0.8.0;

import {IInterchainSecurityModule} from "../interfaces/IInterchainSecurityModule.sol";
import {PackageVersioned} from "contracts/PackageVersioned.sol";

contract NoopIsm is IInterchainSecurityModule {
contract NoopIsm is IInterchainSecurityModule, PackageVersioned {
uint8 public constant override moduleType = uint8(Types.NULL);

function verify(
Expand Down
8 changes: 7 additions & 1 deletion solidity/contracts/isms/PausableIsm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

// ============ Internal Imports ============
import {IInterchainSecurityModule} from "../interfaces/IInterchainSecurityModule.sol";
import {PackageVersioned} from "contracts/PackageVersioned.sol";

contract PausableIsm is IInterchainSecurityModule, Ownable, Pausable {
contract PausableIsm is
IInterchainSecurityModule,
Ownable,
Pausable,
PackageVersioned
{
uint8 public constant override moduleType = uint8(Types.NULL);

constructor(address owner) Ownable() Pausable() {
Expand Down
3 changes: 2 additions & 1 deletion solidity/contracts/isms/TrustedRelayerIsm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ pragma solidity >=0.8.0;
import {IInterchainSecurityModule} from "../interfaces/IInterchainSecurityModule.sol";
import {Message} from "../libs/Message.sol";
import {Mailbox} from "../Mailbox.sol";
import {PackageVersioned} from "contracts/PackageVersioned.sol";

contract TrustedRelayerIsm is IInterchainSecurityModule {
contract TrustedRelayerIsm is IInterchainSecurityModule, PackageVersioned {
using Message for bytes;

uint8 public immutable moduleType = uint8(Types.NULL);
Expand Down
3 changes: 2 additions & 1 deletion solidity/contracts/isms/aggregation/StaticAggregationIsm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ pragma solidity >=0.8.0;
import {AbstractAggregationIsm} from "./AbstractAggregationIsm.sol";
import {AggregationIsmMetadata} from "../../isms/libs/AggregationIsmMetadata.sol";
import {MetaProxy} from "../../libs/MetaProxy.sol";
import {PackageVersioned} from "contracts/PackageVersioned.sol";

/**
* @title StaticAggregationIsm
* @notice Manages per-domain m-of-n ISM sets that are used to verify
* interchain messages.
*/
contract StaticAggregationIsm is AbstractAggregationIsm {
contract StaticAggregationIsm is AbstractAggregationIsm, PackageVersioned {
// ============ Public Functions ============

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;

// ============ Internal Imports ============
import {StaticAggregationIsm} from "./StaticAggregationIsm.sol";
import {StaticThresholdAddressSetFactory} from "../../libs/StaticAddressSetFactory.sol";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ pragma solidity >=0.8.0;
import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol";
import {LibBit} from "../../libs/LibBit.sol";
import {Message} from "../../libs/Message.sol";
import {PackageVersioned} from "contracts/PackageVersioned.sol";

// ============ External Imports ============

import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
Expand All @@ -31,7 +31,8 @@ import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Ini
*/
abstract contract AbstractMessageIdAuthorizedIsm is
IInterchainSecurityModule,
Initializable
Initializable,
PackageVersioned
{
using Address for address payable;
using LibBit for uint256;
Expand Down
3 changes: 2 additions & 1 deletion solidity/contracts/isms/multisig/AbstractMultisigIsm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityMod
import {IMultisigIsm} from "../../interfaces/isms/IMultisigIsm.sol";
import {Message} from "../../libs/Message.sol";
import {MerkleLib} from "../../libs/Merkle.sol";
import {PackageVersioned} from "../../PackageVersioned.sol";

/**
* @title AbstractMultisig
Expand All @@ -29,7 +30,7 @@ import {MerkleLib} from "../../libs/Merkle.sol";
* for concrete implementations of `digest` and `signatureAt`.
* @dev See ./StaticMultisigIsm.sol for concrete implementations.
*/
abstract contract AbstractMultisig {
abstract contract AbstractMultisig is PackageVersioned {
/**
* @notice Returns the digest to be used for signature verification.
* @param _metadata ABI encoded module metadata
Expand Down
7 changes: 6 additions & 1 deletion solidity/contracts/isms/routing/DomainRoutingIsm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@ import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityMod
import {Message} from "../../libs/Message.sol";
import {TypeCasts} from "../../libs/TypeCasts.sol";
import {EnumerableMapExtended} from "../../libs/EnumerableMapExtended.sol";
import {PackageVersioned} from "../../PackageVersioned.sol";

/**
* @title DomainRoutingIsm
*/
contract DomainRoutingIsm is AbstractRoutingIsm, OwnableUpgradeable {
contract DomainRoutingIsm is
AbstractRoutingIsm,
OwnableUpgradeable,
PackageVersioned
{
using EnumerableMapExtended for EnumerableMapExtended.UintToBytes32Map;
using Message for bytes;
using TypeCasts for bytes32;
Expand Down
3 changes: 2 additions & 1 deletion solidity/contracts/isms/routing/DomainRoutingIsmFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import {DomainRoutingIsm} from "./DomainRoutingIsm.sol";
import {DefaultFallbackRoutingIsm} from "./DefaultFallbackRoutingIsm.sol";
import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol";
import {MinimalProxy} from "../../libs/MinimalProxy.sol";
import {PackageVersioned} from "../../PackageVersioned.sol";

abstract contract AbstractDomainRoutingIsmFactory {
abstract contract AbstractDomainRoutingIsmFactory is PackageVersioned {
/**
* @notice Emitted when a routing module is deployed
* @param module The deployed ISM
Expand Down
3 changes: 2 additions & 1 deletion solidity/contracts/isms/routing/InterchainAccountIsm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import {IMailbox} from "../../interfaces/IMailbox.sol";
import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol";
import {Message} from "../../libs/Message.sol";
import {InterchainAccountMessage} from "../../middleware/libs/InterchainAccountMessage.sol";
import {PackageVersioned} from "../../PackageVersioned.sol";

/**
* @title InterchainAccountIsm
*/
contract InterchainAccountIsm is AbstractRoutingIsm {
contract InterchainAccountIsm is AbstractRoutingIsm, PackageVersioned {
IMailbox private immutable mailbox;

// ============ Constructor ============
Expand Down
3 changes: 2 additions & 1 deletion solidity/contracts/libs/StaticAddressSetFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";

// ============ Internal Imports ============
import {MetaProxy} from "./MetaProxy.sol";
import {PackageVersioned} from "../PackageVersioned.sol";

abstract contract StaticThresholdAddressSetFactory {
abstract contract StaticThresholdAddressSetFactory is PackageVersioned {
// ============ Immutables ============
address public immutable implementation;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import {IStaticWeightedMultisigIsm} from "../interfaces/isms/IWeightedMultisigIs

// ============ Internal Imports ============
import {MetaProxy} from "./MetaProxy.sol";
import {PackageVersioned} from "../PackageVersioned.sol";

abstract contract StaticWeightedValidatorSetFactory {
abstract contract StaticWeightedValidatorSetFactory is PackageVersioned {
// ============ Immutables ============
address public immutable implementation;

Expand Down
12 changes: 8 additions & 4 deletions solidity/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"solidity-coverage": "^0.8.3",
"ts-generator": "^0.1.1",
"ts-node": "^10.8.0",
"tsx": "^4.19.1",
"typechain": "patch:typechain@npm%3A8.3.2#~/.yarn/patches/typechain-npm-8.3.2-b02e27439e.patch",
"typescript": "5.3.3"
},
Expand Down Expand Up @@ -63,22 +64,25 @@
],
"license": "Apache-2.0",
"scripts": {
"build": "yarn hardhat-esm compile && tsc && ./exportBuildArtifact.sh",
"build": "yarn version:bytecode && yarn hardhat-esm compile && tsc && ./exportBuildArtifact.sh",
"lint": "solhint contracts/**/*.sol",
"clean": "yarn hardhat-esm clean && rm -rf ./dist ./cache ./types ./coverage ./out ./forge-cache ./fixtures",
"coverage": "yarn fixtures && ./coverage.sh",
"docs": "forge doc",
"fixtures": "mkdir -p ./fixtures/aggregation ./fixtures/multisig",
"hardhat-esm": "NODE_OPTIONS='--experimental-loader ts-node/esm/transpile-only --no-warnings=ExperimentalWarning' hardhat --config hardhat.config.cts",
"prettier": "prettier --write ./contracts ./test",
"test": "yarn hardhat-esm test && yarn test:forge",
"test": "yarn version:exhaustive && yarn hardhat-esm test && yarn test:forge",
"test:hardhat": "yarn hardhat-esm test",
"test:forge": "yarn fixtures && forge test -vvv",
"test:ci": "yarn test:hardhat && yarn test:forge --no-match-test testFork",
"test:ci": "yarn version:changed && yarn test:hardhat && yarn test:forge --no-match-test testFork",
"gas": "forge snapshot",
"gas-ci": "yarn gas --check --tolerance 2 || (echo 'Manually update gas snapshot' && exit 1)",
"slither": "slither .",
"storage": "./storage.sh"
"storage": "./storage.sh",
"version:bytecode": "./bytecodeversion.sh",
"version:changed": "yarn version:bytecode && git diff --exit-code",
"version:exhaustive": "yarn tsx ./test/exhaustiveversion.test.ts"
},
"peerDependencies": {
"@ethersproject/abi": "*",
Expand Down
Loading

0 comments on commit c5c217f

Please sign in to comment.