diff --git a/.changeset/chatty-starfishes-double.md b/.changeset/chatty-starfishes-double.md new file mode 100644 index 0000000000..2e51bb44da --- /dev/null +++ b/.changeset/chatty-starfishes-double.md @@ -0,0 +1,11 @@ +--- +'@hyperlane-xyz/core': minor +--- + +Add ZKSync support and restructure build artifacts: + +- Add ZKSync compilation support +- Restructure typechain directory location to core-utils/typechain +- Add ZKSync-specific artifact generation and exports +- Update build process to handle both standard and ZKSync artifacts +- Add new exports for ZKSync build artifacts and contract types diff --git a/.changeset/eleven-cows-dance.md b/.changeset/eleven-cows-dance.md new file mode 100644 index 0000000000..adc16422bd --- /dev/null +++ b/.changeset/eleven-cows-dance.md @@ -0,0 +1,5 @@ +--- +'@hyperlane-xyz/sdk': minor +--- + +Added ZKSync specific deployment logic and artifact related utils diff --git a/.changeset/mighty-terms-rest.md b/.changeset/mighty-terms-rest.md new file mode 100644 index 0000000000..4f0598feb1 --- /dev/null +++ b/.changeset/mighty-terms-rest.md @@ -0,0 +1,5 @@ +--- +'@hyperlane-xyz/sdk': minor +--- + +ZKSync Provider types with builders diff --git a/solidity/.gitignore b/solidity/.gitignore index 6f01b8e770..d7ca1005d0 100644 --- a/solidity/.gitignore +++ b/solidity/.gitignore @@ -15,3 +15,10 @@ docs flattened/ buildArtifact.json fixtures/ +# ZKSync +artifacts-zk +cache-zk +core-utils/zksync/artifacts/output +.zksolc-libraries-cache/ +typechain-types/ +typechain/ \ No newline at end of file diff --git a/solidity/core-utils/index.ts b/solidity/core-utils/index.ts new file mode 100644 index 0000000000..1fbeb99f89 --- /dev/null +++ b/solidity/core-utils/index.ts @@ -0,0 +1,2 @@ +export * from './typechain/index.js'; +export * from './zksync/index.js'; diff --git a/solidity/core-utils/zksync/artifacts.ts b/solidity/core-utils/zksync/artifacts.ts new file mode 100644 index 0000000000..86c6b2dcf5 --- /dev/null +++ b/solidity/core-utils/zksync/artifacts.ts @@ -0,0 +1,5 @@ +import type { ZKSyncArtifact } from './types.js'; + +// Default empty artifact array when `yarn build:zk` hasn't been run +// This file will be populated with contract artifacts in dist after running the build:zk command +export const zkSyncContractArtifacts: ZKSyncArtifact[] = [] as const; diff --git a/solidity/core-utils/zksync/buildArtifact.ts b/solidity/core-utils/zksync/buildArtifact.ts new file mode 100644 index 0000000000..6405cdef48 --- /dev/null +++ b/solidity/core-utils/zksync/buildArtifact.ts @@ -0,0 +1,19 @@ +// Default empty artifact array when `yarn build:zk` hasn't been run +// This file will be populated with build artifacts in dist/zksync after running the build:zk command +export const buildArtifact = { + solcLongVersion: '', + zk_version: '', + input: { + language: 'Solidity', + sources: {}, + settings: { + optimizer: { + enabled: false, + runs: 200, + }, + outputSelection: {}, + evmVersion: 'london', + remappings: [], + }, + }, +}; diff --git a/solidity/core-utils/zksync/index.ts b/solidity/core-utils/zksync/index.ts new file mode 100644 index 0000000000..f27a955d7c --- /dev/null +++ b/solidity/core-utils/zksync/index.ts @@ -0,0 +1,4 @@ +export * from './artifacts.js'; +export * from './buildArtifact.js'; +export * from './utils.js'; +export * from './types.js'; diff --git a/solidity/core-utils/zksync/types.ts b/solidity/core-utils/zksync/types.ts new file mode 100644 index 0000000000..eba36c83ce --- /dev/null +++ b/solidity/core-utils/zksync/types.ts @@ -0,0 +1,11 @@ +export interface ZKSyncArtifact { + _format: string; + contractName: string; + sourceName: string; + abi: any[]; + bytecode: string; + deployedBytecode: string; + linkReferences: Record; + deployedLinkReferences: Record; + factoryDeps: Record; +} diff --git a/solidity/core-utils/zksync/utils.ts b/solidity/core-utils/zksync/utils.ts new file mode 100644 index 0000000000..64be6859a1 --- /dev/null +++ b/solidity/core-utils/zksync/utils.ts @@ -0,0 +1,23 @@ +import { zkSyncContractArtifacts } from './artifacts.js'; +import { ZKSyncArtifact } from './types.js'; + +/** + * @dev Get a ZkSync artifact by its name. + * @param name The name of the artifact to get. + * @return The loaded ZKSyncArtifact or undefined if it cannot be found. + */ +export function getZKSyncArtifactByName( + name: string, +): ZKSyncArtifact | undefined { + return zkSyncContractArtifacts.find( + (artifact) => artifact.contractName === name, + ); +} + +/** + * @dev Loads all ZkSync artifacts into an array. + * @return An array of ZkSync artifacts. + */ +export function loadAllZKSyncArtifacts(): ZKSyncArtifact[] { + return zkSyncContractArtifacts; +} diff --git a/solidity/eslint.config.mjs b/solidity/eslint.config.mjs index e323f60701..44a7ba33fc 100644 --- a/solidity/eslint.config.mjs +++ b/solidity/eslint.config.mjs @@ -4,9 +4,11 @@ export default [ ...MonorepoDefaults, { ignores: [ - './test/**/*', - './dist/**/*', + '**/test/**/*', + '**/dist/**/*', + '**/typechain/**/*', '.solcover.js', + 'generate-artifact-exports.mjs', ], }, ]; diff --git a/solidity/exportBuildArtifact.sh b/solidity/exportBuildArtifact.sh index e6d5d503b8..c951281911 100755 --- a/solidity/exportBuildArtifact.sh +++ b/solidity/exportBuildArtifact.sh @@ -37,3 +37,42 @@ else echo 'Failed to process build artifact with jq' exit 1 fi + +# ZKSYNC + +if [ "$ZKSYNC" = "true" ]; then + # 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 ZKSync hardhat build 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 ZKSync build artifact' + exit 1 + fi + + # 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 ZKSync build artifact.' + else + echo 'Failed to process ZKSync build artifact with jq' + exit 1 + fi +fi \ No newline at end of file diff --git a/solidity/generate-artifact-exports.mjs b/solidity/generate-artifact-exports.mjs new file mode 100755 index 0000000000..69327ffda4 --- /dev/null +++ b/solidity/generate-artifact-exports.mjs @@ -0,0 +1,174 @@ +import { promises as fs } from 'fs'; +import { basename, dirname, join } from 'path'; +import { glob } from 'typechain'; +import { fileURLToPath } from 'url'; + +const cwd = process.cwd(); +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const ROOT_OUTPUT_DIR = join(__dirname, 'dist/zksync/'); +const ARTIFACTS_OUTPUT_DIR = join(ROOT_OUTPUT_DIR, 'artifacts'); + +/** + * @notice Templates for TypeScript artifact generation + */ +const TEMPLATES = { + JS_ARTIFACT: `\ +export const {name} = {artifact}; +`, + + DTS_ARTIFACT: `\ +import type { ZKSyncArtifact } from '../types.js'; + +export declare const {name}: ZKSyncArtifact; +`, + + JS_INDEX: `\ +{imports} + +export const zkSyncContractArtifacts = [ +{exports} +]; +`, + + DTS_INDEX: `\ +import type { ZKSyncArtifact } from './types.js'; + +export declare const zkSyncContractArtifacts: readonly ZKSyncArtifact[]; +`, +}; + +class ArtifactGenerator { + constructor() { + this.processedFiles = new Set(); + } + + /** + * @notice Retrieves paths of all relevant artifact files + * @dev Excludes debug files and build-info directory + * @return {string[]} Array of file paths matching the glob pattern + */ + getArtifactPaths() { + return glob(cwd, [ + `!./artifacts-zk/!(build-info)/**/*.dbg.json`, + `./artifacts-zk/!(build-info)/**/+([a-zA-Z0-9_]).json`, + ]); + } + + /** + * @notice Creates the output directory if it doesn't exist + */ + async createOutputDirectory() { + await fs.mkdir(ARTIFACTS_OUTPUT_DIR, { recursive: true }); + } + + /** + * @notice Reads and parses a JSON artifact file + * @param filePath Path to the artifact file + * @return {Promise} Parsed JSON content + */ + async readArtifactFile(filePath) { + const content = await fs.readFile(filePath, 'utf-8'); + return JSON.parse(content); + } + + /** + * @notice Generates JavaScript content for a contract artifact + */ + generateJavaScriptContent(name, artifact) { + return TEMPLATES.JS_ARTIFACT.replace('{name}', name).replace( + '{artifact}', + JSON.stringify(artifact, null, 2), + ); + } + + /** + * @notice Generates TypeScript declaration content for a contract artifact + */ + generateDeclarationContent(name) { + return TEMPLATES.DTS_ARTIFACT.replace('{name}', name); + } + + /** + * @notice Generates index file contents + */ + generateIndexContents(artifactNames) { + const imports = artifactNames + .map((name) => `import { ${name} } from './artifacts/${name}.js';`) + .join('\n'); + const exports = artifactNames.map((name) => ` ${name},`).join('\n'); + + const jsContent = TEMPLATES.JS_INDEX.replace('{imports}', imports).replace( + '{exports}', + exports, + ); + + const dtsContent = TEMPLATES.DTS_INDEX.replace( + '{imports}', + imports, + ).replace('{exports}', exports); + + return { jsContent, dtsContent }; + } + + /** + * @notice Processes a single artifact file + */ + async processArtifact(filePath) { + const name = basename(filePath, '.json'); + + if (this.processedFiles.has(name)) { + return; + } + + const artifact = await this.readArtifactFile(filePath); + + // Generate and write .js file + const jsContent = this.generateJavaScriptContent(name, artifact); + await fs.writeFile( + join(ROOT_OUTPUT_DIR, 'artifacts', `${name}.js`), + jsContent, + ); + + // Generate and write .d.ts file + const dtsContent = this.generateDeclarationContent(name); + await fs.writeFile( + join(ROOT_OUTPUT_DIR, 'artifacts', `${name}.d.ts`), + dtsContent, + ); + + this.processedFiles.add(name); + } + + async generate() { + try { + await this.createOutputDirectory(); + + const artifactPaths = this.getArtifactPaths(); + + for (const filePath of artifactPaths) { + await this.processArtifact(filePath); + } + + const processedNames = Array.from(this.processedFiles); + + // Generate and write index files + const { jsContent, dtsContent } = + this.generateIndexContents(processedNames); + + await fs.writeFile(join(ROOT_OUTPUT_DIR, 'artifacts.js'), jsContent); + await fs.writeFile(join(ROOT_OUTPUT_DIR, 'artifacts.d.ts'), dtsContent); + + console.log( + `Successfully processed ${processedNames.length} zksync artifacts`, + ); + } catch (error) { + console.error('Error processing zksync artifacts:', error); + throw error; + } + } +} + +const generator = new ArtifactGenerator(); +generator.generate().catch(console.error); diff --git a/solidity/hardhat.config.cts b/solidity/hardhat.config.cts index 6d64d971e6..6fd31c3dc4 100644 --- a/solidity/hardhat.config.cts +++ b/solidity/hardhat.config.cts @@ -22,7 +22,7 @@ module.exports = { currency: 'USD', }, typechain: { - outDir: './types', + outDir: './core-utils/typechain', target: 'ethers-v5', alwaysGenerateOverloads: true, node16Modules: true, diff --git a/solidity/package.json b/solidity/package.json index c367e7b931..e41a3fb472 100644 --- a/solidity/package.json +++ b/solidity/package.json @@ -13,6 +13,7 @@ }, "devDependencies": { "@layerzerolabs/solidity-examples": "^1.1.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", @@ -36,7 +37,8 @@ "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" + "typescript": "5.3.3", + "zksync-ethers": "^5.10.0" }, "directories": { "test": "test" @@ -44,9 +46,10 @@ "type": "module", "exports": { ".": "./dist/index.js", - "./mailbox": "./dist/contracts/Mailbox.js", + "./mailbox": "./dist/typechain/contracts/Mailbox.js", "./buildArtifact.js": "./dist/buildArtifact.js", "./buildArtifact.json": "./dist/buildArtifact.json", + "./buildArtifact-zksync.js": "./dist/zksync/buildArtifact.js", "./contracts": "./contracts" }, "types": "./dist/index.d.ts", @@ -66,12 +69,15 @@ "license": "Apache-2.0", "scripts": { "build": "yarn version:update && 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", + "build:zk": "yarn hardhat-zk compile && tsc && ts-node generate-artifact-exports.mjs && ZKSYNC=true ./exportBuildArtifact.sh", + "prepublishOnly": "yarn build && yarn build:zk", + "lint": "solhint contracts/**/*.sol && eslint -c ./eslint.config.mjs", + "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 version:exhaustive && yarn hardhat-esm test && yarn test:forge", "test:hardhat": "yarn hardhat-esm test", diff --git a/solidity/test/lib/mailboxes.ts b/solidity/test/lib/mailboxes.ts index 06ae211cf5..bd1d728e36 100644 --- a/solidity/test/lib/mailboxes.ts +++ b/solidity/test/lib/mailboxes.ts @@ -18,8 +18,8 @@ import { LegacyMultisigIsm, TestMailbox, TestMerkleTreeHook, -} from '../../types'; -import { DispatchEvent } from '../../types/contracts/Mailbox'; +} from '../../core-utils/typechain'; +import { DispatchEvent } from '../../core-utils/typechain/contracts/Mailbox'; export type MessageAndProof = { proof: MerkleProof; diff --git a/solidity/test/merkle.test.ts b/solidity/test/merkle.test.ts index f2a3d5d399..5546ac86bf 100644 --- a/solidity/test/merkle.test.ts +++ b/solidity/test/merkle.test.ts @@ -2,7 +2,7 @@ import { expect } from 'chai'; import { utils } from 'ethers'; import merkleTestCases from '../../vectors/merkle.json' assert { type: 'json' }; -import { TestMerkle, TestMerkle__factory } from '../types'; +import { TestMerkle, TestMerkle__factory } from '../core-utils/typechain'; import { getSigner } from './signer'; diff --git a/solidity/test/message.test.ts b/solidity/test/message.test.ts index 83bde28b6f..996bb31e7b 100644 --- a/solidity/test/message.test.ts +++ b/solidity/test/message.test.ts @@ -8,7 +8,11 @@ import { } from '@hyperlane-xyz/utils'; import testCases from '../../vectors/message.json' assert { type: 'json' }; -import { Mailbox__factory, TestMessage, TestMessage__factory } from '../types'; +import { + Mailbox__factory, + TestMessage, + TestMessage__factory, +} from '../core-utils/typechain'; import { getSigner, getSigners } from './signer'; diff --git a/solidity/test/mockMailbox.test.ts b/solidity/test/mockMailbox.test.ts index db49a7585e..6df9ec41db 100644 --- a/solidity/test/mockMailbox.test.ts +++ b/solidity/test/mockMailbox.test.ts @@ -3,7 +3,10 @@ import { utils } from 'ethers'; import { addressToBytes32 } from '@hyperlane-xyz/utils'; -import { MockMailbox__factory, TestRecipient__factory } from '../types'; +import { + MockMailbox__factory, + TestRecipient__factory, +} from '../core-utils/typechain'; import { getSigner } from './signer'; diff --git a/solidity/test/testrecipient.test.ts b/solidity/test/testrecipient.test.ts index acdbf573eb..dd1d9a44e1 100644 --- a/solidity/test/testrecipient.test.ts +++ b/solidity/test/testrecipient.test.ts @@ -3,7 +3,7 @@ import { utils } from 'ethers'; import { addressToBytes32 } from '@hyperlane-xyz/utils'; -import { TestRecipient, TestRecipient__factory } from '../types'; +import { TestRecipient, TestRecipient__factory } from '../core-utils/typechain'; import { getSigner } from './signer'; diff --git a/solidity/tsconfig.json b/solidity/tsconfig.json index cece6d7fc6..99ae657d2b 100644 --- a/solidity/tsconfig.json +++ b/solidity/tsconfig.json @@ -2,7 +2,7 @@ "extends": "../tsconfig.json", "compilerOptions": { "outDir": "./dist", - "rootDir": "./types" + "rootDir": "./core-utils" }, - "exclude": ["./test", "hardhat.config.cts", "./dist"] + "exclude": ["./test", "hardhat.config.cts", "./dist", "zk-hardhat.config.cts"] } diff --git a/solidity/zk-hardhat.config.cts b/solidity/zk-hardhat.config.cts new file mode 100644 index 0000000000..618fe65a5b --- /dev/null +++ b/solidity/zk-hardhat.config.cts @@ -0,0 +1,46 @@ +import '@matterlabs/hardhat-zksync-solc'; +import '@nomiclabs/hardhat-ethers'; +import 'hardhat-ignore-warnings'; + +/** + * @type import('hardhat/config').HardhatUserConfig + */ +module.exports = { + zksolc: { + version: '1.5.3', + compilerSource: 'binary', + enableEraVMExtensions: true, + }, + defaultNetwork: 'zkSyncNetwork', + networks: { + zkSyncNetwork: { + url: 'http://127.0.0.1:8011', + ethNetwork: '', + zksync: true, + }, + }, + solidity: { + version: '0.8.19', + settings: { + optimizer: { + enabled: true, + runs: 999_999, + }, + }, + }, + mocha: { + bail: true, + import: 'tsx', + }, + warnings: { + // turn off all warnings for libs: + 'fx-portal/**/*': { + default: 'off', + }, + }, + paths: { + sources: './contracts', + cache: './cache-zk', + artifacts: './artifacts-zk', + }, +}; diff --git a/typescript/sdk/package.json b/typescript/sdk/package.json index 79f67348c7..2ed4ea9790 100644 --- a/typescript/sdk/package.json +++ b/typescript/sdk/package.json @@ -21,6 +21,7 @@ "ethers": "^5.7.2", "pino": "^8.19.0", "viem": "^2.21.45", + "zksync-ethers": "^5.10.0", "zod": "^3.21.2" }, "devDependencies": { diff --git a/typescript/sdk/src/deploy/proxy.ts b/typescript/sdk/src/deploy/proxy.ts index 8749e433a9..9e28e4f65a 100644 --- a/typescript/sdk/src/deploy/proxy.ts +++ b/typescript/sdk/src/deploy/proxy.ts @@ -1,4 +1,5 @@ import { ethers } from 'ethers'; +import { Provider as ZKSyncProvider } from 'zksync-ethers'; import { ProxyAdmin__factory } from '@hyperlane-xyz/core'; import { Address, ChainId, eqAddress } from '@hyperlane-xyz/utils'; @@ -7,6 +8,8 @@ import { transferOwnershipTransactions } from '../contracts/contracts.js'; import { AnnotatedEV5Transaction } from '../providers/ProviderType.js'; import { DeployedOwnableConfig } from '../types.js'; +type NetworkProvider = ethers.providers.Provider | ZKSyncProvider; + export type UpgradeConfig = { timelock: { delay: number; @@ -19,7 +22,7 @@ export type UpgradeConfig = { }; export async function proxyImplementation( - provider: ethers.providers.Provider, + provider: NetworkProvider, proxy: Address, ): Promise
{ // Hardcoded storage slot for implementation per EIP-1967 @@ -31,7 +34,7 @@ export async function proxyImplementation( } export async function isInitialized( - provider: ethers.providers.Provider, + provider: NetworkProvider, contract: Address, ): Promise { // Using OZ's Initializable 4.9 which keeps it at the 0x0 slot @@ -43,7 +46,7 @@ export async function isInitialized( } export async function proxyAdmin( - provider: ethers.providers.Provider, + provider: NetworkProvider, proxy: Address, ): Promise
{ // Hardcoded storage slot for admin per EIP-1967 @@ -66,7 +69,7 @@ export function proxyConstructorArgs( } export async function isProxy( - provider: ethers.providers.Provider, + provider: NetworkProvider, proxy: Address, ): Promise { const admin = await proxyAdmin(provider, proxy); diff --git a/typescript/sdk/src/deploy/proxyFactoryUtils.ts b/typescript/sdk/src/deploy/proxyFactoryUtils.ts new file mode 100644 index 0000000000..ecdbd51dd1 --- /dev/null +++ b/typescript/sdk/src/deploy/proxyFactoryUtils.ts @@ -0,0 +1,16 @@ +import { ethers } from 'ethers'; + +import { proxyFactoryFactories } from './contracts.js'; +import { ProxyFactoryFactoriesAddresses } from './types.js'; + +/** + * Creates a default ProxyFactoryFactoriesAddresses object with all values set to ethers.constants.AddressZero. + * @returns {ProxyFactoryFactoriesAddresses} An object with all factory addresses set to AddressZero. + */ +export function createDefaultProxyFactoryFactories(): ProxyFactoryFactoriesAddresses { + const defaultAddress = ethers.constants.AddressZero; + return Object.keys(proxyFactoryFactories).reduce((acc, key) => { + acc[key as keyof ProxyFactoryFactoriesAddresses] = defaultAddress; // Type assertion added here + return acc; + }, {} as ProxyFactoryFactoriesAddresses); +} diff --git a/typescript/sdk/src/hook/types.ts b/typescript/sdk/src/hook/types.ts index 76e749fd95..8f1ea0c7c4 100644 --- a/typescript/sdk/src/hook/types.ts +++ b/typescript/sdk/src/hook/types.ts @@ -38,6 +38,21 @@ export enum HookType { ARB_L2_TO_L1 = 'arbL2ToL1Hook', } +export const HookTypeToContractNameMap: Record< + Exclude, + string +> = { + [HookType.MERKLE_TREE]: 'merkleTreeHook', + [HookType.INTERCHAIN_GAS_PAYMASTER]: 'interchainGasPaymaster', + [HookType.AGGREGATION]: 'staticAggregationHook', + [HookType.PROTOCOL_FEE]: 'protocolFee', + [HookType.OP_STACK]: 'opStackHook', + [HookType.ROUTING]: 'domainRoutingHook', + [HookType.FALLBACK_ROUTING]: 'fallbackDomainRoutingHook', + [HookType.PAUSABLE]: 'pausableHook', + [HookType.ARB_L2_TO_L1]: 'arbL2ToL1Hook', +}; + export type MerkleTreeHookConfig = z.infer; export type IgpHookConfig = z.infer; export type ProtocolFeeHookConfig = z.infer; diff --git a/typescript/sdk/src/index.ts b/typescript/sdk/src/index.ts index 0ec8e740b3..90bb6f06f4 100644 --- a/typescript/sdk/src/index.ts +++ b/typescript/sdk/src/index.ts @@ -205,7 +205,12 @@ export { WeightedMultisigIsmConfig, WeightedMultisigIsmConfigSchema, } from './ism/types.js'; -export { collectValidators, moduleCanCertainlyVerify } from './ism/utils.js'; +export { + collectValidators, + moduleCanCertainlyVerify, + isStaticDeploymentSupported, + isIsmCompatible, +} from './ism/utils.js'; export { AgentChainMetadata, AgentChainMetadataSchema, diff --git a/typescript/sdk/src/ism/types.ts b/typescript/sdk/src/ism/types.ts index 87adb2cff2..810f6ada33 100644 --- a/typescript/sdk/src/ism/types.ts +++ b/typescript/sdk/src/ism/types.ts @@ -67,6 +67,16 @@ export const MUTABLE_ISM_TYPE = [ IsmType.PAUSABLE, ]; +// ISM types that require static deployment +export const STATIC_ISM_TYPES = [ + IsmType.AGGREGATION, + IsmType.MERKLE_ROOT_MULTISIG, + IsmType.MESSAGE_ID_MULTISIG, + IsmType.WEIGHTED_MERKLE_ROOT_MULTISIG, + IsmType.WEIGHTED_MESSAGE_ID_MULTISIG, + IsmType.ICA_ROUTING, +]; + // mapping between the two enums export function ismTypeToModuleType(ismType: IsmType): ModuleType { switch (ismType) { diff --git a/typescript/sdk/src/ism/utils.ts b/typescript/sdk/src/ism/utils.ts index 5989854ab7..d8cb457384 100644 --- a/typescript/sdk/src/ism/utils.ts +++ b/typescript/sdk/src/ism/utils.ts @@ -24,6 +24,7 @@ import { import { HyperlaneContracts } from '../contracts/types.js'; import { ProxyFactoryFactories } from '../deploy/contracts.js'; +import { ChainTechnicalStack } from '../metadata/chainMetadataTypes.js'; import { MultiProvider } from '../providers/MultiProvider.js'; import { ChainName } from '../types.js'; @@ -34,6 +35,7 @@ import { ModuleType, RoutingIsmConfig, RoutingIsmDelta, + STATIC_ISM_TYPES, ismTypeToModuleType, } from './types.js'; @@ -534,3 +536,37 @@ export function collectValidators( return new Set(validators); } + +/** + * Determines if static ISM deployment is supported on a given chain's technical stack + * @dev Currently, only ZkSync does not support static deployments + * @param chainTechnicalStack - The technical stack of the target chain + * @returns boolean - true if static deployment is supported, false for ZkSync + */ +export function isStaticDeploymentSupported( + chainTechnicalStack: ChainTechnicalStack | undefined, +): boolean { + if (chainTechnicalStack === undefined) return true; + return chainTechnicalStack !== ChainTechnicalStack.ZkSync; +} + +/** + * Checks if the given ISM type is compatible with the chain's technical stack. + * + * @param {Object} params - The parameters object + * @param {ChainTechnicalStack | undefined} params.chainTechnicalStack - The technical stack of the chain + * @param {IsmType} params.ismType - The type of Interchain Security Module (ISM) + * @returns {boolean} True if the ISM type is compatible with the chain, false otherwise + */ +export function isIsmCompatible({ + chainTechnicalStack, + ismType, +}: { + chainTechnicalStack: ChainTechnicalStack | undefined; + ismType: IsmType; +}): boolean { + // Skip compatibility check for non-static ISMs as they're always supported + if (!STATIC_ISM_TYPES.includes(ismType)) return true; + + return isStaticDeploymentSupported(chainTechnicalStack); +} diff --git a/typescript/sdk/src/metadata/chainMetadataTypes.ts b/typescript/sdk/src/metadata/chainMetadataTypes.ts index f8972f9bdb..5f57159487 100644 --- a/typescript/sdk/src/metadata/chainMetadataTypes.ts +++ b/typescript/sdk/src/metadata/chainMetadataTypes.ts @@ -22,6 +22,7 @@ export enum ExplorerFamily { Etherscan = 'etherscan', Blockscout = 'blockscout', Routescan = 'routescan', + ZkSync = 'zksync', Other = 'other', } diff --git a/typescript/sdk/src/providers/ProviderType.ts b/typescript/sdk/src/providers/ProviderType.ts index ce1740873d..a09f1da325 100644 --- a/typescript/sdk/src/providers/ProviderType.ts +++ b/typescript/sdk/src/providers/ProviderType.ts @@ -21,6 +21,11 @@ import type { Transaction as VTransaction, TransactionReceipt as VTransactionReceipt, } from 'viem'; +import { + Contract as ZKSyncBaseContract, + Provider as ZKSyncBaseProvider, + types as zkSyncTypes, +} from 'zksync-ethers'; import { Annotated, ProtocolType } from '@hyperlane-xyz/utils'; @@ -31,6 +36,7 @@ export enum ProviderType { CosmJs = 'cosmjs', CosmJsWasm = 'cosmjs-wasm', GnosisTxBuilder = 'gnosis-txBuilder', + ZkSync = 'zksync', } export const PROTOCOL_TO_DEFAULT_PROVIDER_TYPE: Record< @@ -124,13 +130,19 @@ export interface CosmJsWasmProvider provider: Promise; } +export interface ZKSyncProvider extends TypedProviderBase { + type: ProviderType.ZkSync; + provider: ZKSyncBaseProvider; +} + export type TypedProvider = | EthersV5Provider // | EthersV6Provider | ViemProvider | SolanaWeb3Provider | CosmJsProvider - | CosmJsWasmProvider; + | CosmJsWasmProvider + | ZKSyncProvider; /** * Contracts with discriminated union of provider type @@ -169,13 +181,19 @@ export interface CosmJsWasmContract contract: CosmWasmContract; } +export interface ZKSyncContract extends TypedContractBase { + type: ProviderType.ZkSync; + contract: ZKSyncBaseContract; +} + export type TypedContract = | EthersV5Contract // | EthersV6Contract | ViemContract | SolanaWeb3Contract | CosmJsContract - | CosmJsWasmContract; + | CosmJsWasmContract + | ZKSyncBaseContract; /** * Transactions with discriminated union of provider type @@ -216,13 +234,20 @@ export interface CosmJsWasmTransaction transaction: ExecuteInstruction; } +export interface ZKSyncTransaction + extends TypedTransactionBase { + type: ProviderType.ZkSync; + transaction: zkSyncTypes.TransactionRequest; +} + export type TypedTransaction = | EthersV5Transaction // | EthersV6Transaction | ViemTransaction | SolanaWeb3Transaction | CosmJsTransaction - | CosmJsWasmTransaction; + | CosmJsWasmTransaction + | ZKSyncTransaction; /** * Transaction receipt/response with discriminated union of provider type @@ -263,9 +288,16 @@ export interface CosmJsWasmTransactionReceipt receipt: DeliverTxResponse; } +export interface ZKSyncTransactionReceipt + extends TypedTransactionReceiptBase { + type: ProviderType.ZkSync; + receipt: zkSyncTypes.TransactionReceipt; +} + export type TypedTransactionReceipt = | EthersV5TransactionReceipt | ViemTransactionReceipt | SolanaWeb3TransactionReceipt | CosmJsTransactionReceipt - | CosmJsWasmTransactionReceipt; + | CosmJsWasmTransactionReceipt + | ZKSyncTransactionReceipt; diff --git a/typescript/sdk/src/providers/providerBuilders.ts b/typescript/sdk/src/providers/providerBuilders.ts index bc8051b1ba..cfe773de95 100644 --- a/typescript/sdk/src/providers/providerBuilders.ts +++ b/typescript/sdk/src/providers/providerBuilders.ts @@ -3,8 +3,9 @@ import { StargateClient } from '@cosmjs/stargate'; import { Connection } from '@solana/web3.js'; import { providers } from 'ethers'; import { createPublicClient, http } from 'viem'; +import { Provider as ZKProvider } from 'zksync-ethers'; -import { ProtocolType, isNumeric } from '@hyperlane-xyz/utils'; +import { ProtocolType, assert, isNumeric } from '@hyperlane-xyz/utils'; import { ChainMetadata, RpcUrl } from '../metadata/chainMetadataTypes.js'; @@ -16,6 +17,7 @@ import { SolanaWeb3Provider, TypedProvider, ViemProvider, + ZKSyncProvider, } from './ProviderType.js'; import { HyperlaneSmartProvider } from './SmartProvider/SmartProvider.js'; import { ProviderRetryOptions } from './SmartProvider/types.js'; @@ -109,6 +111,16 @@ export function defaultCosmJsWasmProviderBuilder( }; } +export function defaultZKSyncProviderBuilder( + rpcUrls: RpcUrl[], + network: providers.Networkish, +): ZKSyncProvider { + assert(rpcUrls.length, 'No RPC URLs provided'); + const url = rpcUrls[0].http; + const provider = new ZKProvider(url, network); + return { type: ProviderType.ZkSync, provider }; +} + // Kept for backwards compatibility export function defaultProviderBuilder( rpcUrls: RpcUrl[], @@ -117,6 +129,13 @@ export function defaultProviderBuilder( return defaultEthersV5ProviderBuilder(rpcUrls, _network).provider; } +export function defaultZKProviderBuilder( + rpcUrls: RpcUrl[], + _network: number | string, +): ZKProvider { + return defaultZKSyncProviderBuilder(rpcUrls, _network).provider; +} + export type ProviderBuilderMap = Record< ProviderType, ProviderBuilderFn @@ -128,6 +147,7 @@ export const defaultProviderBuilderMap: ProviderBuilderMap = { [ProviderType.SolanaWeb3]: defaultSolProviderBuilder, [ProviderType.CosmJs]: defaultCosmJsProviderBuilder, [ProviderType.CosmJsWasm]: defaultCosmJsWasmProviderBuilder, + [ProviderType.ZkSync]: defaultZKSyncProviderBuilder, }; export const protocolToDefaultProviderBuilder: Record< diff --git a/typescript/sdk/src/utils/zksync.ts b/typescript/sdk/src/utils/zksync.ts new file mode 100644 index 0000000000..0b97e4330c --- /dev/null +++ b/typescript/sdk/src/utils/zksync.ts @@ -0,0 +1,32 @@ +import { ZKSyncArtifact, loadAllZKSyncArtifacts } from '@hyperlane-xyz/core'; + +/** + * @dev Retrieves a ZkSync artifact by its contract name or qualified name. + * @param name The name of the contract or qualified name in the format "sourceName:contractName". + * @return The corresponding ZKSyncArtifact if found, or undefined if not found. + */ +export const getZKSyncArtifactByContractName = async ( + name: string, +): Promise => { + // Load all ZkSync artifacts + const allArtifacts = loadAllZKSyncArtifacts(); + + // Find the artifact that matches the contract name or qualified name + const artifact = Object.values(allArtifacts).find( + ({ contractName, sourceName }: ZKSyncArtifact) => { + const lowerCaseContractName = contractName.toLowerCase(); + const lowerCaseName = name.toLowerCase(); + + // Check if the contract name matches + if (lowerCaseContractName === lowerCaseName) { + return true; + } + + // Check if the qualified name matches + const qualifiedName = `${sourceName}:${contractName}`; + return qualifiedName === name; // Return true if qualified name matches + }, + ); + + return artifact; +}; diff --git a/typescript/sdk/src/zksync/ZKSyncDeployer.ts b/typescript/sdk/src/zksync/ZKSyncDeployer.ts new file mode 100644 index 0000000000..9206926311 --- /dev/null +++ b/typescript/sdk/src/zksync/ZKSyncDeployer.ts @@ -0,0 +1,185 @@ +import { BigNumber, BytesLike, Overrides, utils } from 'ethers'; +import { + Contract, + ContractFactory, + Wallet, + types as zksyncTypes, +} from 'zksync-ethers'; + +import { ZKSyncArtifact } from '@hyperlane-xyz/core'; +import { assert } from '@hyperlane-xyz/utils'; + +import { defaultZKProviderBuilder } from '../providers/providerBuilders.js'; +import { getZKSyncArtifactByContractName } from '../utils/zksync.js'; + +/** + * Class for deploying contracts to the ZKSync network. + */ +export class ZKSyncDeployer { + public zkWallet: Wallet; + public deploymentType?: zksyncTypes.DeploymentType; + + constructor(zkWallet: Wallet, deploymentType?: zksyncTypes.DeploymentType) { + this.deploymentType = deploymentType; + + this.zkWallet = zkWallet.connect( + zkWallet.provider ?? + defaultZKProviderBuilder([{ http: 'http://127.0.0.1:8011' }], 260), + ); + } + + /** + * Loads and validates a ZKSync contract artifact by name + * @param contractTitle - Contract name or qualified name (sourceName:contractName) + * + * @returns The ZKSync artifact + */ + private async loadArtifact(contractTitle: string): Promise { + const artifact = await getZKSyncArtifactByContractName(contractTitle); + assert(artifact, `No ZKSync artifact for contract ${contractTitle} found!`); + return artifact; + } + + /** + * Estimates the price of calling a deploy transaction in ETH. + * + * @param artifact The previously loaded artifact object. + * @param constructorArguments List of arguments to be passed to the contract constructor. + * + * @returns Calculated fee in ETH wei + */ + public async estimateDeployFee( + artifact: ZKSyncArtifact, + constructorArguments: any[], + ): Promise { + const gas = await this.estimateDeployGas(artifact, constructorArguments); + const gasPrice = await this.zkWallet.provider.getGasPrice(); + return gas.mul(gasPrice); + } + + /** + * Estimates the amount of gas needed to execute a deploy transaction. + * + * @param artifact The previously loaded artifact object. + * @param constructorArguments List of arguments to be passed to the contract constructor. + * + * @returns Calculated amount of gas. + */ + public async estimateDeployGas( + artifact: ZKSyncArtifact, + constructorArguments: any[], + ): Promise { + const factoryDeps = await this.extractFactoryDeps(artifact); + + const factory = new ContractFactory( + artifact.abi, + artifact.bytecode, + this.zkWallet, + this.deploymentType, + ); + + // Encode deploy transaction so it can be estimated. + const deployTx = factory.getDeployTransaction(...constructorArguments, { + customData: { + factoryDeps, + }, + }); + deployTx.from = this.zkWallet.address; + + return this.zkWallet.provider.estimateGas(deployTx); + } + + /** + * Sends a deploy transaction to the zkSync network. + * For now, it will use defaults for the transaction parameters: + * - fee amount is requested automatically from the zkSync server. + * + * @param artifact The previously loaded artifact object. + * @param constructorArguments List of arguments to be passed to the contract constructor. + * @param overrides Optional object with additional deploy transaction parameters. + * @param additionalFactoryDeps Additional contract bytecodes to be added to the factory dependencies list. + * + * @returns A contract object. + */ + public async deploy( + artifact: ZKSyncArtifact, + constructorArguments: any[] = [], + overrides?: Overrides, + additionalFactoryDeps?: BytesLike[], + ): Promise { + const baseDeps = await this.extractFactoryDeps(artifact); + const additionalDeps = additionalFactoryDeps + ? additionalFactoryDeps.map((val) => utils.hexlify(val)) + : []; + const factoryDeps = [...baseDeps, ...additionalDeps]; + + const factory = new ContractFactory( + artifact.abi, + artifact.bytecode, + this.zkWallet, + this.deploymentType, + ); + + const { customData, ..._overrides } = overrides ?? {}; + + // Encode and send the deploy transaction providing factory dependencies. + const contract = await factory.deploy(...constructorArguments, { + ..._overrides, + customData: { + ...customData, + factoryDeps, + }, + }); + + await contract.deployed(); + + return contract; + } + + /** + * Extracts factory dependencies from the artifact. + * + * @param artifact Artifact to extract dependencies from + * + * @returns Factory dependencies in the format expected by SDK. + */ + async extractFactoryDeps(artifact: ZKSyncArtifact): Promise { + const visited = new Set(); + + visited.add(`${artifact.sourceName}:${artifact.contractName}`); + return this.extractFactoryDepsRecursive(artifact, visited); + } + + private async extractFactoryDepsRecursive( + artifact: ZKSyncArtifact, + visited: Set, + ): Promise { + // Load all the dependency bytecodes. + // We transform it into an array of bytecodes. + const factoryDeps: string[] = []; + for (const dependencyHash in artifact.factoryDeps) { + if ( + Object.prototype.hasOwnProperty.call( + artifact.factoryDeps, + dependencyHash, + ) + ) { + const dependencyContract = artifact.factoryDeps[dependencyHash]; + if (!visited.has(dependencyContract)) { + const dependencyArtifact = await this.loadArtifact( + dependencyContract, + ); + factoryDeps.push(dependencyArtifact.bytecode); + visited.add(dependencyContract); + const transitiveDeps = await this.extractFactoryDepsRecursive( + dependencyArtifact, + visited, + ); + factoryDeps.push(...transitiveDeps); + } + } + } + + return factoryDeps; + } +} diff --git a/yarn.lock b/yarn.lock index a3575df63f..4330df460e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4240,6 +4240,13 @@ __metadata: languageName: node linkType: hard +"@balena/dockerignore@npm:^1.0.2": + version: 1.0.2 + resolution: "@balena/dockerignore@npm:1.0.2" + checksum: 10/13d654fdd725008577d32e721c720275bdc48f72bce612326363d5bed449febbed856c517a0b23c7c40d87cb531e63432804550b4ecc13e365d26fee38fb6c8a + languageName: node + linkType: hard + "@base2/pretty-print-object@npm:1.0.1": version: 1.0.1 resolution: "@base2/pretty-print-object@npm:1.0.1" @@ -7214,6 +7221,16 @@ __metadata: languageName: node linkType: hard +"@grpc/grpc-js@npm:^1.11.1": + version: 1.12.5 + resolution: "@grpc/grpc-js@npm:1.12.5" + dependencies: + "@grpc/proto-loader": "npm:^0.7.13" + "@js-sdsl/ordered-map": "npm:^4.4.2" + checksum: 10/4f8ead236dcab4d94e15e62d65ad2d93732d37f5cc52ffafe67ae00f69eae4a4c97d6d34a1b9eac9f30206468f2d15302ea6649afcba1d38929afa9d1e7c12d5 + languageName: node + linkType: hard + "@grpc/grpc-js@npm:~1.10.3": version: 1.10.8 resolution: "@grpc/grpc-js@npm:1.10.8" @@ -7370,6 +7387,7 @@ __metadata: "@hyperlane-xyz/utils": "npm:8.5.0" "@layerzerolabs/lz-evm-oapp-v2": "npm:2.0.2" "@layerzerolabs/solidity-examples": "npm:^1.1.0" + "@matterlabs/hardhat-zksync-solc": "npm:^1.2.4" "@nomiclabs/hardhat-ethers": "npm:^2.2.3" "@nomiclabs/hardhat-waffle": "npm:^2.0.6" "@openzeppelin/contracts": "npm:^4.9.3" @@ -7397,6 +7415,7 @@ __metadata: tsx: "npm:^4.19.1" typechain: "patch:typechain@npm%3A8.3.2#~/.yarn/patches/typechain-npm-8.3.2-b02e27439e.patch" typescript: "npm:5.3.3" + zksync-ethers: "npm:^5.10.0" peerDependencies: "@ethersproject/abi": "*" "@ethersproject/providers": "*" @@ -7596,6 +7615,7 @@ __metadata: typescript: "npm:5.3.3" viem: "npm:^2.21.45" yaml: "npm:2.4.5" + zksync-ethers: "npm:^5.10.0" zod: "npm:^3.21.2" peerDependencies: "@ethersproject/abi": "*" @@ -8744,6 +8764,27 @@ __metadata: languageName: node linkType: hard +"@matterlabs/hardhat-zksync-solc@npm:^1.2.4": + version: 1.2.5 + resolution: "@matterlabs/hardhat-zksync-solc@npm:1.2.5" + dependencies: + "@nomiclabs/hardhat-docker": "npm:^2.0.2" + chai: "npm:^4.3.4" + chalk: "npm:^4.1.2" + debug: "npm:^4.3.5" + dockerode: "npm:^4.0.2" + fs-extra: "npm:^11.2.0" + proper-lockfile: "npm:^4.1.2" + semver: "npm:^7.6.2" + sinon: "npm:^18.0.0" + sinon-chai: "npm:^3.7.0" + undici: "npm:^6.18.2" + peerDependencies: + hardhat: ^2.22.5 + checksum: 10/0452ad5504258fad2f2d10be40cc79bb0e65d3470af75f70f60e4a94bb92f238031a13587cda51a0dfd77ef1cb028145088e2628a02db6d7a5ac721bf2816bf0 + languageName: node + linkType: hard + "@mdx-js/react@npm:^2.1.5": version: 2.3.0 resolution: "@mdx-js/react@npm:2.3.0" @@ -9629,6 +9670,17 @@ __metadata: languageName: node linkType: hard +"@nomiclabs/hardhat-docker@npm:^2.0.2": + version: 2.0.2 + resolution: "@nomiclabs/hardhat-docker@npm:2.0.2" + dependencies: + dockerode: "npm:^2.5.8" + fs-extra: "npm:^7.0.1" + node-fetch: "npm:^2.6.0" + checksum: 10/2b6601a7bcac115a24dc4d2ce35b76b1748ffaebd723afad17e8f506231e1d6c7e5c9df73b29d429c5eb01cb0e11ff92f10c746ca31343b0fd3ddc449c9ec8f3 + languageName: node + linkType: hard + "@nomiclabs/hardhat-ethers@npm:^2.2.3": version: 2.2.3 resolution: "@nomiclabs/hardhat-ethers@npm:2.2.3" @@ -12977,7 +13029,7 @@ __metadata: languageName: node linkType: hard -"@sinonjs/commons@npm:^3.0.0": +"@sinonjs/commons@npm:^3.0.0, @sinonjs/commons@npm:^3.0.1": version: 3.0.1 resolution: "@sinonjs/commons@npm:3.0.1" dependencies: @@ -12986,6 +13038,15 @@ __metadata: languageName: node linkType: hard +"@sinonjs/fake-timers@npm:11.2.2": + version: 11.2.2 + resolution: "@sinonjs/fake-timers@npm:11.2.2" + dependencies: + "@sinonjs/commons": "npm:^3.0.0" + checksum: 10/da7dfa677b2362bc5a321fc1563184755b5c62fbb1a72457fb9e901cd187ba9dc834f9e8a0fb5a4e1d1e6e6ad4c5b54e90900faa44dd6c82d3c49c92ec23ecd4 + languageName: node + linkType: hard + "@sinonjs/fake-timers@npm:>=5, @sinonjs/fake-timers@npm:^9.1.2": version: 9.1.2 resolution: "@sinonjs/fake-timers@npm:9.1.2" @@ -13004,6 +13065,15 @@ __metadata: languageName: node linkType: hard +"@sinonjs/fake-timers@npm:^13.0.1": + version: 13.0.5 + resolution: "@sinonjs/fake-timers@npm:13.0.5" + dependencies: + "@sinonjs/commons": "npm:^3.0.1" + checksum: 10/11ee417968fc4dce1896ab332ac13f353866075a9d2a88ed1f6258f17cc4f7d93e66031b51fcddb8c203aa4d53fd980b0ae18aba06269f4682164878a992ec3f + languageName: node + linkType: hard + "@sinonjs/samsam@npm:^6.1.1": version: 6.1.1 resolution: "@sinonjs/samsam@npm:6.1.1" @@ -13015,6 +13085,17 @@ __metadata: languageName: node linkType: hard +"@sinonjs/samsam@npm:^8.0.0": + version: 8.0.2 + resolution: "@sinonjs/samsam@npm:8.0.2" + dependencies: + "@sinonjs/commons": "npm:^3.0.1" + lodash.get: "npm:^4.4.2" + type-detect: "npm:^4.1.0" + checksum: 10/58ca9752e8e835a09ed275f8edf8da2720fe95c0c02f6bcb90ad7f86fdceb393f35f744194b705dd94216228646ec0aedbb814e245eb869b940dcf1266b7a533 + languageName: node + linkType: hard + "@sinonjs/text-encoding@npm:^0.7.1": version: 0.7.1 resolution: "@sinonjs/text-encoding@npm:0.7.1" @@ -13022,6 +13103,13 @@ __metadata: languageName: node linkType: hard +"@sinonjs/text-encoding@npm:^0.7.3": + version: 0.7.3 + resolution: "@sinonjs/text-encoding@npm:0.7.3" + checksum: 10/f0cc89bae36e7ce159187dece7800b78831288f1913e9ae8cf8a878da5388232d2049740f6f4a43ec4b43b8ad1beb55f919f45eb9a577adb4a2a6eacb27b25fc + languageName: node + linkType: hard + "@smithy/abort-controller@npm:^3.0.0": version: 3.0.0 resolution: "@smithy/abort-controller@npm:3.0.0" @@ -17081,6 +17169,18 @@ __metadata: languageName: node linkType: hard +"JSONStream@npm:1.3.2": + version: 1.3.2 + resolution: "JSONStream@npm:1.3.2" + dependencies: + jsonparse: "npm:^1.2.0" + through: "npm:>=2.2.7 <3" + bin: + JSONStream: ./bin.js + checksum: 10/3a1274f39e9b0369da5d5536906b527113326434a43b92923ac2d3c2d449009253b245055de2633b1d9ca7ae30054b6091d755e79f0cb1c7dab9b6b253871812 + languageName: node + linkType: hard + "JSONStream@npm:^1.3.5": version: 1.3.5 resolution: "JSONStream@npm:1.3.5" @@ -17905,7 +18005,7 @@ __metadata: languageName: node linkType: hard -"asn1@npm:~0.2.3": +"asn1@npm:^0.2.6, asn1@npm:~0.2.3": version: 0.2.6 resolution: "asn1@npm:0.2.6" dependencies: @@ -18319,7 +18419,7 @@ __metadata: languageName: node linkType: hard -"bcrypt-pbkdf@npm:^1.0.0": +"bcrypt-pbkdf@npm:^1.0.0, bcrypt-pbkdf@npm:^1.0.2": version: 1.0.2 resolution: "bcrypt-pbkdf@npm:1.0.2" dependencies: @@ -18487,6 +18587,16 @@ __metadata: languageName: node linkType: hard +"bl@npm:^1.0.0": + version: 1.2.3 + resolution: "bl@npm:1.2.3" + dependencies: + readable-stream: "npm:^2.3.5" + safe-buffer: "npm:^5.1.1" + checksum: 10/11d775b09ebd7d8c0df1ed7efd03cc8a2b1283c804a55153c81a0b586728a085fa24240647cac9a60163eb6f36a28cf8c45b80bf460a46336d4c84c40205faff + languageName: node + linkType: hard + "bl@npm:^4.0.3, bl@npm:^4.1.0": version: 4.1.0 resolution: "bl@npm:4.1.0" @@ -18811,6 +18921,23 @@ __metadata: languageName: node linkType: hard +"buffer-alloc-unsafe@npm:^1.1.0": + version: 1.1.0 + resolution: "buffer-alloc-unsafe@npm:1.1.0" + checksum: 10/c5e18bf51f67754ec843c9af3d4c005051aac5008a3992938dda1344e5cfec77c4b02b4ca303644d1e9a6e281765155ce6356d85c6f5ccc5cd21afc868def396 + languageName: node + linkType: hard + +"buffer-alloc@npm:^1.2.0": + version: 1.2.0 + resolution: "buffer-alloc@npm:1.2.0" + dependencies: + buffer-alloc-unsafe: "npm:^1.1.0" + buffer-fill: "npm:^1.0.0" + checksum: 10/560cd27f3cbe73c614867da373407d4506309c62fe18de45a1ce191f3785ec6ca2488d802ff82065798542422980ca25f903db078c57822218182c37c3576df5 + languageName: node + linkType: hard + "buffer-crc32@npm:~0.2.3": version: 0.2.13 resolution: "buffer-crc32@npm:0.2.13" @@ -18825,6 +18952,13 @@ __metadata: languageName: node linkType: hard +"buffer-fill@npm:^1.0.0": + version: 1.0.0 + resolution: "buffer-fill@npm:1.0.0" + checksum: 10/c29b4723ddeab01e74b5d3b982a0c6828f2ded49cef049ddca3dac661c874ecdbcecb5dd8380cf0f4adbeb8cff90a7de724126750a1f1e5ebd4eb6c59a1315b1 + languageName: node + linkType: hard + "buffer-from@npm:^1.0.0": version: 1.1.2 resolution: "buffer-from@npm:1.1.2" @@ -18930,6 +19064,13 @@ __metadata: languageName: node linkType: hard +"buildcheck@npm:~0.0.6": + version: 0.0.6 + resolution: "buildcheck@npm:0.0.6" + checksum: 10/194ee8d3b0926fd6f3e799732130ad7ab194882c56900b8670ad43c81326f64871f49b7d9f1e9baad91ca3070eb4e8b678797fe9ae78cf87dde86d8916eb25d2 + languageName: node + linkType: hard + "busboy@npm:^1.6.0": version: 1.6.0 resolution: "busboy@npm:1.6.0" @@ -19388,7 +19529,7 @@ __metadata: languageName: node linkType: hard -"chownr@npm:^1.1.1, chownr@npm:^1.1.4": +"chownr@npm:^1.0.1, chownr@npm:^1.1.1, chownr@npm:^1.1.4": version: 1.1.4 resolution: "chownr@npm:1.1.4" checksum: 10/115648f8eb38bac5e41c3857f3e663f9c39ed6480d1349977c4d96c95a47266fcacc5a5aabf3cb6c481e22d72f41992827db47301851766c4fd77ac21a4f081d @@ -19923,7 +20064,7 @@ __metadata: languageName: node linkType: hard -"concat-stream@npm:^1.6.0, concat-stream@npm:^1.6.2": +"concat-stream@npm:^1.6.0, concat-stream@npm:^1.6.2, concat-stream@npm:~1.6.2": version: 1.6.2 resolution: "concat-stream@npm:1.6.2" dependencies: @@ -20152,6 +20293,17 @@ __metadata: languageName: node linkType: hard +"cpu-features@npm:~0.0.10": + version: 0.0.10 + resolution: "cpu-features@npm:0.0.10" + dependencies: + buildcheck: "npm:~0.0.6" + nan: "npm:^2.19.0" + node-gyp: "npm:latest" + checksum: 10/941b828ffe77582b2bdc03e894c913e2e2eeb5c6043ccb01338c34446d026f6888dc480ecb85e684809f9c3889d245f3648c7907eb61a92bdfc6aed039fcda8d + languageName: node + linkType: hard + "crc-32@npm:^1.2.0": version: 1.2.2 resolution: "crc-32@npm:1.2.2" @@ -20481,7 +20633,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:^3.1.0, debug@npm:^3.2.7": +"debug@npm:^3.1.0, debug@npm:^3.2.6, debug@npm:^3.2.7": version: 3.2.7 resolution: "debug@npm:3.2.7" dependencies: @@ -20943,6 +21095,13 @@ __metadata: languageName: node linkType: hard +"diff@npm:^5.2.0": + version: 5.2.0 + resolution: "diff@npm:5.2.0" + checksum: 10/01b7b440f83a997350a988e9d2f558366c0f90f15be19f4aa7f1bb3109a4e153dfc3b9fbf78e14ea725717017407eeaa2271e3896374a0181e8f52445740846d + languageName: node + linkType: hard + "difflib@npm:^0.2.4": version: 0.2.4 resolution: "difflib@npm:0.2.4" @@ -20975,6 +21134,56 @@ __metadata: languageName: node linkType: hard +"docker-modem@npm:^1.0.8": + version: 1.0.9 + resolution: "docker-modem@npm:1.0.9" + dependencies: + JSONStream: "npm:1.3.2" + debug: "npm:^3.2.6" + readable-stream: "npm:~1.0.26-4" + split-ca: "npm:^1.0.0" + checksum: 10/2ade3d9f1b25231a5ecadcbfb9401a397eff3de2eec7add8130de1c40004faaa58fe074e5110ccef12957973089e5911b711648c77944a4a15d908e9b9605549 + languageName: node + linkType: hard + +"docker-modem@npm:^5.0.6": + version: 5.0.6 + resolution: "docker-modem@npm:5.0.6" + dependencies: + debug: "npm:^4.1.1" + readable-stream: "npm:^3.5.0" + split-ca: "npm:^1.0.1" + ssh2: "npm:^1.15.0" + checksum: 10/4977797814c29205f0762215f2e3e26600986bb65139018ff6840ff4c596e5d19f3002be1abcc5e73e3828870bb73bab28275a6458ad027ed56ab61fca014b6d + languageName: node + linkType: hard + +"dockerode@npm:^2.5.8": + version: 2.5.8 + resolution: "dockerode@npm:2.5.8" + dependencies: + concat-stream: "npm:~1.6.2" + docker-modem: "npm:^1.0.8" + tar-fs: "npm:~1.16.3" + checksum: 10/13111cfcaf47905cd2cd323a07cb5b79404ef5e9032e33ef3a6f71d1f72283d9b2921b6de955c8454b147bbf4db33822a80d960b2250e3e8aed62ffe0b43083f + languageName: node + linkType: hard + +"dockerode@npm:^4.0.2": + version: 4.0.4 + resolution: "dockerode@npm:4.0.4" + dependencies: + "@balena/dockerignore": "npm:^1.0.2" + "@grpc/grpc-js": "npm:^1.11.1" + "@grpc/proto-loader": "npm:^0.7.13" + docker-modem: "npm:^5.0.6" + protobufjs: "npm:^7.3.2" + tar-fs: "npm:~2.0.1" + uuid: "npm:^10.0.0" + checksum: 10/db2304e6125d0c4246833eaa6a389497c98564ba2ed18fa465eace1b6eb6c2a41f1711fc1e57cd2fc0f7ca6be80eeca43b0c35cd6b86205e34faf9acb0f72bcc + languageName: node + linkType: hard + "doctrine@npm:^2.1.0": version: 2.1.0 resolution: "doctrine@npm:2.1.0" @@ -23674,6 +23883,17 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:^11.2.0": + version: 11.3.0 + resolution: "fs-extra@npm:11.3.0" + dependencies: + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^6.0.1" + universalify: "npm:^2.0.0" + checksum: 10/c9fe7b23dded1efe7bbae528d685c3206477e20cc60e9aaceb3f024f9b9ff2ee1f62413c161cb88546cc564009ab516dec99e9781ba782d869bb37e4fe04a97f + languageName: node + linkType: hard + "fs-extra@npm:^4.0.2": version: 4.0.3 resolution: "fs-extra@npm:4.0.3" @@ -27286,6 +27506,13 @@ __metadata: languageName: node linkType: hard +"just-extend@npm:^6.2.0": + version: 6.2.0 + resolution: "just-extend@npm:6.2.0" + checksum: 10/1f487b074b9e5773befdd44dc5d1b446f01f24f7d4f1f255d51c0ef7f686e8eb5f95d983b792b9ca5c8b10cd7e60a924d64103725759eddbd7f18bcb22743f92 + languageName: node + linkType: hard + "jwa@npm:^2.0.0": version: 2.0.0 resolution: "jwa@npm:2.0.0" @@ -29114,7 +29341,7 @@ __metadata: languageName: node linkType: hard -"nan@npm:^2.13.2": +"nan@npm:^2.13.2, nan@npm:^2.19.0, nan@npm:^2.20.0": version: 2.22.0 resolution: "nan@npm:2.22.0" dependencies: @@ -29226,6 +29453,19 @@ __metadata: languageName: node linkType: hard +"nise@npm:^6.0.0": + version: 6.1.1 + resolution: "nise@npm:6.1.1" + dependencies: + "@sinonjs/commons": "npm:^3.0.1" + "@sinonjs/fake-timers": "npm:^13.0.1" + "@sinonjs/text-encoding": "npm:^0.7.3" + just-extend: "npm:^6.2.0" + path-to-regexp: "npm:^8.1.0" + checksum: 10/2d3175587cf0a351e2c91eb643fdc59d266de39f394a3ac0bace38571749d1e7f25341d763899245139b8f0d2ee048b2d3387d75ecf94c4897e947d5fc881eea + languageName: node + linkType: hard + "nock@npm:13.5.4": version: 13.5.4 resolution: "nock@npm:13.5.4" @@ -30364,6 +30604,13 @@ __metadata: languageName: node linkType: hard +"path-to-regexp@npm:^8.1.0": + version: 8.2.0 + resolution: "path-to-regexp@npm:8.2.0" + checksum: 10/23378276a172b8ba5f5fb824475d1818ca5ccee7bbdb4674701616470f23a14e536c1db11da9c9e6d82b82c556a817bbf4eee6e41b9ed20090ef9427cbb38e13 + languageName: node + linkType: hard + "path-type@npm:^4.0.0": version: 4.0.0 resolution: "path-type@npm:4.0.0" @@ -31025,7 +31272,7 @@ __metadata: languageName: node linkType: hard -"proper-lockfile@npm:^4.1.1": +"proper-lockfile@npm:^4.1.1, proper-lockfile@npm:^4.1.2": version: 4.1.2 resolution: "proper-lockfile@npm:4.1.2" dependencies: @@ -31116,6 +31363,26 @@ __metadata: languageName: node linkType: hard +"protobufjs@npm:^7.3.2": + version: 7.4.0 + resolution: "protobufjs@npm:7.4.0" + dependencies: + "@protobufjs/aspromise": "npm:^1.1.2" + "@protobufjs/base64": "npm:^1.1.2" + "@protobufjs/codegen": "npm:^2.0.4" + "@protobufjs/eventemitter": "npm:^1.1.0" + "@protobufjs/fetch": "npm:^1.1.0" + "@protobufjs/float": "npm:^1.0.2" + "@protobufjs/inquire": "npm:^1.1.0" + "@protobufjs/path": "npm:^1.1.2" + "@protobufjs/pool": "npm:^1.1.0" + "@protobufjs/utf8": "npm:^1.1.0" + "@types/node": "npm:>=13.7.0" + long: "npm:^5.0.0" + checksum: 10/408423506610f70858d7593632f4a6aa4f05796c90fd632be9b9252457c795acc71aa6d3b54bb7f48a890141728fee4ca3906723ccea6c202ad71f21b3879b8b + languageName: node + linkType: hard + "proxy-addr@npm:~2.0.7": version: 2.0.7 resolution: "proxy-addr@npm:2.0.7" @@ -31168,6 +31435,16 @@ __metadata: languageName: node linkType: hard +"pump@npm:^1.0.0": + version: 1.0.3 + resolution: "pump@npm:1.0.3" + dependencies: + end-of-stream: "npm:^1.1.0" + once: "npm:^1.3.1" + checksum: 10/61fe58694f9900020a5cf5bc765d74396891c201afecf06659df2f5874fd832be4e19e2f95cc72d8b9eb98ace0a4db3cebf7343f9fc893a930577be29e3ad8b5 + languageName: node + linkType: hard + "pump@npm:^2.0.0": version: 2.0.1 resolution: "pump@npm:2.0.1" @@ -31898,7 +32175,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^2.0.0, readable-stream@npm:^2.3.3, readable-stream@npm:~2.3.6": +"readable-stream@npm:^2.0.0, readable-stream@npm:^2.3.0, readable-stream@npm:^2.3.3, readable-stream@npm:^2.3.5, readable-stream@npm:~2.3.6": version: 2.3.8 resolution: "readable-stream@npm:2.3.8" dependencies: @@ -31928,7 +32205,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^3.1.0, readable-stream@npm:^3.6.2": +"readable-stream@npm:^3.1.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.2": version: 3.6.2 resolution: "readable-stream@npm:3.6.2" dependencies: @@ -31963,6 +32240,18 @@ __metadata: languageName: node linkType: hard +"readable-stream@npm:~1.0.26-4": + version: 1.0.34 + resolution: "readable-stream@npm:1.0.34" + dependencies: + core-util-is: "npm:~1.0.0" + inherits: "npm:~2.0.1" + isarray: "npm:0.0.1" + string_decoder: "npm:~0.10.x" + checksum: 10/20537fca5a8ffd4af0f483be1cce0e981ed8cbb1087e0c762e2e92ae77f1005627272cebed8422f28047b465056aa1961fefd24baf532ca6a3616afea6811ae0 + languageName: node + linkType: hard + "readdirp@npm:~3.2.0": version: 3.2.0 resolution: "readdirp@npm:3.2.0" @@ -33407,6 +33696,16 @@ __metadata: languageName: node linkType: hard +"sinon-chai@npm:^3.7.0": + version: 3.7.0 + resolution: "sinon-chai@npm:3.7.0" + peerDependencies: + chai: ^4.0.0 + sinon: ">=4.0.0" + checksum: 10/028853eb8a545ca613c6863014a40f07d1e6b81467e20939fefcd13f170206d24165b91099fb297aeb4d137745e321da25daa8e2d665cc0a78f90d5b877e8bbe + languageName: node + linkType: hard + "sinon@npm:^13.0.2": version: 13.0.2 resolution: "sinon@npm:13.0.2" @@ -33421,6 +33720,20 @@ __metadata: languageName: node linkType: hard +"sinon@npm:^18.0.0": + version: 18.0.1 + resolution: "sinon@npm:18.0.1" + dependencies: + "@sinonjs/commons": "npm:^3.0.1" + "@sinonjs/fake-timers": "npm:11.2.2" + "@sinonjs/samsam": "npm:^8.0.0" + diff: "npm:^5.2.0" + nise: "npm:^6.0.0" + supports-color: "npm:^7" + checksum: 10/65be65a7c5dbef7e9e315820bcd17fe0387fb07cb5dd41d3d6a89177e9a2ca463144676d8407348dc075758daa7cf37b9376d35bd1bc7e06717e87d03aa26111 + languageName: node + linkType: hard + "sisteransi@npm:^1.0.5": version: 1.0.5 resolution: "sisteransi@npm:1.0.5" @@ -33920,6 +34233,13 @@ __metadata: languageName: node linkType: hard +"split-ca@npm:^1.0.0, split-ca@npm:^1.0.1": + version: 1.0.1 + resolution: "split-ca@npm:1.0.1" + checksum: 10/1e7409938a95ee843fe2593156a5735e6ee63772748ee448ea8477a5a3e3abde193c3325b3696e56a5aff07c7dcf6b1f6a2f2a036895b4f3afe96abb366d893f + languageName: node + linkType: hard + "split-on-first@npm:^1.0.0": version: 1.1.0 resolution: "split-on-first@npm:1.1.0" @@ -33941,6 +34261,23 @@ __metadata: languageName: node linkType: hard +"ssh2@npm:^1.15.0": + version: 1.16.0 + resolution: "ssh2@npm:1.16.0" + dependencies: + asn1: "npm:^0.2.6" + bcrypt-pbkdf: "npm:^1.0.2" + cpu-features: "npm:~0.0.10" + nan: "npm:^2.20.0" + dependenciesMeta: + cpu-features: + optional: true + nan: + optional: true + checksum: 10/0951c22d9c5a0e3b89a8e5ae890ebcbce9f1f94dbed37d1490e4e48e26bc8b074fa81f202ee57b708e31b5f33033f4c870b92047f4f02b6bc26c32225b01d84c + languageName: node + linkType: hard + "sshpk@npm:^1.7.0": version: 1.17.0 resolution: "sshpk@npm:1.17.0" @@ -34339,6 +34676,13 @@ __metadata: languageName: node linkType: hard +"string_decoder@npm:~0.10.x": + version: 0.10.31 + resolution: "string_decoder@npm:0.10.31" + checksum: 10/cc43e6b1340d4c7843da0e37d4c87a4084c2342fc99dcf6563c3ec273bb082f0cbd4ebf25d5da19b04fb16400d393885fda830be5128e1c416c73b5a6165f175 + languageName: node + linkType: hard + "string_decoder@npm:~1.1.1": version: 1.1.1 resolution: "string_decoder@npm:1.1.1" @@ -34576,7 +34920,7 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:^7.0.0, supports-color@npm:^7.1.0, supports-color@npm:^7.2.0": +"supports-color@npm:^7, supports-color@npm:^7.0.0, supports-color@npm:^7.1.0, supports-color@npm:^7.2.0": version: 7.2.0 resolution: "supports-color@npm:7.2.0" dependencies: @@ -34803,7 +35147,46 @@ __metadata: languageName: node linkType: hard -"tar-stream@npm:^2.1.4": +"tar-fs@npm:~1.16.3": + version: 1.16.4 + resolution: "tar-fs@npm:1.16.4" + dependencies: + chownr: "npm:^1.0.1" + mkdirp: "npm:^0.5.1" + pump: "npm:^1.0.0" + tar-stream: "npm:^1.1.2" + checksum: 10/2392fb92ebcdbf1b70961192a0f32955dbfc5cd844d4980e7e0dc7b8cb269d6e23831ae8ceb8137322367dcc42ae946f2349d0fd79b89b3c30b0a7d3ff5fc15e + languageName: node + linkType: hard + +"tar-fs@npm:~2.0.1": + version: 2.0.1 + resolution: "tar-fs@npm:2.0.1" + dependencies: + chownr: "npm:^1.1.1" + mkdirp-classic: "npm:^0.5.2" + pump: "npm:^3.0.0" + tar-stream: "npm:^2.0.0" + checksum: 10/85ceac6fce0e9175b5b67c0eca8864b7d29a940cae8b7657c60b66e8a252319d701c3df12814162a6839e6120f9e1975757293bdeaf294ad5b15721d236c4d32 + languageName: node + linkType: hard + +"tar-stream@npm:^1.1.2": + version: 1.6.2 + resolution: "tar-stream@npm:1.6.2" + dependencies: + bl: "npm:^1.0.0" + buffer-alloc: "npm:^1.2.0" + end-of-stream: "npm:^1.0.0" + fs-constants: "npm:^1.0.0" + readable-stream: "npm:^2.3.0" + to-buffer: "npm:^1.1.1" + xtend: "npm:^4.0.0" + checksum: 10/ac9b850bd40e6d4b251abcf92613bafd9fc9e592c220c781ebcdbb0ba76da22a245d9ea3ea638ad7168910e7e1ae5079333866cd679d2f1ffadb99c403f99d7f + languageName: node + linkType: hard + +"tar-stream@npm:^2.0.0, tar-stream@npm:^2.1.4": version: 2.2.0 resolution: "tar-stream@npm:2.2.0" dependencies: @@ -35105,6 +35488,13 @@ __metadata: languageName: node linkType: hard +"to-buffer@npm:^1.1.1": + version: 1.1.1 + resolution: "to-buffer@npm:1.1.1" + checksum: 10/8ade59fe04239b281496b6067bc83ad0371a3657552276cbd09ffffaeb3ad0018a28306d61b854b83280eabe1829cbc53001ccd761e834c6062cbcc7fee2766a + languageName: node + linkType: hard + "to-fast-properties@npm:^2.0.0": version: 2.0.0 resolution: "to-fast-properties@npm:2.0.0" @@ -36367,6 +36757,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:^10.0.0": + version: 10.0.0 + resolution: "uuid@npm:10.0.0" + bin: + uuid: dist/bin/uuid + checksum: 10/35aa60614811a201ff90f8ca5e9ecb7076a75c3821e17f0f5ff72d44e36c2d35fcbc2ceee9c4ac7317f4cc41895da30e74f3885e30313bee48fda6338f250538 + languageName: node + linkType: hard + "uuid@npm:^3.3.2": version: 3.4.0 resolution: "uuid@npm:3.4.0"