-
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 39 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 |
---|---|---|
|
@@ -11,7 +11,7 @@ outputFileJs="./dist/buildArtifact.js" | |
outputFileTsd="./dist/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 commentThe reason will be displayed to describe this comment to others. Learn more. not sure I totally understand why we need this 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. We use it in ZKDeployer class. Since the cli/sdk doesn't have access to When we import all contracts as an array its much easier to sift through all of them, and then load the correct artifact for deployment. I don't think this is optimal, need to find a better way. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'; | ||
import { basename, dirname, join } from 'path'; | ||
import { glob } from 'typechain'; | ||
import { fileURLToPath } from 'url'; | ||
|
||
const cwd = process.cwd(); | ||
|
||
const zksyncArtifacts = glob(cwd, [ | ||
`!./artifacts-zk/contracts/**/*.dbg.json`, | ||
`!./artifacts-zk/@openzeppelin/**/*.dbg.json`, | ||
`./artifacts-zk/contracts/**/+([a-zA-Z0-9_]).json`, | ||
`./artifacts-zk/@openzeppelin/**/+([a-zA-Z0-9_]).json`, | ||
]); | ||
|
||
const __filename = fileURLToPath(import.meta.url); | ||
const __dirname = dirname(__filename); | ||
|
||
// Directory containing your JSON files | ||
const outputFile = join(__dirname, 'types/zksync/artifacts/index.ts'); | ||
const outputDir = join(__dirname, 'types/zksync/artifacts'); | ||
|
||
const zkSyncFileNames = new Set(); | ||
|
||
let zkSyncArtifactMap = {}; | ||
|
||
// Start building the TypeScript export string | ||
let exportStatements = zksyncArtifacts | ||
.map((file) => { | ||
const fileContent = readFileSync(file, 'utf-8'); | ||
const jsonObject = JSON.parse(fileContent); | ||
const contractName = jsonObject.contractName; | ||
let fileName = `${basename(file, '.json')}__artifact`; | ||
|
||
if (zkSyncFileNames.has(fileName)) { | ||
return; | ||
} | ||
zkSyncFileNames.add(fileName); | ||
|
||
// Add to artifact map | ||
zkSyncArtifactMap[contractName] = fileName; | ||
|
||
// Create a TypeScript object export statement | ||
return `export const ${fileName} = ${JSON.stringify( | ||
jsonObject, | ||
null, | ||
2, | ||
)} as const;`; | ||
}) | ||
.join('\n\n'); | ||
|
||
exportStatements += `\n\nexport const zksyncArtifacts : any[] = [\n${Array.from( | ||
zkSyncFileNames, | ||
).join(',\n')}\n] as const;`; | ||
|
||
if (!existsSync(outputDir)) { | ||
mkdirSync(outputDir, { recursive: true }); | ||
} | ||
|
||
// Write the index.ts file | ||
writeFileSync(outputFile, exportStatements); | ||
|
||
console.log( | ||
`Generated TypeScript object exports for ${zksyncArtifacts.length} JSON files in configs/`, | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,10 +9,13 @@ | |
"@layerzerolabs/lz-evm-oapp-v2": "2.0.2", | ||
"@openzeppelin/contracts": "^4.9.3", | ||
"@openzeppelin/contracts-upgradeable": "^v4.9.3", | ||
"fx-portal": "^1.0.3" | ||
"fx-portal": "^1.0.3", | ||
"zksync-ethers": "^5" | ||
}, | ||
"devDependencies": { | ||
"@layerzerolabs/solidity-examples": "^1.1.0", | ||
"@matterlabs/hardhat-zksync-deploy": "^0.7.0", | ||
"@matterlabs/hardhat-zksync-solc": "^1.2.4", | ||
"@nomiclabs/hardhat-ethers": "^2.2.3", | ||
"@nomiclabs/hardhat-waffle": "^2.0.6", | ||
"@typechain/ethers-v5": "^11.1.2", | ||
|
@@ -45,12 +48,15 @@ | |
"./mailbox": "./dist/contracts/Mailbox.js", | ||
"./buildArtifact.js": "./dist/buildArtifact.js", | ||
"./buildArtifact.json": "./dist/buildArtifact.json", | ||
"./contracts": "./contracts" | ||
"./contracts": "./contracts", | ||
"./artifacts": "./dist/zksync/artifacts/index.js", | ||
"./artifacts/*": "./dist/zksync/artifacts/*.js" | ||
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. perhaps |
||
}, | ||
"types": "./dist/index.d.ts", | ||
"files": [ | ||
"/dist", | ||
"/contracts" | ||
"/contracts", | ||
"/dist/zksync/artifacts" | ||
], | ||
"engines": { | ||
"node": ">=16" | ||
|
@@ -63,13 +69,14 @@ | |
], | ||
"license": "Apache-2.0", | ||
"scripts": { | ||
"build": "yarn hardhat-esm compile && tsc && ./exportBuildArtifact.sh", | ||
"build": "yarn hardhat-esm compile && yarn hardhat-zk compile && ts-node generate-artifact-exports.mjs && tsc && ./exportBuildArtifact.sh", | ||
"lint": "solhint contracts/**/*.sol", | ||
"clean": "yarn hardhat-esm clean && rm -rf ./dist ./cache ./types ./coverage ./out ./forge-cache ./fixtures", | ||
"clean": "yarn hardhat-esm clean && yarn hardhat-zk clean && rm -rf ./dist ./cache ./cache-zk ./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", | ||
"hardhat-zk": "NODE_OPTIONS='--experimental-loader ts-node/esm/transpile-only --no-warnings=ExperimentalWarning' hardhat --config zk-hardhat.config.cts", | ||
"prettier": "prettier --write ./contracts ./test", | ||
"test": "yarn hardhat-esm test && yarn test:forge", | ||
"test:hardhat": "yarn hardhat-esm test", | ||
|
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.
this is only used for verification btw
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.
Yup, we are currently tackling verification (this code should belong to another branch)