-
Notifications
You must be signed in to change notification settings - Fork 3
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
Txfusion - ZKSync support #1
base: main
Are you sure you want to change the base?
Changes from 60 commits
91a2077
6fc9f02
e5724aa
0a692b3
de77dba
1e1d748
2848efe
79ceac4
04f390c
e76bbf2
e1929f8
8b2596a
e10d557
e4cef73
2d2fb15
a29df94
49c3812
82e0938
53f8e61
3022cd0
3e3637a
23f6e94
733572a
629a4c8
2c0cb55
dcaecea
36244c9
ecb3c49
2b76f59
0ea4e51
74c3a67
15de0ad
50903a6
5e36ece
4273265
d0fb3c8
9bf46bc
8b5afe3
0891c62
be23123
35260d6
b8862ae
a432fbe
b79b813
ccccce0
93af451
6753e1f
4f39405
f44d3d3
ac29b9d
b87cd54
21add82
1f0d464
9f98407
cb81ec7
8383e95
957375f
eb79bea
cff1960
075f699
52b221d
1c591a1
317f6d7
2f4cc62
dec3ef4
8cc652d
29205fb
fbc7c31
48c9b8c
570084a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// SPDX-License-Identifier: MIT OR Apache-2.0 | ||
pragma solidity >=0.8.0; | ||
|
||
interface IThresholdAddressFactory { | ||
function deploy( | ||
address[] calldata _values, | ||
uint8 _threshold | ||
) external returns (address); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// SPDX-License-Identifier: MIT OR Apache-2.0 | ||
pragma solidity >=0.8.0; | ||
|
||
// ============ Internal Imports ============ | ||
import {AbstractMultisigIsm} from "./AbstractMultisigIsm.sol"; | ||
import {AbstractMerkleRootMultisigIsm} from "./AbstractMerkleRootMultisigIsm.sol"; | ||
import {AbstractMessageIdMultisigIsm} from "./AbstractMessageIdMultisigIsm.sol"; | ||
import {IInterchainSecurityModule} from "../../interfaces/IInterchainSecurityModule.sol"; | ||
import {IThresholdAddressFactory} from "../../interfaces/IThresholdAddressFactory.sol"; | ||
import {MinimalProxy} from "../../libs/MinimalProxy.sol"; | ||
|
||
// ============ External Imports ============ | ||
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; | ||
|
||
abstract contract AbstractStorageMultisigIsm is | ||
AbstractMultisigIsm, | ||
OwnableUpgradeable | ||
{ | ||
address[] public validators; | ||
uint8 public threshold; | ||
|
||
event ValidatorsAndThresholdSet(address[] validators, uint8 threshold); | ||
|
||
constructor( | ||
address[] memory _validators, | ||
uint8 _threshold | ||
) OwnableUpgradeable() { | ||
validators = _validators; | ||
threshold = _threshold; | ||
_disableInitializers(); | ||
} | ||
|
||
function initialize( | ||
address[] memory _validators, | ||
uint8 _threshold | ||
) external initializer { | ||
__Ownable_init(); | ||
setValidatorsAndThreshold(_validators, _threshold); | ||
} | ||
|
||
function setValidatorsAndThreshold( | ||
address[] memory _validators, | ||
uint8 _threshold | ||
) public onlyOwner { | ||
require(_threshold <= _validators.length, "Invalid threshold"); | ||
validators = _validators; | ||
threshold = _threshold; | ||
emit ValidatorsAndThresholdSet(_validators, _threshold); | ||
} | ||
|
||
function validatorsAndThreshold( | ||
bytes calldata /* _message */ | ||
) public view override returns (address[] memory, uint8) { | ||
return (validators, threshold); | ||
} | ||
} | ||
|
||
contract StorageMerkleRootMultisigIsm is | ||
AbstractMerkleRootMultisigIsm, | ||
AbstractStorageMultisigIsm | ||
{ | ||
uint8 public constant moduleType = | ||
uint8(IInterchainSecurityModule.Types.MERKLE_ROOT_MULTISIG); | ||
|
||
constructor( | ||
address[] memory _validators, | ||
uint8 _threshold | ||
) AbstractStorageMultisigIsm(_validators, _threshold) {} | ||
} | ||
|
||
contract StorageMessageIdMultisigIsm is | ||
AbstractMessageIdMultisigIsm, | ||
AbstractStorageMultisigIsm | ||
{ | ||
uint8 public constant moduleType = | ||
uint8(IInterchainSecurityModule.Types.MESSAGE_ID_MULTISIG); | ||
|
||
constructor( | ||
address[] memory _validators, | ||
uint8 _threshold | ||
) AbstractStorageMultisigIsm(_validators, _threshold) {} | ||
} | ||
|
||
abstract contract StorageMultisigIsmFactory is IThresholdAddressFactory { | ||
/** | ||
* @notice Emitted when a multisig module is deployed | ||
* @param module The deployed ISM | ||
*/ | ||
event ModuleDeployed(address module); | ||
|
||
// ============ External Functions ============ | ||
function deploy( | ||
address[] calldata _validators, | ||
uint8 _threshold | ||
) external returns (address ism) { | ||
ism = MinimalProxy.create(implementation()); | ||
emit ModuleDeployed(ism); | ||
AbstractStorageMultisigIsm(ism).initialize(_validators, _threshold); | ||
} | ||
|
||
function implementation() public view virtual returns (address); | ||
} | ||
|
||
contract StorageMerkleRootMultisigIsmFactory is StorageMultisigIsmFactory { | ||
address internal immutable _implementation; | ||
|
||
constructor() { | ||
_implementation = address( | ||
new StorageMerkleRootMultisigIsm(new address[](0), 0) | ||
); | ||
} | ||
|
||
function implementation() public view override returns (address) { | ||
return _implementation; | ||
} | ||
} | ||
|
||
contract StorageMessageIdMultisigIsmFactory is StorageMultisigIsmFactory { | ||
address internal immutable _implementation; | ||
|
||
constructor() { | ||
_implementation = address( | ||
new StorageMessageIdMultisigIsm(new address[](0), 0) | ||
); | ||
} | ||
|
||
function implementation() public view override returns (address) { | ||
return _implementation; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import { readdirSync } from 'fs'; | ||
import path, { join } from 'path'; | ||
import { fileURLToPath } from 'url'; | ||
|
||
/** | ||
* @dev Represents a ZkSync artifact. | ||
*/ | ||
export type ZkSyncArtifact = { | ||
contractName: string; | ||
sourceName: string; | ||
abi: any; | ||
bytecode: string; | ||
deployedBytecode: string; | ||
factoryDeps?: Record<string, string>; | ||
}; | ||
|
||
/** | ||
* @dev A mapping of artifact names to their corresponding ZkSync artifacts. | ||
*/ | ||
export type ArtifactMap = { | ||
[key: string]: ZkSyncArtifact; // Key is the artifact name, value is the ZkSyncArtifact | ||
}; | ||
|
||
// Get the resolved path to the current file | ||
const currentFilePath = fileURLToPath(import.meta.url); // Convert the module URL to a file path | ||
const currentDirectory = path.dirname(currentFilePath); | ||
|
||
/** | ||
* @dev Reads artifact files from the specified directory. | ||
* @param directory The directory to read artifact files from. | ||
* @return An array of artifact file names that end with '.js'. | ||
*/ | ||
const getArtifactFiles = (directory: string): string[] => { | ||
return readdirSync(directory).filter((file) => file.endsWith('.js')); // Filter for .js files | ||
}; | ||
|
||
/** | ||
* @dev Exports the list of artifact names without the .js extension. | ||
* @return An array of artifact names without the .js extension. | ||
*/ | ||
export const zksyncArtifactNames = getArtifactFiles( | ||
join(currentDirectory, 'output'), | ||
).map((file) => file.replace('.js', '')); | ||
|
||
/** | ||
* @dev Checks if a ZkSync artifact exists by its name. | ||
* @param name The name of the artifact to check. | ||
* @return True if the artifact exists, false otherwise. | ||
*/ | ||
export const artifactExists = (name: string): boolean => { | ||
return zksyncArtifactNames.includes(`${name}.js`); // Check if the artifact file exists | ||
}; | ||
|
||
/** | ||
* @dev Loads a ZkSync artifact by its name. | ||
* @param name The name of the artifact to load. | ||
* @return The loaded ZkSyncArtifact or undefined if it cannot be loaded. | ||
*/ | ||
const loadZkArtifact = async ( | ||
name: string, | ||
): Promise<ZkSyncArtifact | undefined> => { | ||
try { | ||
const artifactModule = await import( | ||
join(currentDirectory, 'output', `${name}.js`) | ||
); // Dynamically import the artifact module | ||
return artifactModule[name]; // Return the artifact from the artifactModule | ||
} catch (error) { | ||
console.error(`Error loading artifact: ${name}`, error); | ||
return undefined; | ||
} | ||
}; | ||
|
||
/** | ||
* @dev Loads all ZkSync artifacts into a map. | ||
* @return A map of artifact names to their corresponding ZkSync artifacts. | ||
*/ | ||
export const loadAllZkArtifacts = async (): Promise<ArtifactMap> => { | ||
const zkSyncArtifactMap: ArtifactMap = {}; | ||
|
||
// Load all artifacts concurrently | ||
const loadPromises = zksyncArtifactNames.map(async (artifactFileName) => { | ||
const artifact = await loadZkArtifact(artifactFileName); | ||
if (artifact) { | ||
zkSyncArtifactMap[artifactFileName] = artifact; | ||
} | ||
}); | ||
|
||
await Promise.all(loadPromises); | ||
|
||
return zkSyncArtifactMap; // Return the populated artifact map | ||
}; | ||
|
||
/** | ||
* @dev Retrieves a specific ZkSync artifact by its file name. | ||
* @param name The name of the artifact to retrieve. | ||
* @return The loaded ZkSyncArtifact or undefined if it cannot be loaded. | ||
*/ | ||
export const getZkArtifactByName = async ( | ||
name: string, | ||
): Promise<ZkSyncArtifact | undefined> => { | ||
return loadZkArtifact(name); | ||
}; |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is only used for verification btw There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup, we are currently tackling verification (this code should belong to another branch) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,12 +6,12 @@ cd "$(dirname "$0")" | |
# Define the artifacts directory | ||
artifactsDir="./artifacts/build-info" | ||
# Define the output file | ||
outputFileJson="./dist/buildArtifact.json" | ||
outputFileJs="./dist/buildArtifact.js" | ||
outputFileTsd="./dist/buildArtifact.d.ts" | ||
outputFileJson="./dist/evm/buildArtifact.json" | ||
outputFileJs="./dist/evm/buildArtifact.js" | ||
outputFileTsd="./dist/evm/buildArtifact.d.ts" | ||
|
||
# log that we're in the script | ||
echo 'Finding and processing hardhat build artifact...' | ||
echo 'Finding and processing hardhat build EVM artifact...' | ||
|
||
# Find most recently modified JSON build artifact | ||
if [ "$(uname)" = "Darwin" ]; then | ||
|
@@ -37,3 +37,40 @@ else | |
echo 'Failed to process build artifact with jq' | ||
exit 1 | ||
fi | ||
|
||
# ZKSYNC | ||
|
||
# Define the artifacts directory | ||
artifactsDir="./artifacts-zk/build-info" | ||
# Define the output file | ||
outputFileJson="./dist/zksync/buildArtifact.json" | ||
outputFileJs="./dist/zksync/buildArtifact.js" | ||
outputFileTsd="./dist/zksync/buildArtifact.d.ts" | ||
|
||
# log that we're in the script | ||
echo 'Finding and processing hardhat build ZKSync artifact...' | ||
|
||
# Find most recently modified JSON build artifact | ||
if [ "$(uname)" = "Darwin" ]; then | ||
# for local flow | ||
jsonFiles=$(find "$artifactsDir" -type f -name "*.json" -exec stat -f "%m %N" {} \; | sort -rn | head -n 1 | cut -d' ' -f2-) | ||
else | ||
# for CI flow | ||
jsonFiles=$(find "$artifactsDir" -type f -name "*.json" -exec stat -c "%Y %n" {} \; | sort -rn | head -n 1 | cut -d' ' -f2-) | ||
fi | ||
|
||
if [ ! -f "$jsonFiles" ]; then | ||
echo 'Failed to find build artifact' | ||
exit 1 | ||
fi | ||
Comment on lines
+53
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would be nice to deduplicate this recently modified artifact finding/checking |
||
|
||
# Extract required keys and write to outputFile | ||
if jq -c '{input, solcLongVersion, zk_version: .output.zk_version}' "$jsonFiles" > "$outputFileJson"; then | ||
echo "export const buildArtifact = " > "$outputFileJs" | ||
cat "$outputFileJson" >> "$outputFileJs" | ||
echo "export const buildArtifact: any" > "$outputFileTsd" | ||
echo 'Finished processing build artifact.' | ||
else | ||
echo 'Failed to process build artifact with jq' | ||
exit 1 | ||
fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete this?