From 8c7fd79e94a9501a5b36b810e70a961a3109381c Mon Sep 17 00:00:00 2001 From: Petar Penovic Date: Mon, 14 Aug 2023 13:50:26 +0200 Subject: [PATCH 1/5] Remove CLI emulation for starknet.js wrapper --- src/account-utils.ts | 4 +- src/extend-utils.ts | 77 +++++++++--------------- src/index.ts | 4 +- src/starknet-js-wrapper.ts | 120 ++++--------------------------------- src/starknet-wrappers.ts | 62 ------------------- src/task-actions.ts | 18 ++++-- src/type-extensions.ts | 8 ++- src/types/index.ts | 114 ++++++++++++++++------------------- src/utils.ts | 26 +++++--- 9 files changed, 132 insertions(+), 301 deletions(-) diff --git a/src/account-utils.ts b/src/account-utils.ts index 0e131180..1f1435fd 100644 --- a/src/account-utils.ts +++ b/src/account-utils.ts @@ -163,7 +163,7 @@ export async function sendDeployAccountTx( return new Promise((resolve, reject) => { iterativelyCheckStatus( resp.data.transaction_hash, - hre.starknetWrapper, + hre, () => resolve(resp.data.transaction_hash), reject ); @@ -199,7 +199,7 @@ export async function sendDeclareV2Tx( return new Promise((resolve, reject) => { iterativelyCheckStatus( resp.data.transaction_hash, - hre.starknetWrapper, + hre, () => resolve(resp.data.transaction_hash), reject ); diff --git a/src/extend-utils.ts b/src/extend-utils.ts index 4a85323d..ae1652d4 100644 --- a/src/extend-utils.ts +++ b/src/extend-utils.ts @@ -1,6 +1,6 @@ import { Block, HardhatRuntimeEnvironment, Transaction } from "hardhat/types"; import path from "path"; -import { uint256 } from "starknet"; +import { SequencerProvider, uint256 } from "starknet"; import { handleInternalContractArtifacts } from "./account-utils"; import { @@ -95,76 +95,58 @@ export async function getTransactionUtil( txHash: string, hre: HardhatRuntimeEnvironment ): Promise { - const executed = await hre.starknetWrapper.getTransaction({ - hash: txHash - }); - if (executed.statusCode) { - const msg = `Could not get the transaction. ${executed.stderr.toString()}`; + try { + const transaction = await hre.starknetProvider.getTransaction(txHash); + return transaction as Transaction; + } catch (error) { + const msg = `Could not get the transaction. ${error}`; throw new StarknetPluginError(msg); } - const txReceipt = JSON.parse(executed.stdout.toString()) as Transaction; - return txReceipt; } export async function getTransactionReceiptUtil( txHash: string, hre: HardhatRuntimeEnvironment ): Promise { - const executed = await hre.starknetWrapper.getTransactionReceipt({ - hash: txHash - }); - if (executed.statusCode) { - const msg = `Could not get the transaction receipt. Error: ${executed.stderr.toString()}`; + try { + const receipt = await hre.starknetProvider.getTransactionReceipt(txHash); + return receipt as unknown as TransactionReceipt; + } catch (error) { + const msg = `Could not get the transaction receipt. Error: ${error}`; throw new StarknetPluginError(msg); } - const txReceipt = JSON.parse(executed.stdout.toString()) as TransactionReceipt; - return txReceipt; } export async function getTransactionTraceUtil( txHash: string, hre: HardhatRuntimeEnvironment ): Promise { - const executed = await hre.starknetWrapper.getTransactionTrace({ - hash: txHash - }); - - if (executed.statusCode) { - const msg = `Could not get the transaction trace. Error: ${executed.stderr.toString()}`; + try { + const trace = await (hre.starknetProvider as SequencerProvider).getTransactionTrace(txHash); + return trace as TransactionTrace; + } catch (error) { + const msg = `Could not get the transaction trace. Error: ${error}`; throw new StarknetPluginError(msg); } - const txTrace = JSON.parse(executed.stdout.toString()) as TransactionTrace; - return txTrace; } export async function getBlockUtil( hre: HardhatRuntimeEnvironment, identifier?: BlockIdentifier ): Promise { - const blockOptions = { - feederGatewayUrl: hre.starknet.networkConfig.url, - gatewayUrl: hre.starknet.networkConfig.url, - number: identifier?.blockNumber, - hash: identifier?.blockHash - }; - if (identifier && typeof identifier !== "object") { const msg = `Invalid identifier provided to getBlock: ${identifier}`; throw new StarknetPluginError(msg); } - if (blockOptions.number == null && !blockOptions.hash) { - blockOptions.number = "latest"; - } - - const executed = await hre.starknetWrapper.getBlock(blockOptions); - - if (executed.statusCode) { - const msg = `Could not get block. Error: ${executed.stderr.toString()}`; + try { + const blockIdentifier = identifier?.blockHash ?? identifier?.blockNumber; + const block = hre.starknetProvider.getBlock(blockIdentifier); + return block; + } catch (error) { + const msg = `Could not get block. Error: ${error}`; throw new StarknetPluginError(msg); } - const block = JSON.parse(executed.stdout.toString()) as Block; - return block; } export async function getNonceUtil( @@ -172,17 +154,14 @@ export async function getNonceUtil( address: string, options: NonceQueryOptions ): Promise { - const executed = await hre.starknetWrapper.getNonce({ - address, - ...options - }); - - if (executed.statusCode) { - const msg = `Could not get nonce. Error: ${executed.stderr.toString()}`; + try { + const blockIdentifier = options?.blockHash ?? options?.blockNumber; + const nonce = await hre.starknetProvider.getNonceForAddress(address, blockIdentifier); + return parseInt(nonce); + } catch (error) { + const msg = `Could not get nonce. Error: ${error}`; throw new StarknetPluginError(msg); } - - return parseInt(executed.stdout.toString()); } export async function getBalanceUtil( diff --git a/src/index.ts b/src/index.ts index 15afeccf..5d2c982b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -65,7 +65,7 @@ import { DevnetUtils } from "./devnet-utils"; import { ExternalServer } from "./external-server"; import { ArgentAccount, OpenZeppelinAccount } from "./account"; import { AmarnaDocker } from "./external-server/docker-amarna"; -import { StarknetLegacyWrapper } from "./starknet-js-wrapper"; +import { StarknetJsWrapper } from "./starknet-js-wrapper"; exitHook(() => { ExternalServer.cleanAll(); @@ -171,7 +171,7 @@ function setVenvWrapper(hre: HardhatRuntimeEnvironment, venvPath: string) { // add venv wrapper or docker wrapper of starknet extendEnvironment((hre) => { - hre.starknetJs = new StarknetLegacyWrapper(hre.config.starknet.networkConfig); + hre.starknetJs = new StarknetJsWrapper(hre); const venvPath = hre.config.starknet.venv; if (venvPath) { diff --git a/src/starknet-js-wrapper.ts b/src/starknet-js-wrapper.ts index be910ac4..eabde53d 100644 --- a/src/starknet-js-wrapper.ts +++ b/src/starknet-js-wrapper.ts @@ -1,118 +1,20 @@ -import { ProcessResult } from "@nomiclabs/hardhat-docker"; -import { promises as fsp } from "fs"; -import { NetworkConfig } from "hardhat/types/config"; -import { - BigNumberish, - BlockIdentifier, - json, - provider as providerUtil, - SequencerProvider -} from "starknet"; +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { ProviderInterface, SequencerProvider } from "starknet"; export class StarknetJsWrapper { - public provider: SequencerProvider; + public provider: ProviderInterface; - constructor(networkConfig: NetworkConfig) { - this.setProvider(networkConfig); + private hre: HardhatRuntimeEnvironment; + + constructor(hre: HardhatRuntimeEnvironment) { + this.hre = hre; + this.setProvider(); } - public setProvider(networkConfig: NetworkConfig) { + public setProvider() { this.provider = new SequencerProvider({ - baseUrl: networkConfig.url + baseUrl: this.hre.config.starknet.networkConfig.url }); - } -} - -/** - * StarknetLegacyWrapper is meant to facilitate the discontinuation of the Starknet CLI usage within StarknetWrapper - */ -export class StarknetLegacyWrapper extends StarknetJsWrapper { - private async readContract(contractPath: string) { - return json.parse((await fsp.readFile(contractPath)).toString("ascii")); - } - - private stringifyResponse(r: unknown) { - return typeof r !== "string" - ? `${json.stringify(r, undefined, "\n").replace(/\n+/g, "\n")}\n` - : r; - } - - private generateProcessResult( - statusCode: number, - stdout: string, - stderr: string - ): ProcessResult { - return { - statusCode, - stdout, - stderr - } as unknown as ProcessResult; - } - - private async wrapProcessResult(p: Promise): Promise { - return p - .then((a) => this.generateProcessResult(0, this.stringifyResponse(a), "")) - .catch((e) => this.generateProcessResult(1, "", this.stringifyResponse(e))); - } - - public async declare( - contractPath: string, - senderAddress: string, - signature: string[], - nonce: string, - maxFee: string - ): Promise { - const contractJson = await this.readContract(contractPath); - const contract = providerUtil.parseContract(contractJson); - - return this.wrapProcessResult( - this.provider - .declareContract( - { - contract, - senderAddress, - signature - }, - { - nonce, - maxFee - } - ) - .then( - ({ class_hash, transaction_hash }) => - "DeprecatedDeclare transaction was sent.\n" + - `Contract class hash: ${class_hash}\n` + - `Transaction hash: ${transaction_hash}\n` - ) - ); - } - - public async getTxStatus(txHash: BigNumberish): Promise { - return this.wrapProcessResult(this.provider.getTransactionStatus(txHash)); - } - - public async getTransactionTrace(txHash: BigNumberish): Promise { - return this.wrapProcessResult(this.provider.getTransactionTrace(txHash)); - } - - public async getTransactionReceipt(txHash: BigNumberish): Promise { - return this.wrapProcessResult(this.provider.getTransactionReceipt(txHash)); - } - - public async getTransaction(txHash: BigNumberish): Promise { - return this.wrapProcessResult(this.provider.getTransaction(txHash)); - } - - public async getBlock(blockIdentifier?: BlockIdentifier): Promise { - return this.wrapProcessResult(this.provider.getBlock(blockIdentifier)); - } - - public async getNonce( - address: string, - blockIdentifier?: BlockIdentifier - ): Promise { - return this.wrapProcessResult( - this.provider.getNonceForAddress(address, blockIdentifier).then(BigInt) - ); + this.hre.starknetProvider = this.provider; } } diff --git a/src/starknet-wrappers.ts b/src/starknet-wrappers.ts index bec4e6ac..95ff068d 100644 --- a/src/starknet-wrappers.ts +++ b/src/starknet-wrappers.ts @@ -16,7 +16,6 @@ import { StarknetDockerProxy } from "./starknet-docker-proxy"; import { StarknetPluginError } from "./starknet-plugin-error"; import { FeeEstimation } from "./starknet-types"; import { StarknetVenvProxy } from "./starknet-venv-proxy"; -import { BlockNumber } from "./types"; import { getPrefixedCommand, normalizeVenvPath } from "./utils/venv"; interface CompileWrapperOptions { @@ -47,30 +46,6 @@ interface SierraToCasmOptions { addPythonicHints?: boolean; } -interface DeclareWrapperOptions { - contract: string; - maxFee: string; - signature?: string[]; - token?: string; - sender?: string; - nonce?: string; -} - -interface TxHashQueryWrapperOptions { - hash: string; -} - -interface BlockQueryWrapperOptions { - number?: BlockNumber; - hash?: string; -} - -interface NonceQueryWrapperOptions { - address: string; - blockHash?: string; - blockNumber?: BlockNumber; -} - export abstract class StarknetWrapper { constructor( protected externalServer: ExternalServer, @@ -214,43 +189,6 @@ export abstract class StarknetWrapper { return [cairo1Bin, ...args]; } - public async declare(options: DeclareWrapperOptions): Promise { - return this.hre.starknetJs.declare( - options.contract, - options.sender, - options.signature, - options.nonce, - options.maxFee - ); - } - - public async getTxStatus(options: TxHashQueryWrapperOptions): Promise { - return this.hre.starknetJs.getTxStatus(options.hash); - } - - public async getTransactionTrace(options: TxHashQueryWrapperOptions): Promise { - return this.hre.starknetJs.getTransactionTrace(options.hash); - } - - public async getTransactionReceipt(options: TxHashQueryWrapperOptions): Promise { - return this.hre.starknetJs.getTransactionReceipt(options.hash); - } - - public async getTransaction(options: TxHashQueryWrapperOptions): Promise { - return await this.hre.starknetJs.getTransaction(options.hash); - } - - public async getBlock(options: BlockQueryWrapperOptions): Promise { - return this.hre.starknetJs.getBlock(options.hash ?? options.number); - } - - public async getNonce(options: NonceQueryWrapperOptions): Promise { - return this.hre.starknetJs.getNonce( - options.address, - options.blockHash ?? options.blockNumber - ); - } - public async getClassHash(artifactPath: string): Promise { const executed = await this.execute("get_class_hash", [artifactPath]); if (executed.statusCode) { diff --git a/src/task-actions.ts b/src/task-actions.ts index 3057b5c9..fa6604c8 100644 --- a/src/task-actions.ts +++ b/src/task-actions.ts @@ -11,7 +11,15 @@ import { DEFAULT_STARKNET_NETWORK } from "./constants"; import { ProcessResult } from "@nomiclabs/hardhat-docker"; -import { adaptLog, traverseFiles, getNetwork, isStarknetDevnet, adaptPath } from "./utils"; +import { + adaptLog, + adaptPath, + getNetwork, + isStarknetDevnet, + readContractAsync, + readContractSync, + traverseFiles +} from "./utils"; import { HardhatNetworkConfig, HardhatRuntimeEnvironment, @@ -128,7 +136,7 @@ function loadScarbMainArtifact(scarbArtifactDirPath: string, packageName: string const msg = `Error in building ${packageName}, could not find ${mainPackageArtifactPath}`; throw new StarknetPluginError(msg); } - return JSON.parse(fs.readFileSync(mainPackageArtifactPath, "utf-8").toString()); + return readContractSync(mainPackageArtifactPath, "utf-8"); } async function findPackageConfigPaths( @@ -209,7 +217,7 @@ export async function starknetCompileCairo1Action( const abiOutput = path.join(dirPath, `${fileName}${ABI_SUFFIX}`); initializeFile(abiOutput); - const outputJson = JSON.parse(fs.readFileSync(outputPath, "utf-8")); + const outputJson = await readContractAsync(outputPath, "utf-8"); fs.writeFileSync(abiOutput, JSON.stringify(outputJson.abi) + "\n"); const casmOutput = path.join(dirPath, `${fileName}${CAIRO1_ASSEMBLY_SUFFIX}`); @@ -382,7 +390,7 @@ export async function starknetBuildAction(args: TaskArguments, hre: HardhatRunti const abiOutput = path.join(ourArtifactDirPath, `${fileName}${ABI_SUFFIX}`); initializeFile(abiOutput); - const outputJson = JSON.parse(fs.readFileSync(scarbSierraPath, "utf-8")); + const outputJson = readContractSync(scarbSierraPath, "utf-8"); fs.writeFileSync(abiOutput, JSON.stringify(outputJson.abi) + "\n"); } @@ -569,7 +577,7 @@ function setRuntimeNetwork(args: TaskArguments, hre: HardhatRuntimeEnvironment) hre.starknet.network = networkName; hre.starknet.networkConfig = networkConfig; - hre.starknetJs.setProvider(hre.starknet.networkConfig); + hre.starknetJs.setProvider(); console.log(`Using network ${hre.starknet.network} at ${hre.starknet.networkConfig.url}`); } diff --git a/src/type-extensions.ts b/src/type-extensions.ts index 24b1313b..f4c62956 100644 --- a/src/type-extensions.ts +++ b/src/type-extensions.ts @@ -1,12 +1,12 @@ import "hardhat/types/config"; import "hardhat/types/runtime"; -import { GetBlockResponse } from "starknet"; +import { GetBlockResponse, ProviderInterface } from "starknet"; import { Account } from "./account"; import { StarknetChainId } from "./constants"; import { AmarnaDocker } from "./external-server/docker-amarna"; import { Transaction, TransactionReceipt, TransactionTrace } from "./starknet-types"; -import { StarknetLegacyWrapper } from "./starknet-js-wrapper"; +import { StarknetJsWrapper } from "./starknet-js-wrapper"; import { StarknetWrapper } from "./starknet-wrappers"; import { StarknetContract, StarknetContractFactory, StringMap } from "./types"; import * as DevnetTypes from "./types/devnet"; @@ -90,7 +90,9 @@ declare module "hardhat/types/runtime" { starknetWrapper: StarknetWrapper; amarnaDocker: AmarnaDocker; starknet: StarknetTypes.Starknet; - starknetJs: StarknetLegacyWrapper; + + starknetJs: StarknetJsWrapper; + starknetProvider: ProviderInterface; } type StarknetContract = StarknetContractType; diff --git a/src/types/index.ts b/src/types/index.ts index 5532b6a1..2cd21043 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,6 +1,17 @@ import { HardhatRuntimeEnvironment } from "hardhat/types"; import fs from "node:fs"; -import { CallData, SequencerProvider, events as eventUtil, hash, json, selector } from "starknet"; +import { + CallData, + DeclareContractTransaction, + InvocationsDetailsWithNonce, + ProviderInterface, + SequencerProvider, + events as eventUtil, + hash, + json, + provider as providerUtil, + selector +} from "starknet"; import { adaptInputUtil, adaptOutputUtil, formatFelt } from "../adapt"; import { @@ -12,8 +23,15 @@ import { } from "../constants"; import { StarknetPluginError } from "../starknet-plugin-error"; import * as starknet from "../starknet-types"; -import { StarknetWrapper } from "../starknet-wrappers"; -import { adaptLog, copyWithBigint, findConstructor, sleep, warn } from "../utils"; +import { + adaptLog, + copyWithBigint, + findConstructor, + readContractAsync, + readContractSync, + sleep, + warn +} from "../utils"; /** * According to: https://starknet.io/docs/hello_starknet/intro.html#interact-with-the-contract @@ -113,24 +131,6 @@ export class InteractChoice { ) {} } -export function extractClassHash(response: string) { - return extractFromResponse(response, /^Contract class hash: (.*)$/m); -} - -function extractTxHash(response: string) { - return extractFromResponse(response, /^Transaction hash: (.*)$/m); -} - -function extractFromResponse(response: string, regex: RegExp) { - const matched = response.match(regex); - if (!matched || !matched[1]) { - throw new StarknetPluginError( - `Could not parse response. Check that you're using the correct network. Response received: ${response}` - ); - } - return matched[1]; -} - /** * The object returned by starknet tx_status. */ @@ -140,23 +140,6 @@ type StatusObject = { tx_failure_reason?: starknet.TxFailureReason; }; -async function checkStatus(hash: string, starknetWrapper: StarknetWrapper): Promise { - const executed = await starknetWrapper.getTxStatus({ - hash - }); - if (executed.statusCode) { - throw new StarknetPluginError(executed.stderr.toString()); - } - - const response = executed.stdout.toString(); - try { - const responseParsed = JSON.parse(response); - return responseParsed; - } catch (err) { - throw new StarknetPluginError(`Cannot interpret the following: ${response}`); - } -} - const ACCEPTABLE_STATUSES: TxStatus[] = ["PENDING", "ACCEPTED_ON_L2", "ACCEPTED_ON_L1"]; export function isTxAccepted(statusObject: StatusObject): boolean { return ACCEPTABLE_STATUSES.includes(statusObject.tx_status); @@ -169,7 +152,7 @@ function isTxRejected(statusObject: StatusObject): boolean { export async function iterativelyCheckStatus( txHash: string, - starknetWrapper: StarknetWrapper, + hre: HardhatRuntimeEnvironment, resolve: (status: string) => void, reject: (reason: Error) => void, retryCount = 10 @@ -181,10 +164,13 @@ export async function iterativelyCheckStatus( let error; while (count > 0) { // This promise is rejected usually if the network is unavailable - statusObject = await checkStatus(txHash, starknetWrapper).catch((reason) => { - error = reason; - return undefined; - }); + statusObject = await (hre.starknetProvider as SequencerProvider) + .getTransactionStatus(txHash) + .catch((err) => { + error = new StarknetPluginError(err); + return undefined; + }); + // Check count at 1 to avoid unnecessary waiting(sleep) in the last iteration if (statusObject || count === 1) { break; @@ -401,7 +387,7 @@ export class StarknetContractFactory { }; } - const casmJson = JSON.parse(fs.readFileSync(this.casmPath, "utf-8")); + const casmJson = readContractSync(this.casmPath, "utf-8"); if (casmJson?.compiler_version.split(".")[0] === "0") { const msg = ".CASM json should have been generated with a compiler version >= 1"; throw new StarknetPluginError(msg); @@ -432,26 +418,30 @@ export class StarknetContractFactory { * @returns transaction hash as a hex string */ async declare(options: DeclareOptions = {}): Promise { - const executed = await this.hre.starknetWrapper.declare({ - contract: this.metadataPath, - maxFee: (options.maxFee || 0).toString(), - token: options.token, - signature: handleSignature(options.signature), - sender: options.sender, - nonce: options.nonce?.toString() - }); - if (executed.statusCode) { - const msg = `Could not declare class: ${executed.stderr.toString()}`; - throw new StarknetPluginError(msg); - } + const contractJson = await readContractAsync(this.metadataPath); + const contract = providerUtil.parseContract(contractJson); - const executedOutput = executed.stdout.toString(); - const txHash = extractTxHash(executedOutput); + const transaction: DeclareContractTransaction = { + contract, + senderAddress: options.sender, + signature: handleSignature(options.signature) + }; + const details: InvocationsDetailsWithNonce = { + maxFee: options.maxFee, + nonce: options.nonce + }; + const contractResponse = await this.hre.starknetProvider + .declareContract(transaction, details) + .catch((error) => { + const msg = `Could not declare class: ${error}`; + throw new StarknetPluginError(msg); + }); + const txHash = contractResponse.transaction_hash; return new Promise((resolve, reject) => { iterativelyCheckStatus( txHash, - this.hre.starknetWrapper, + this.hre, () => resolve(txHash), (error) => { reject(new StarknetPluginError(`Declare transaction ${txHash}: ${error}`)); @@ -546,8 +536,8 @@ export class StarknetContract { return; } - get provider(): SequencerProvider { - return this.hre.starknetJs.provider; + get provider(): ProviderInterface { + return this.hre.starknetProvider; } /** @@ -594,7 +584,7 @@ export class StarknetContract { return new Promise((resolve, reject) => { iterativelyCheckStatus( txHash, - this.hre.starknetWrapper, + this.hre, () => resolve(txHash), (error) => { reject(new StarknetPluginError(`Invoke transaction ${txHash}: ${error}`)); diff --git a/src/utils.ts b/src/utils.ts index 0f7bad9f..8f3b100e 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,3 @@ -import fs from "fs"; import { glob } from "glob"; import { HardhatNetworkConfig, @@ -9,8 +8,15 @@ import { ProjectPathsConfig, VmLang } from "hardhat/types"; -import path from "path"; -import { json, stark, LegacyCompiledContract, hash } from "starknet"; +import fs, { promises as fsp } from "node:fs"; +import path from "node:path"; +import { + CompiledSierra, + LegacyCompiledContract, + hash, + json, + stark +} from "starknet"; import { handleInternalContractArtifacts } from "./account-utils"; import { @@ -302,10 +308,16 @@ export class UDC { } } +export function readContractSync(filePath: string, encoding: BufferEncoding = "ascii") { + return json.parse(fs.readFileSync(filePath, encoding)); +} + +export async function readContractAsync(filePath: string, encoding: BufferEncoding = "ascii") { + return json.parse(await fsp.readFile(filePath, encoding)); +} + export function readContract(contractPath: string) { - const parsedContract = json.parse( - fs.readFileSync(contractPath).toString("ascii") - ) as LegacyCompiledContract; + const parsedContract = readContractSync(contractPath) as LegacyCompiledContract; return { ...parsedContract, program: stark.compressProgram(parsedContract.program) @@ -313,7 +325,7 @@ export function readContract(contractPath: string) { } export function readCairo1Contract(contractPath: string) { - const parsedContract = json.parse(fs.readFileSync(contractPath).toString("ascii")); + const parsedContract = readContractSync(contractPath) as CompiledSierra; const { contract_class_version, entry_points_by_type, sierra_program } = parsedContract; const contract = new Cairo1ContractClass({ From 861ef94854a8273bda463fafa3b87a9181a640ec Mon Sep 17 00:00:00 2001 From: Petar Penovic Date: Tue, 5 Sep 2023 07:05:10 +0200 Subject: [PATCH 2/5] Allow fallback ABI resolution for contract initialization --- src/extend-utils.ts | 5 ---- src/types/index.ts | 69 +++++++++++++++++++++++++++++---------------- src/utils.ts | 11 ++------ 3 files changed, 48 insertions(+), 37 deletions(-) diff --git a/src/extend-utils.ts b/src/extend-utils.ts index ae1652d4..7b127f5d 100644 --- a/src/extend-utils.ts +++ b/src/extend-utils.ts @@ -42,11 +42,6 @@ export async function getContractFactoryUtil(hre: HardhatRuntimeEnvironment, con `${path.basename(contractPath)}${ABI_SUFFIX}` ); const abiPath = await findPath(artifactsPath, abiSearchTarget); - if (!abiPath) { - throw new StarknetPluginError( - `Could not find ABI JSON artifact for "${contractPath}.cairo". Consider recompiling your contracts.` - ); - } return new StarknetContractFactory({ metadataPath, diff --git a/src/types/index.ts b/src/types/index.ts index 2cd21043..fa903e6f 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -4,8 +4,10 @@ import { CallData, DeclareContractTransaction, InvocationsDetailsWithNonce, + LegacyContractClass, ProviderInterface, SequencerProvider, + SierraContractClass, events as eventUtil, hash, json, @@ -23,15 +25,7 @@ import { } from "../constants"; import { StarknetPluginError } from "../starknet-plugin-error"; import * as starknet from "../starknet-types"; -import { - adaptLog, - copyWithBigint, - findConstructor, - readContractAsync, - readContractSync, - sleep, - warn -} from "../utils"; +import { adaptLog, copyWithBigint, findConstructor, readContractSync, sleep, warn } from "../utils"; /** * According to: https://starknet.io/docs/hello_starknet/intro.html#interact-with-the-contract @@ -65,17 +59,25 @@ export type TxStatus = export type InvokeResponse = string; export type StarknetContractFactoryConfig = { - abiPath: string; + abiPath?: string; casmPath?: string; metadataPath: string; hre: HardhatRuntimeEnvironment; }; -export interface StarknetContractConfig { - abiPath: string; +export type StarknetContractConfig = { hre: HardhatRuntimeEnvironment; isCairo1: boolean; -} +} & ( + | { + abiPath: string; + abiRaw?: undefined; + } + | { + abiPath?: undefined; + abiRaw: string; + } +); export type Numeric = number | bigint; @@ -202,6 +204,15 @@ function readAbi(abiPath: string): string { return hash.formatSpaces(fs.readFileSync(abiPath).toString("ascii").trim()); } +/** + * Extracts the ABI from the contract + */ +function getFallbackAbi(contract: LegacyContractClass | SierraContractClass): string { + return hash.formatSpaces( + typeof contract.abi === "string" ? contract.abi : json.stringify(contract.abi) + ); +} + /** * Converts `rawAbi` to an object for lookup by name */ @@ -359,19 +370,26 @@ export type SierraContractEntryPointFields = { export type NonceQueryOptions = BlockIdentifier; export class StarknetContractFactory { + private classHash: string; + private constructorAbi: starknet.CairoFunction; + private contract: LegacyContractClass | SierraContractClass; private hre: HardhatRuntimeEnvironment; + public abi: starknet.Abi; - public abiPath: string; + public abiPath?: string; public abiRaw: string; - private constructorAbi: starknet.CairoFunction; public metadataPath: string; public casmPath: string; - private classHash: string; constructor(config: StarknetContractFactoryConfig) { this.hre = config.hre; + this.metadataPath = config.metadataPath; + this.contract = providerUtil.parseContract(readContractSync(this.metadataPath)); + this.abiPath = config.abiPath; - this.abiRaw = readAbi(this.abiPath); + this.abiRaw = this.abiPath + ? readAbi(this.abiPath) + : getFallbackAbi(this.retrieveContract()); this.abi = mapAbi(this.abiRaw); this.metadataPath = config.metadataPath; this.casmPath = config.casmPath; @@ -412,17 +430,19 @@ export class StarknetContractFactory { }; } + private retrieveContract() { + this.contract ??= providerUtil.parseContract(readContractSync(this.metadataPath)); + return this.contract; + } + /** * Declare a contract class. * @param options optional arguments to class declaration * @returns transaction hash as a hex string */ async declare(options: DeclareOptions = {}): Promise { - const contractJson = await readContractAsync(this.metadataPath); - const contract = providerUtil.parseContract(contractJson); - const transaction: DeclareContractTransaction = { - contract, + contract: this.retrieveContract(), senderAddress: options.sender, signature: handleSignature(options.signature) }; @@ -485,6 +505,7 @@ export class StarknetContractFactory { } const contract = new StarknetContract({ abiPath: this.abiPath, + abiRaw: this.abiRaw as undefined, hre: this.hre, isCairo1: this.isCairo1() }); @@ -521,7 +542,7 @@ export class StarknetContract { constructor(config: StarknetContractConfig) { this.hre = config.hre; this.abiPath = config.abiPath; - this.abiRaw = readAbi(this.abiPath); + this.abiRaw = config.abiRaw ?? readAbi(this.abiPath); this.abi = mapAbi(this.abiRaw); this.isCairo1 = config.isCairo1; this.eventsSpecifications = extractEventSpecifications(this.abi); @@ -786,11 +807,11 @@ export class StarknetContract { } } -export interface ContractClassConfig extends StarknetContractConfig { +export type ContractClassConfig = StarknetContractConfig & { sierraProgram: string; contractClassVersion: string; entryPointsByType: SierraEntryPointsByType; -} +}; export class Cairo1ContractClass extends StarknetContract { protected sierraProgram: string; diff --git a/src/utils.ts b/src/utils.ts index 8f3b100e..d8406794 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -10,13 +10,7 @@ import { } from "hardhat/types"; import fs, { promises as fsp } from "node:fs"; import path from "node:path"; -import { - CompiledSierra, - LegacyCompiledContract, - hash, - json, - stark -} from "starknet"; +import { CompiledSierra, LegacyCompiledContract, hash, json, stark } from "starknet"; import { handleInternalContractArtifacts } from "./account-utils"; import { @@ -326,13 +320,14 @@ export function readContract(contractPath: string) { export function readCairo1Contract(contractPath: string) { const parsedContract = readContractSync(contractPath) as CompiledSierra; - const { contract_class_version, entry_points_by_type, sierra_program } = parsedContract; + const { abi, contract_class_version, entry_points_by_type, sierra_program } = parsedContract; const contract = new Cairo1ContractClass({ abiPath: path.join( path.dirname(contractPath), `${path.parse(contractPath).name}${ABI_SUFFIX}` ), + abiRaw: hash.formatSpaces(json.stringify(abi)), sierraProgram: stark.compressProgram(hash.formatSpaces(json.stringify(sierra_program))), entryPointsByType: entry_points_by_type, contractClassVersion: contract_class_version From 932a77f072a740c99995f8eeeced2a9e10680240 Mon Sep 17 00:00:00 2001 From: Petar Penovic Date: Thu, 21 Sep 2023 10:33:06 +0200 Subject: [PATCH 3/5] Restructure legacy utilities and directly expose starknet.js through the runtime environment --- src/account.ts | 1065 ----------------- src/cairo1-compiler.ts | 21 +- src/index.ts | 31 +- src/{ => legacy/account}/account-utils.ts | 36 +- src/legacy/account/account.ts | 540 +++++++++ src/legacy/account/argent-account.ts | 339 ++++++ src/legacy/account/index.ts | 4 + src/legacy/account/open-zeppelin-account.ts | 218 ++++ src/legacy/contract/cairo1-contract-class.ts | 29 + src/legacy/contract/index.ts | 3 + .../contract/starknet-contract-factory.ts | 188 +++ src/legacy/contract/starknet-contract.ts | 315 +++++ src/{ => legacy}/extend-utils.ts | 26 +- src/legacy/index.ts | 3 + src/legacy/types/contract.ts | 29 + src/legacy/types/index.ts | 115 ++ src/legacy/utils/abi.ts | 48 + src/{ => legacy/utils}/adapt.ts | 47 +- src/legacy/utils/index.ts | 123 ++ src/starknet-wrappers.ts | 2 +- src/type-extensions.ts | 29 +- src/types/devnet.ts | 6 +- src/types/index.ts | 829 +------------ .../{starknet.ts => starknet-environment.ts} | 38 +- src/{ => types}/starknet-types.ts | 0 src/utils/check-command-path.ts | 8 - src/{ => utils}/devnet-utils.ts | 8 +- src/{utils.ts => utils/index.ts} | 15 +- src/utils/venv.ts | 12 +- .../short-string-test/short-string-test.ts | 2 +- 30 files changed, 2110 insertions(+), 2019 deletions(-) delete mode 100644 src/account.ts rename src/{ => legacy/account}/account-utils.ts (90%) create mode 100644 src/legacy/account/account.ts create mode 100644 src/legacy/account/argent-account.ts create mode 100644 src/legacy/account/index.ts create mode 100644 src/legacy/account/open-zeppelin-account.ts create mode 100644 src/legacy/contract/cairo1-contract-class.ts create mode 100644 src/legacy/contract/index.ts create mode 100644 src/legacy/contract/starknet-contract-factory.ts create mode 100644 src/legacy/contract/starknet-contract.ts rename src/{ => legacy}/extend-utils.ts (88%) create mode 100644 src/legacy/index.ts create mode 100644 src/legacy/types/contract.ts create mode 100644 src/legacy/types/index.ts create mode 100644 src/legacy/utils/abi.ts rename src/{ => legacy/utils}/adapt.ts (95%) create mode 100644 src/legacy/utils/index.ts rename src/types/{starknet.ts => starknet-environment.ts} (88%) rename src/{ => types}/starknet-types.ts (100%) delete mode 100644 src/utils/check-command-path.ts rename src/{ => utils}/devnet-utils.ts (96%) rename src/{utils.ts => utils/index.ts} (95%) diff --git a/src/account.ts b/src/account.ts deleted file mode 100644 index be8dae55..00000000 --- a/src/account.ts +++ /dev/null @@ -1,1065 +0,0 @@ -import { constants, ec, hash, selector, BigNumberish, Call, RawCalldata } from "starknet"; - -import { - calculateDeployAccountHash, - CallParameters, - generateKeys, - handleInternalContractArtifacts, - sendDeclareV2Tx, - sendDeployAccountTx, - sendEstimateFeeTx, - signMultiCall -} from "./account-utils"; -import { - QUERY_VERSION, - StarknetChainId, - TransactionHashPrefix, - TRANSACTION_VERSION, - UDC_DEPLOY_FUNCTION_NAME -} from "./constants"; -import { getTransactionReceiptUtil } from "./extend-utils"; -import { StarknetPluginError } from "./starknet-plugin-error"; -import * as starknet from "./starknet-types"; -import { - ContractInteractionFunction, - DeclareOptions, - DeployAccountOptions, - DeployOptions, - EstimateFeeOptions, - InteractChoice, - InteractOptions, - InvokeOptions, - InvokeResponse, - Numeric, - StarknetContract, - StarknetContractFactory, - StringMap -} from "./types"; -import { - numericToHexString, - copyWithBigint, - generateRandomSalt, - UDC, - readContract, - bnToDecimalStringArray, - estimatedFeeToMaxFee, - readCairo1Contract -} from "./utils"; - -type ExecuteCallParameters = { - to: bigint; - selector: BigNumberish; - data_offset: number; - data_len: number; -}; - -/** - * Representation of an Account. - * Multiple implementations can exist, each will be defined by an extension of this Abstract class - */ -export abstract class Account { - public publicKey: string; - - protected constructor( - public starknetContract: StarknetContract, - public privateKey: string, - public salt: string, - protected deployed: boolean - ) { - this.publicKey = ec.starkCurve.getStarkKey(privateKey); - } - - /** - * Uses the account contract as a proxy to invoke a function on the target contract with a signature - * - * @param toContract target contract to be called - * @param functionName function in the contract to be called - * @param calldata calldata to use as input for the contract call - */ - async invoke( - toContract: StarknetContract, - functionName: string, - calldata?: StringMap, - options?: InvokeOptions - ): Promise { - if (options?.maxFee && options?.overhead) { - const msg = "maxFee and overhead cannot be specified together"; - throw new StarknetPluginError(msg); - } - - if (options?.maxFee === undefined || options?.maxFee === null) { - const maxFee = await this.estimateFee(toContract, functionName, calldata, options); - options = { - ...options, - maxFee: estimatedFeeToMaxFee(maxFee.amount, options?.overhead) - }; - } - return ( - await this.interact(InteractChoice.INVOKE, toContract, functionName, calldata, options) - ).toString(); - } - - get address() { - return this.starknetContract.address; - } - - /** - * Deploy another contract using this account - * @param contractFactory the factory of the contract to be deployed - * @param constructorArguments - * @param options extra options - * @returns the deployed StarknetContract - */ - async deploy( - contractFactory: StarknetContractFactory, - constructorArguments?: StringMap, - options: DeployOptions = {} - ): Promise { - const classHash = await contractFactory.getClassHash(); - const udc = await UDC.getInstance(); - const adaptedArgs = contractFactory.handleConstructorArguments(constructorArguments); - const deployTxHash = await this.invoke( - udc, - UDC_DEPLOY_FUNCTION_NAME, - { - classHash, - salt: options?.salt ?? generateRandomSalt(), - unique: BigInt(options?.unique ?? true), - calldata: adaptedArgs - }, - { - maxFee: options?.maxFee, - nonce: options?.nonce - } - ); - - const hre = await import("hardhat"); - const deploymentReceipt = await getTransactionReceiptUtil(deployTxHash, hre); - const decodedEvents = udc.decodeEvents(deploymentReceipt.events); - // the only event should be ContractDeployed - const deployedContractAddress = numericToHexString(decodedEvents[0].data.address); - - const deployedContract = contractFactory.getContractAt(deployedContractAddress); - deployedContract.deployTxHash = deployTxHash; - - return deployedContract; - } - - protected assertNotDeployed() { - if (this.deployed) { - const msg = "The account is not expected to be deployed."; - throw new StarknetPluginError(msg); - } - } - - private assertDeployed() { - if (!this.deployed) { - const msg = "Prior to usage, the account must be funded and deployed."; - throw new StarknetPluginError(msg); - } - } - - async estimateFee( - toContract: StarknetContract, - functionName: string, - calldata?: StringMap, - options?: EstimateFeeOptions - ): Promise { - return await this.interact( - InteractChoice.ESTIMATE_FEE, - toContract, - functionName, - calldata, - options - ); - } - - private async estimateDeclareV2Fee( - contractFactory: StarknetContractFactory, - options: EstimateFeeOptions = {} - ): Promise { - const maxFee = (options.maxFee || 0).toString(); - const version = hash.feeTransactionVersion_2; - const nonce = options.nonce == null ? await this.getNonce() : options.nonce; - - const hre = await import("hardhat"); - const chainId = hre.starknet.networkConfig.starknetChainId; - - const compiledClassHash = await hre.starknetWrapper.getCompiledClassHash( - contractFactory.casmPath - ); - - const classHash = await hre.starknetWrapper.getSierraContractClassHash( - contractFactory.metadataPath - ); - - const messageHash = hash.calculateDeclareTransactionHash( - classHash, - this.address, - version, - maxFee, - chainId as unknown as constants.StarknetChainId, - nonce, - compiledClassHash - ); - const signatures = this.getSignatures(messageHash); - - const data = { - type: "DECLARE", - sender_address: this.address, - compiled_class_hash: compiledClassHash, - contract_class: readCairo1Contract(contractFactory.metadataPath).getCompiledClass(), - signature: bnToDecimalStringArray(signatures || []), - version: numericToHexString(version), - nonce: numericToHexString(nonce) - }; - - return await sendEstimateFeeTx(data); - } - - async estimateDeclareFee( - contractFactory: StarknetContractFactory, - options: EstimateFeeOptions = {} - ): Promise { - if (contractFactory.isCairo1()) { - return await this.estimateDeclareV2Fee(contractFactory, options); - } - - const nonce = options.nonce == null ? await this.getNonce() : options.nonce; - const maxFee = (options.maxFee || 0).toString(); - - const hre = await import("hardhat"); - const classHash = await hre.starknetWrapper.getClassHash(contractFactory.metadataPath); - const chainId = hre.starknet.networkConfig.starknetChainId; - - const calldata = [classHash]; - const calldataHash = hash.computeHashOnElements(calldata); - - const messageHash = hash.computeHashOnElements([ - TransactionHashPrefix.DECLARE, - numericToHexString(QUERY_VERSION), - this.address, - 0, // entrypoint selector is implied - calldataHash, - maxFee, - chainId, - numericToHexString(nonce) - ]); - - const signature = this.getSignatures(messageHash); - const data = { - type: "DECLARE", - sender_address: this.address, - contract_class: readContract(contractFactory.metadataPath), - signature: bnToDecimalStringArray(signature || []), - version: numericToHexString(QUERY_VERSION), - nonce: numericToHexString(nonce) - }; - return await sendEstimateFeeTx(data); - } - - async estimateDeployFee( - contractFactory: StarknetContractFactory, - constructorArguments?: StringMap, - options: EstimateFeeOptions = {} - ): Promise { - const classHash = await contractFactory.getClassHash(); - const udc = await UDC.getInstance(); - const adaptedArgs = contractFactory.handleConstructorArguments(constructorArguments); - const calldata: StringMap = { - classHash, - salt: options?.salt ?? generateRandomSalt(), - unique: BigInt(options?.unique ?? true), - calldata: adaptedArgs - }; - return await this.estimateFee(udc, UDC_DEPLOY_FUNCTION_NAME, calldata, options); - } - - private async interact( - choice: InteractChoice, - toContract: StarknetContract, - functionName: string, - calldata?: StringMap, - options?: InteractOptions - ) { - const call: CallParameters = { - functionName: functionName, - toContract: toContract, - calldata: calldata - }; - - return await this.multiInteract(choice, [call], options); - } - - /** - * Performs multiple invokes as a single transaction through this account - * @param callParameters an array with the parameters for each invoke - * @returns the transaction hash of the invoke - */ - async multiInvoke(callParameters: CallParameters[], options?: InvokeOptions): Promise { - // Invoke only returns one transaction hash, as the multiple invokes are done by the account contract, but only one is sent to it. - return await this.multiInteract(InteractChoice.INVOKE, callParameters, options); - } - - /** - * Estimate the fee of the multicall. - * @param callParameters an array with the parameters for each call - * @returns the total estimated fee - */ - async multiEstimateFee( - callParameters: CallParameters[], - options?: EstimateFeeOptions - ): Promise { - return await this.multiInteract(InteractChoice.ESTIMATE_FEE, callParameters, options); - } - - private async multiInteract( - choice: InteractChoice, - callParameters: CallParameters[], - options: InteractOptions = {} - ) { - this.assertDeployed(); - options = copyWithBigint(options); - options.maxFee = BigInt(options?.maxFee || "0"); - const nonce = options.nonce == null ? await this.getNonce() : options.nonce; - delete options.nonce; // the options object is incompatible if passed on with nonce - - const hre = await import("hardhat"); - const { messageHash, args } = this.handleMultiInteract( - this.address, - callParameters, - nonce, - options.maxFee, - choice.transactionVersion, - hre.starknet.networkConfig.starknetChainId, - options.rawInput - ); - - if (options.signature) { - const msg = - "Custom signature cannot be specified when using Account (it is calculated automatically)"; - throw new StarknetPluginError(msg); - } - const contractInteractOptions = { - signature: this.getSignatures(messageHash), - ...options, - rawInput: false // rawInput shouldn't affect validating args of __execute__ - }; - - const contractInteractor = (( - this.starknetContract[choice.internalCommand] - )).bind(this.starknetContract); - const executionFunctionName = this.getExecutionFunctionName(); - return contractInteractor(executionFunctionName, args, contractInteractOptions); - } - - /** - * Prepares the calldata and hashes the message for the multicall execution - * - * @param accountAddress address of the account contract - * @param callParameters array with the call parameters - * @param nonce current nonce - * @param maxFee the maximum fee amount set for the contract interaction - * @param version the transaction version - * @param chainId the ID of the chain - * @param rawInput if `true`, interprets calldata as already adapted into an array - * @returns the message hash for the multicall and the arguments to execute it with - */ - private handleMultiInteract( - accountAddress: string, - callParameters: CallParameters[], - nonce: Numeric, - maxFee: Numeric, - version: Numeric, - chainId: StarknetChainId, - rawInput: boolean - ) { - const callArray: Call[] = callParameters.map((callParameters) => { - const calldata = rawInput - ? callParameters.calldata - : callParameters.toContract.adaptInput( - callParameters.functionName, - callParameters.calldata - ); - return { - contractAddress: callParameters.toContract.address, - entrypoint: callParameters.functionName, - calldata - }; - }); - - const executeCallArray: ExecuteCallParameters[] = []; - const rawCalldata: RawCalldata = []; - - // Parse the Call array to create the objects which will be accepted by the contract - callArray.forEach((call) => { - const calldata = call.calldata as BigNumberish[]; - executeCallArray.push({ - to: BigInt(call.contractAddress), - selector: selector.starknetKeccak(call.entrypoint), - data_offset: rawCalldata.length, - data_len: calldata.length - }); - rawCalldata.push(...calldata); - }); - - const adaptedNonce = nonce.toString(); - const adaptedMaxFee = numericToHexString(maxFee); - const adaptedVersion = numericToHexString(version); - const messageHash = this.getMessageHash( - TransactionHashPrefix.INVOKE, - accountAddress, - callArray, - adaptedNonce, - adaptedMaxFee, - adaptedVersion, - chainId - ); - - const args = { - call_array: executeCallArray, - calldata: rawCalldata - }; - return { messageHash, args }; - } - - protected abstract getMessageHash( - transactionHashPrefix: TransactionHashPrefix, - accountAddress: string, - callArray: Call[], - nonce: string, - maxFee: string, - version: string, - chainId: StarknetChainId - ): string; - - protected abstract getSignatures(messageHash: string): bigint[]; - - protected abstract estimateDeployAccountFee(): Promise; - - public abstract deployAccount(options?: DeployAccountOptions): Promise; - - protected getExecutionFunctionName() { - return "__execute__"; - } - - private async getNonce(): Promise { - const hre = await import("hardhat"); - return await hre.starknet.getNonce(this.address); - } - - /** - * Declare the contract class corresponding to the `contractFactory` - * @param contractFactory - * @param options - * @returns transaction hash - */ - public async declare( - contractFactory: StarknetContractFactory, - options: DeclareOptions = {} - ): Promise { - if (contractFactory.isCairo1()) { - return await this.declareV2(contractFactory, options); - } - - let maxFee = options?.maxFee; - if (maxFee && options?.overhead) { - const msg = "maxFee and overhead cannot be specified together"; - throw new StarknetPluginError(msg); - } - - const nonce = options.nonce == null ? await this.getNonce() : options.nonce; - if (maxFee === undefined || maxFee === null) { - const estimatedDeclareFee = await this.estimateDeclareFee(contractFactory, options); - maxFee = estimatedFeeToMaxFee(estimatedDeclareFee.amount, options?.overhead); - } - - const hre = await import("hardhat"); - const classHash = await hre.starknetWrapper.getClassHash(contractFactory.metadataPath); - const chainId = hre.starknet.networkConfig.starknetChainId; - - const calldata = [classHash]; - const calldataHash = hash.computeHashOnElements(calldata); - - const messageHash = hash.computeHashOnElements([ - TransactionHashPrefix.DECLARE, - TRANSACTION_VERSION.toString(), - this.address, - 0, // entrypoint selector is implied - calldataHash, - maxFee.toString(), - chainId, - nonce.toString() - ]); - - const signature = this.getSignatures(messageHash); - return contractFactory.declare({ - nonce, - signature, - token: options.token, - sender: this.address, - maxFee: BigInt(maxFee) - }); - } - - private async declareV2( - contractFactory: StarknetContractFactory, - options: DeclareOptions = {} - ): Promise { - let maxFee = options?.maxFee; - if (maxFee && options?.overhead) { - const msg = "maxFee and overhead cannot be specified together"; - throw new StarknetPluginError(msg); - } - - const nonce = options.nonce == null ? await this.getNonce() : options.nonce; - if (maxFee === undefined || maxFee === null) { - const estimatedDeclareFee = await this.estimateDeclareV2Fee(contractFactory, options); - maxFee = estimatedFeeToMaxFee(estimatedDeclareFee.amount, options?.overhead); - } - - const version = hash.transactionVersion_2; - const hre = await import("hardhat"); - const chainId = hre.starknet.networkConfig.starknetChainId; - - const compiledClassHash = await hre.starknetWrapper.getCompiledClassHash( - contractFactory.casmPath - ); - const classHash = await hre.starknetWrapper.getSierraContractClassHash( - contractFactory.metadataPath - ); - - const messageHash = hash.calculateDeclareTransactionHash( - classHash, - this.address, - version, - maxFee, - chainId as unknown as constants.StarknetChainId, - nonce, - compiledClassHash - ); - const signatures = this.getSignatures(messageHash); - - return sendDeclareV2Tx( - bnToDecimalStringArray(signatures), - compiledClassHash, - maxFee, - this.address, - version, - nonce, - readCairo1Contract(contractFactory.metadataPath) - ); - } -} - -/** - * Wrapper for the OpenZeppelin implementation of an Account - */ -export class OpenZeppelinAccount extends Account { - private static contractFactory: StarknetContractFactory; - - protected constructor( - starknetContract: StarknetContract, - privateKey: string, - salt: string, - deployed: boolean - ) { - super(starknetContract, privateKey, salt, deployed); - } - - private static async getContractFactory() { - const hre = await import("hardhat"); - if (!this.contractFactory) { - const contractPath = handleInternalContractArtifacts( - "OpenZeppelinAccount", - "Account", - "0.5.1", - hre - ); - this.contractFactory = await hre.starknet.getContractFactory(contractPath); - } - return this.contractFactory; - } - - /** - * Generates a new key pair if none specified. - * The created account needs to be deployed using the `deployAccount` method. - * @param options - * @returns an undeployed instance of account - */ - public static async createAccount( - options: { - salt?: string; - privateKey?: string; - } = {} - ): Promise { - const signer = generateKeys(options.privateKey); - const salt = options.salt || generateRandomSalt(); - const contractFactory = await this.getContractFactory(); - const address = hash.calculateContractAddressFromHash( - salt, - await contractFactory.getClassHash(), - [signer.publicKey], - "0x0" // deployer address - ); - const contract = contractFactory.getContractAt(address); - return new this(contract, signer.privateKey, salt, false); - } - - protected override getMessageHash( - transactionHashPrefix: TransactionHashPrefix, - accountAddress: string, - callArray: Call[], - nonce: string, - maxFee: string, - version: string, - chainId: StarknetChainId - ): string { - const hashable: BigNumberish[] = [callArray.length]; - const rawCalldata: RawCalldata = []; - callArray.forEach((call) => { - const calldata = call.calldata as BigNumberish[]; - hashable.push( - call.contractAddress, - hash.starknetKeccak(call.entrypoint), - rawCalldata.length, - calldata.length - ); - rawCalldata.push(...calldata); - }); - - hashable.push(rawCalldata.length, ...rawCalldata); - const calldataHash = hash.computeHashOnElements(hashable); - return hash.computeHashOnElements([ - transactionHashPrefix, - version, - accountAddress, - 0, // entrypoint selector is implied - calldataHash, - maxFee, - chainId, - nonce - ]); - } - - protected override getSignatures(messageHash: string): bigint[] { - return signMultiCall(messageHash, this.privateKey); - } - - public override async estimateDeployAccountFee(): Promise { - this.assertNotDeployed(); - const hre = await import("hardhat"); - - const contractFactory = await OpenZeppelinAccount.getContractFactory(); - const classHash = await contractFactory.getClassHash(); - const constructorCalldata = [BigInt(this.publicKey).toString()]; - - const maxFee = numericToHexString(0); - const nonce = numericToHexString(0); - - const calldataHash = hash.computeHashOnElements([ - classHash, - this.salt, - ...constructorCalldata - ]); - const msgHash = hash.computeHashOnElements([ - TransactionHashPrefix.DEPLOY_ACCOUNT, - numericToHexString(QUERY_VERSION), - this.address, - 0, // entrypoint selector is implied - calldataHash, - maxFee, - hre.starknet.networkConfig.starknetChainId, - nonce - ]); - - const signature = this.getSignatures(msgHash); - const data = { - type: "DEPLOY_ACCOUNT", - class_hash: classHash, - constructor_calldata: constructorCalldata, - contract_address_salt: this.salt, - signature: bnToDecimalStringArray(signature || []), - version: numericToHexString(QUERY_VERSION), - nonce - }; - - return await sendEstimateFeeTx(data); - } - - public override async deployAccount(options: DeployAccountOptions = {}): Promise { - this.assertNotDeployed(); - const hre = await import("hardhat"); - - let maxFee = options?.maxFee; - if (maxFee && options?.overhead) { - const msg = "maxFee and overhead cannot be specified together"; - throw new StarknetPluginError(msg); - } - - if (maxFee === undefined || maxFee === null) { - const estimatedDeployFee = await this.estimateDeployAccountFee(); - maxFee = estimatedFeeToMaxFee(estimatedDeployFee.amount, options?.overhead); - } - - const contractFactory = await OpenZeppelinAccount.getContractFactory(); - const classHash = await contractFactory.getClassHash(); - const constructorCalldata = [BigInt(this.publicKey).toString()]; - - const msgHash = calculateDeployAccountHash( - this.address, - constructorCalldata, - this.salt, - classHash, - numericToHexString(maxFee), - hre.starknet.networkConfig.starknetChainId - ); - - const deploymentTxHash = await sendDeployAccountTx( - this.getSignatures(msgHash).map((val) => val.toString()), - classHash, - constructorCalldata, - this.salt, - numericToHexString(maxFee) - ); - - this.starknetContract.deployTxHash = deploymentTxHash; - this.deployed = true; - return deploymentTxHash; - } - - static async getAccountFromAddress( - address: string, - privateKey: string - ): Promise { - const contractFactory = await this.getContractFactory(); - const contract = contractFactory.getContractAt(address); - - const { publicKey: expectedPubKey } = await contract.call("getPublicKey"); - const publicKey = ec.starkCurve.getStarkKey(privateKey); - - if (BigInt(publicKey) !== expectedPubKey) { - throw new StarknetPluginError( - "The provided private key is not compatible with the public key stored in the contract." - ); - } - - return new this(contract, privateKey, undefined, true); - } -} - -/** - * Wrapper for the Argent implementation of Account - */ -export class ArgentAccount extends Account { - private static readonly VERSION: string = "780760e4156afe592bb1feff7e769cf279ae9831"; - - private static proxyContractFactory: StarknetContractFactory; - private static implementationContractFactory: StarknetContractFactory; - - private static readonly PROXY_CLASS_HASH = - "0x25ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918"; - private static readonly IMPLEMENTATION_CLASS_HASH = - "0x33434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2"; - - public guardianPublicKey: string; - public guardianPrivateKey: string; - - protected constructor( - starknetContract: StarknetContract, - privateKey: string, - guardianPrivateKey: string, - salt: string, - deployed: boolean - ) { - super(starknetContract, privateKey, salt, deployed); - this.guardianPrivateKey = guardianPrivateKey; - if (this.guardianPrivateKey) { - const guardianSigner = generateKeys(this.guardianPrivateKey); - this.guardianPublicKey = guardianSigner.publicKey; - } - } - - private static async getImplementationContractFactory() { - const hre = await import("hardhat"); - if (!this.implementationContractFactory) { - const contractPath = handleInternalContractArtifacts( - "ArgentAccount", - "ArgentAccount", - this.VERSION, - hre - ); - this.implementationContractFactory = await hre.starknet.getContractFactory( - contractPath - ); - } - return this.implementationContractFactory; - } - - private static async getProxyContractFactory() { - const hre = await import("hardhat"); - if (!this.proxyContractFactory) { - const contractPath = handleInternalContractArtifacts( - "ArgentAccount", - "Proxy", - this.VERSION, - hre - ); - this.proxyContractFactory = await hre.starknet.getContractFactory(contractPath); - } - return this.proxyContractFactory; - } - - private static generateGuardianPublicKey(guardianPrivateKey: string) { - if (!guardianPrivateKey) { - return "0x0"; - } - return generateKeys(guardianPrivateKey).publicKey; - } - - /** - * Generates a new key pair if none specified. - * Does NOT generate a new guardian key pair if none specified. - * If you don't specify a guardian private key, no guardian will be assigned. - * The created account needs to be deployed using the `deployAccount` method. - * @param options - * @returns an undeployed instance of account - */ - public static async createAccount( - options: { - salt?: string; - privateKey?: string; - guardianPrivateKey?: string; - } = {} - ): Promise { - const signer = generateKeys(options.privateKey); - const guardianPrivateKey = options?.guardianPrivateKey; - const guardianPublicKey = this.generateGuardianPublicKey(guardianPrivateKey); - const salt = options.salt || generateRandomSalt(); - const constructorCalldata = [ - this.IMPLEMENTATION_CLASS_HASH, - selector.getSelectorFromName("initialize"), - "2", - signer.publicKey, - guardianPublicKey - ]; - const address = hash.calculateContractAddressFromHash( - salt, - this.PROXY_CLASS_HASH, - constructorCalldata, - "0x0" // deployer address - ); - - const proxyContractFactory = await this.getProxyContractFactory(); - const contract = proxyContractFactory.getContractAt(address); - return new this(contract, signer.privateKey, guardianPrivateKey, salt, false); - } - - protected getMessageHash( - transactionHashPrefix: TransactionHashPrefix, - accountAddress: string, - callArray: Call[], - nonce: string, - maxFee: string, - version: string, - chainId: StarknetChainId - ): string { - const hashable: BigNumberish[] = [callArray.length]; - const rawCalldata: RawCalldata = []; - callArray.forEach((call) => { - const calldata = call.calldata as BigNumberish[]; - hashable.push( - call.contractAddress, - selector.starknetKeccak(call.entrypoint), - rawCalldata.length, - calldata.length - ); - rawCalldata.push(...calldata); - }); - - hashable.push(rawCalldata.length, ...rawCalldata); - const calldataHash = hash.computeHashOnElements(hashable); - return hash.computeHashOnElements([ - transactionHashPrefix, - version, - accountAddress, - 0, // entrypoint selector is implied - calldataHash, - maxFee, - chainId, - nonce - ]); - } - - protected override getSignatures(messageHash: string): bigint[] { - const signatures = signMultiCall(messageHash, this.privateKey); - if (this.guardianPrivateKey) { - const guardianSignatures = signMultiCall(messageHash, this.guardianPrivateKey); - signatures.push(...guardianSignatures); - } - return signatures; - } - - public override async estimateDeployAccountFee(): Promise { - this.assertNotDeployed(); - const hre = await import("hardhat"); - - const nonce = numericToHexString(0); - const maxFee = numericToHexString(0); - - const constructorCalldata: string[] = [ - ArgentAccount.IMPLEMENTATION_CLASS_HASH, - selector.getSelectorFromName("initialize"), - "2", - this.publicKey, - ArgentAccount.generateGuardianPublicKey(this.guardianPrivateKey) - ].map((val) => BigInt(val).toString()); - const calldataHash = hash.computeHashOnElements([ - ArgentAccount.PROXY_CLASS_HASH, - this.salt, - ...constructorCalldata - ]); - const msgHash = hash.computeHashOnElements([ - TransactionHashPrefix.DEPLOY_ACCOUNT, - numericToHexString(QUERY_VERSION), - this.address, - 0, // entrypoint selector is implied - calldataHash, - maxFee, - hre.starknet.networkConfig.starknetChainId, - nonce - ]); - - const signature = this.getSignatures(msgHash); - const data = { - type: "DEPLOY_ACCOUNT", - class_hash: ArgentAccount.PROXY_CLASS_HASH, - constructor_calldata: constructorCalldata, - contract_address_salt: this.salt, - signature: bnToDecimalStringArray(signature || []), - version: numericToHexString(QUERY_VERSION), - nonce - }; - - return await sendEstimateFeeTx(data); - } - - /** - * Deploys (initializes) the account. - * @param options - * @returns the tx hash of the deployment - */ - public override async deployAccount(options: DeployAccountOptions = {}): Promise { - this.assertNotDeployed(); - const hre = await import("hardhat"); - - let maxFee = options?.maxFee; - if (maxFee && options?.overhead) { - const msg = "maxFee and overhead cannot be specified together"; - throw new StarknetPluginError(msg); - } - - if (maxFee === undefined || maxFee === null) { - const estimatedDeployFee = await this.estimateDeployAccountFee(); - maxFee = estimatedFeeToMaxFee(estimatedDeployFee.amount, options?.overhead); - } - - const constructorCalldata: string[] = [ - ArgentAccount.IMPLEMENTATION_CLASS_HASH, - selector.getSelectorFromName("initialize"), - "2", - this.publicKey, - ArgentAccount.generateGuardianPublicKey(this.guardianPrivateKey) - ].map((val) => BigInt(val).toString()); - - const msgHash = calculateDeployAccountHash( - this.address, - constructorCalldata, - this.salt, - ArgentAccount.PROXY_CLASS_HASH, - numericToHexString(maxFee), - hre.starknet.networkConfig.starknetChainId - ); - - const deploymentTxHash = await sendDeployAccountTx( - this.getSignatures(msgHash).map((val) => val.toString()), - ArgentAccount.PROXY_CLASS_HASH, - constructorCalldata, - this.salt, - numericToHexString(maxFee) - ); - - const implementationFactory = await ArgentAccount.getImplementationContractFactory(); - this.starknetContract.setImplementation(implementationFactory); - this.starknetContract.deployTxHash = deploymentTxHash; - this.deployed = true; - return deploymentTxHash; - } - - /** - * Updates the guardian key in the contract. Set it to `undefined` to remove the guardian. - * @param newGuardianPrivateKey private key of the guardian to update - * @returns hash of the transaction which changes the guardian - */ - public async setGuardian( - newGuardianPrivateKey?: string, - invokeOptions?: InvokeOptions - ): Promise { - let guardianPublicKey: string; - if (!BigInt(newGuardianPrivateKey || 0)) { - newGuardianPrivateKey = undefined; - guardianPublicKey = undefined; - } else { - guardianPublicKey = ec.starkCurve.getStarkKey(newGuardianPrivateKey); - } - - const call: CallParameters = { - functionName: "changeGuardian", - toContract: this.starknetContract, - calldata: { newGuardian: BigInt(guardianPublicKey || 0) } - }; - - const txHash = await this.multiInvoke([call], invokeOptions); - - // set after signing - this.guardianPrivateKey = newGuardianPrivateKey; - this.guardianPublicKey = guardianPublicKey; - - return txHash; - } - - /** - * Returns an account previously deployed to `address`. - * A check is performed if the public key stored in the account matches the provided `privateKey`. - * No check is done for the optional guardian private key. - * @param address - * @param privateKey - * @param options - * @returns the retrieved account - */ - static async getAccountFromAddress( - address: string, - privateKey: string, - options: { - guardianPrivateKey?: string; - } = {} - ): Promise { - const contractFactory = await this.getProxyContractFactory(); - const contract = contractFactory.getContractAt(address); - const implementationFactory = await this.getImplementationContractFactory(); - contract.setImplementation(implementationFactory); - - const { signer: expectedPubKey } = await contract.call("getSigner"); - const publicKey = ec.starkCurve.getStarkKey(privateKey); - - if (expectedPubKey === BigInt(0)) { - // not yet initialized - } else if (BigInt(publicKey) !== expectedPubKey) { - throw new StarknetPluginError( - "The provided private key is not compatible with the public key stored in the contract." - ); - } - - return new this(contract, privateKey, options.guardianPrivateKey, undefined, true); - } -} diff --git a/src/cairo1-compiler.ts b/src/cairo1-compiler.ts index a44c32e9..29bbf214 100644 --- a/src/cairo1-compiler.ts +++ b/src/cairo1-compiler.ts @@ -1,20 +1,21 @@ -import fs from "fs"; -import os from "os"; import { ProcessResult } from "@nomiclabs/hardhat-docker"; -import shell from "shelljs"; -import path from "path"; import axios, { AxiosError } from "axios"; -import { StarknetPluginError } from "./starknet-plugin-error"; +import { TaskArguments } from "hardhat/types"; +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import shell from "shelljs"; +import tar from "tar-fs"; +import zlib from "zlib"; + +import config from "../config.json"; import { CAIRO_COMPILER_BINARY_URL, HIDDEN_PLUGIN_COMPILER_SUBDIR, HIDDEN_PLUGIN_DIR } from "./constants"; -import { StarknetConfig } from "./types/starknet"; -import config from "../config.json"; -import tar from "tar-fs"; -import zlib from "zlib"; -import { TaskArguments } from "hardhat/types"; +import { StarknetPluginError } from "./starknet-plugin-error"; +import { StarknetConfig } from "./types/starknet-environment"; export const exec = (args: string) => { const result = shell.exec(args, { diff --git a/src/index.ts b/src/index.ts index 5d2c982b..b29c6bf8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,5 @@ -import * as path from "path"; +import exitHook from "exit-hook"; import { task, extendEnvironment, extendConfig } from "hardhat/config"; -import { StarknetPluginError } from "./starknet-plugin-error"; import { lazyObject } from "hardhat/plugins"; import { ConfigurableTaskDefinition, @@ -9,9 +8,9 @@ import { HardhatRuntimeEnvironment, HardhatUserConfig } from "hardhat/types"; -import exitHook from "exit-hook"; +import * as path from "node:path"; +import * as starknet from "starknet"; -import "./type-extensions"; import { DEFAULT_STARKNET_SOURCES_PATH, DEFAULT_STARKNET_ARTIFACTS_PATH, @@ -39,6 +38,8 @@ import { getDefaultHttpNetworkConfig, getNetwork } from "./utils"; + +import { StarknetPluginError } from "./starknet-plugin-error"; import { DockerWrapper, VenvWrapper } from "./starknet-wrappers"; import { amarnaAction, @@ -60,12 +61,14 @@ import { getNonceUtil, getTransactionTraceUtil, getBalanceUtil -} from "./extend-utils"; -import { DevnetUtils } from "./devnet-utils"; +} from "./legacy/extend-utils"; +import { DevnetUtils } from "./utils/devnet-utils"; import { ExternalServer } from "./external-server"; -import { ArgentAccount, OpenZeppelinAccount } from "./account"; +import { OpenZeppelinAccount } from "./legacy/account/open-zeppelin-account"; +import { ArgentAccount } from "./legacy/account/argent-account"; import { AmarnaDocker } from "./external-server/docker-amarna"; import { StarknetJsWrapper } from "./starknet-js-wrapper"; +import "./type-extensions"; exitHook(() => { ExternalServer.cleanAll(); @@ -267,6 +270,13 @@ task("starknet-build", "Builds Scarb projects") extendEnvironment((hre) => { hre.starknet = { + ...starknet, + devnet: lazyObject(() => new DevnetUtils(hre)), + network: hre.config.starknet.network, + networkConfig: hre.config.starknet.networkConfig as HardhatNetworkConfig + }; + + hre.starknetLegacy = { getContractFactory: async (contractPath) => { const contractFactory = await getContractFactoryUtil(hre, contractPath); return contractFactory; @@ -282,8 +292,6 @@ extendEnvironment((hre) => { return convertedBigInt; }, - devnet: lazyObject(() => new DevnetUtils(hre)), - getTransaction: async (txHash) => { const transaction = await getTransactionUtil(txHash, hre); return transaction; @@ -314,9 +322,6 @@ extendEnvironment((hre) => { return balance; }, - network: hre.config.starknet.network, - networkConfig: hre.config.starknet.networkConfig as HardhatNetworkConfig, - OpenZeppelinAccount: OpenZeppelinAccount, ArgentAccount: ArgentAccount }; @@ -357,5 +362,5 @@ task("amarna", "Runs Amarna, the static-analyzer and linter for Cairo.") .setAction(amarnaAction); export * from "./types"; -export * from "./starknet-types"; +export * from "./types/starknet-types"; export * from "./starknet-plugin-error"; diff --git a/src/account-utils.ts b/src/legacy/account/account-utils.ts similarity index 90% rename from src/account-utils.ts rename to src/legacy/account/account-utils.ts index 1f1435fd..c6640d82 100644 --- a/src/account-utils.ts +++ b/src/legacy/account/account-utils.ts @@ -1,26 +1,21 @@ import axios, { AxiosError } from "axios"; -import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { HardhatRuntimeEnvironment, StarknetContract, StringMap } from "hardhat/types"; import fs from "node:fs"; import path from "node:path"; import { ec, hash, stark } from "starknet"; import { - ABI_SUFFIX, INTERNAL_ARTIFACTS_DIR, + ABI_SUFFIX, + StarknetChainId, TransactionHashPrefix, - TRANSACTION_VERSION, - StarknetChainId -} from "./constants"; -import { StarknetPluginError } from "./starknet-plugin-error"; -import * as starknet from "./starknet-types"; -import { - Cairo1ContractClass, - iterativelyCheckStatus, - Numeric, - StarknetContract, - StringMap -} from "./types"; -import { numericToHexString } from "./utils"; + TRANSACTION_VERSION +} from "../../constants"; +import { StarknetPluginError } from "../../starknet-plugin-error"; +import { Numeric, starknetTypes } from "../../types"; +import { numericToHexString } from "../../utils"; +import { Cairo1ContractClass } from "../contract"; +import { iterativelyCheckStatus } from "../utils"; export type CallParameters = { toContract: StarknetContract; @@ -70,8 +65,7 @@ export function handleInternalContractArtifacts( const abiArtifact = contractName + ABI_SUFFIX; const artifactsSourcePath = path.join( - __dirname, - "..", // necessary since artifact dir is in the root, not in src + __dirname.match(/^.*dist\//)[0], // necessary since artifact dir is in the root INTERNAL_ARTIFACTS_DIR, contractDir, artifactsVersion, @@ -155,7 +149,7 @@ export async function sendDeployAccountTx( version: numericToHexString(TRANSACTION_VERSION), type: "DEPLOY_ACCOUNT" }) - .catch((error: AxiosError) => { + .catch((error: AxiosError) => { const msg = `Deploying account failed: ${error.response.data.message}`; throw new StarknetPluginError(msg, error); }); @@ -191,7 +185,7 @@ export async function sendDeclareV2Tx( nonce: numericToHexString(nonce), max_fee: numericToHexString(maxFee) }) - .catch((error: AxiosError) => { + .catch((error: AxiosError) => { const msg = `Declaring contract failed: ${error.response.data.message}`; throw new StarknetPluginError(msg, error); }); @@ -216,7 +210,7 @@ export async function sendEstimateFeeTx(data: unknown) { const resp = await axios .post(`${hre.starknet.networkConfig.url}/feeder_gateway/estimate_fee`, data) - .catch((error: AxiosError) => { + .catch((error: AxiosError) => { const msg = `Estimating fees failed: ${error.response.data.message}`; throw new StarknetPluginError(msg, error); }); @@ -227,5 +221,5 @@ export async function sendEstimateFeeTx(data: unknown) { unit, gas_price: BigInt(gas_price), gas_usage: BigInt(gas_usage) - } as starknet.FeeEstimation; + } as starknetTypes.FeeEstimation; } diff --git a/src/legacy/account/account.ts b/src/legacy/account/account.ts new file mode 100644 index 00000000..dc0bc63b --- /dev/null +++ b/src/legacy/account/account.ts @@ -0,0 +1,540 @@ +import { constants, ec, hash, selector, BigNumberish, Call, RawCalldata } from "starknet"; + +import { + UDC_DEPLOY_FUNCTION_NAME, + TransactionHashPrefix, + QUERY_VERSION, + StarknetChainId, + TRANSACTION_VERSION +} from "../../constants"; +import { getTransactionReceiptUtil, getNonceUtil } from "../extend-utils"; +import { StarknetPluginError } from "../../starknet-plugin-error"; +import { InvokeOptions, Numeric, StringMap, starknetTypes } from "../../types"; +import { + estimatedFeeToMaxFee, + UDC, + generateRandomSalt, + numericToHexString, + readCairo1Contract, + bnToDecimalStringArray, + readContract, + copyWithBigint +} from "../../utils"; +import { StarknetContract, StarknetContractFactory } from "../contract"; +import { + InvokeResponse, + DeployOptions, + EstimateFeeOptions, + InteractOptions, + ContractInteractionFunction, + DeployAccountOptions, + DeclareOptions +} from "../types"; +import { InteractChoice } from "../utils"; +import { sendEstimateFeeTx, CallParameters, sendDeclareV2Tx } from "./account-utils"; + +type ExecuteCallParameters = { + to: bigint; + selector: BigNumberish; + data_offset: number; + data_len: number; +}; + +/** + * Representation of an Account. + * Multiple implementations can exist, each will be defined by an extension of this Abstract class + */ +export abstract class Account { + public publicKey: string; + + protected constructor( + public starknetContract: StarknetContract, + public privateKey: string, + public salt: string, + protected deployed: boolean + ) { + this.publicKey = ec.starkCurve.getStarkKey(privateKey); + } + + /** + * Uses the account contract as a proxy to invoke a function on the target contract with a signature + * + * @param toContract target contract to be called + * @param functionName function in the contract to be called + * @param calldata calldata to use as input for the contract call + */ + async invoke( + toContract: StarknetContract, + functionName: string, + calldata?: StringMap, + options?: InvokeOptions + ): Promise { + if (options?.maxFee && options?.overhead) { + const msg = "maxFee and overhead cannot be specified together"; + throw new StarknetPluginError(msg); + } + + if (options?.maxFee === undefined || options?.maxFee === null) { + const maxFee = await this.estimateFee(toContract, functionName, calldata, options); + options = { + ...options, + maxFee: estimatedFeeToMaxFee(maxFee.amount, options?.overhead) + }; + } + return ( + await this.interact(InteractChoice.INVOKE, toContract, functionName, calldata, options) + ).toString(); + } + + get address() { + return this.starknetContract.address; + } + + /** + * Deploy another contract using this account + * @param contractFactory the factory of the contract to be deployed + * @param constructorArguments + * @param options extra options + * @returns the deployed StarknetContract + */ + async deploy( + contractFactory: StarknetContractFactory, + constructorArguments?: StringMap, + options: DeployOptions = {} + ): Promise { + const classHash = await contractFactory.getClassHash(); + const udc = await UDC.getInstance(); + const adaptedArgs = contractFactory.handleConstructorArguments(constructorArguments); + const deployTxHash = await this.invoke( + udc, + UDC_DEPLOY_FUNCTION_NAME, + { + classHash, + salt: options?.salt ?? generateRandomSalt(), + unique: BigInt(options?.unique ?? true), + calldata: adaptedArgs + }, + { + maxFee: options?.maxFee, + nonce: options?.nonce + } + ); + + const hre = await import("hardhat"); + const deploymentReceipt = await getTransactionReceiptUtil(deployTxHash, hre); + const decodedEvents = udc.decodeEvents(deploymentReceipt.events); + // the only event should be ContractDeployed + const deployedContractAddress = numericToHexString(decodedEvents[0].data.address); + + const deployedContract = contractFactory.getContractAt(deployedContractAddress); + deployedContract.deployTxHash = deployTxHash; + + return deployedContract; + } + + protected assertNotDeployed() { + if (this.deployed) { + const msg = "The account is not expected to be deployed."; + throw new StarknetPluginError(msg); + } + } + + private assertDeployed() { + if (!this.deployed) { + const msg = "Prior to usage, the account must be funded and deployed."; + throw new StarknetPluginError(msg); + } + } + + async estimateFee( + toContract: StarknetContract, + functionName: string, + calldata?: StringMap, + options?: EstimateFeeOptions + ): Promise { + return await this.interact( + InteractChoice.ESTIMATE_FEE, + toContract, + functionName, + calldata, + options + ); + } + + private async estimateDeclareV2Fee( + contractFactory: StarknetContractFactory, + options: EstimateFeeOptions = {} + ): Promise { + const maxFee = (options.maxFee || 0).toString(); + const version = hash.feeTransactionVersion_2; + const nonce = options.nonce == null ? await this.getNonce() : options.nonce; + + const hre = await import("hardhat"); + const chainId = hre.starknet.networkConfig.starknetChainId; + + const compiledClassHash = await hre.starknetWrapper.getCompiledClassHash( + contractFactory.casmPath + ); + + const classHash = await hre.starknetWrapper.getSierraContractClassHash( + contractFactory.metadataPath + ); + + const messageHash = hash.calculateDeclareTransactionHash( + classHash, + this.address, + version, + maxFee, + chainId as unknown as constants.StarknetChainId, + nonce, + compiledClassHash + ); + const signatures = this.getSignatures(messageHash); + + const data = { + type: "DECLARE", + sender_address: this.address, + compiled_class_hash: compiledClassHash, + contract_class: readCairo1Contract(contractFactory.metadataPath).getCompiledClass(), + signature: bnToDecimalStringArray(signatures || []), + version: numericToHexString(version), + nonce: numericToHexString(nonce) + }; + + return await sendEstimateFeeTx(data); + } + + async estimateDeclareFee( + contractFactory: StarknetContractFactory, + options: EstimateFeeOptions = {} + ): Promise { + if (contractFactory.isCairo1()) { + return await this.estimateDeclareV2Fee(contractFactory, options); + } + + const nonce = options.nonce == null ? await this.getNonce() : options.nonce; + const maxFee = (options.maxFee || 0).toString(); + + const hre = await import("hardhat"); + const classHash = await hre.starknetWrapper.getClassHash(contractFactory.metadataPath); + const chainId = hre.starknet.networkConfig.starknetChainId; + + const calldata = [classHash]; + const calldataHash = hash.computeHashOnElements(calldata); + + const messageHash = hash.computeHashOnElements([ + TransactionHashPrefix.DECLARE, + numericToHexString(QUERY_VERSION), + this.address, + 0, // entrypoint selector is implied + calldataHash, + maxFee, + chainId, + numericToHexString(nonce) + ]); + + const signature = this.getSignatures(messageHash); + const data = { + type: "DECLARE", + sender_address: this.address, + contract_class: readContract(contractFactory.metadataPath), + signature: bnToDecimalStringArray(signature || []), + version: numericToHexString(QUERY_VERSION), + nonce: numericToHexString(nonce) + }; + return await sendEstimateFeeTx(data); + } + + async estimateDeployFee( + contractFactory: StarknetContractFactory, + constructorArguments?: StringMap, + options: EstimateFeeOptions = {} + ): Promise { + const classHash = await contractFactory.getClassHash(); + const udc = await UDC.getInstance(); + const adaptedArgs = contractFactory.handleConstructorArguments(constructorArguments); + const calldata: StringMap = { + classHash, + salt: options?.salt ?? generateRandomSalt(), + unique: BigInt(options?.unique ?? true), + calldata: adaptedArgs + }; + return await this.estimateFee(udc, UDC_DEPLOY_FUNCTION_NAME, calldata, options); + } + + private async interact( + choice: InteractChoice, + toContract: StarknetContract, + functionName: string, + calldata?: StringMap, + options?: InteractOptions + ) { + const call: CallParameters = { + functionName: functionName, + toContract: toContract, + calldata: calldata + }; + + return await this.multiInteract(choice, [call], options); + } + + /** + * Performs multiple invokes as a single transaction through this account + * @param callParameters an array with the parameters for each invoke + * @returns the transaction hash of the invoke + */ + async multiInvoke(callParameters: CallParameters[], options?: InvokeOptions): Promise { + // Invoke only returns one transaction hash, as the multiple invokes are done by the account contract, but only one is sent to it. + return await this.multiInteract(InteractChoice.INVOKE, callParameters, options); + } + + /** + * Estimate the fee of the multicall. + * @param callParameters an array with the parameters for each call + * @returns the total estimated fee + */ + async multiEstimateFee( + callParameters: CallParameters[], + options?: EstimateFeeOptions + ): Promise { + return await this.multiInteract(InteractChoice.ESTIMATE_FEE, callParameters, options); + } + + private async multiInteract( + choice: InteractChoice, + callParameters: CallParameters[], + options: InteractOptions = {} + ) { + this.assertDeployed(); + options = copyWithBigint(options); + options.maxFee = BigInt(options?.maxFee || "0"); + const nonce = options.nonce == null ? await this.getNonce() : options.nonce; + delete options.nonce; // the options object is incompatible if passed on with nonce + + const hre = await import("hardhat"); + const { messageHash, args } = this.handleMultiInteract( + this.address, + callParameters, + nonce, + options.maxFee, + choice.transactionVersion, + hre.starknet.networkConfig.starknetChainId, + options.rawInput + ); + + if (options.signature) { + const msg = + "Custom signature cannot be specified when using Account (it is calculated automatically)"; + throw new StarknetPluginError(msg); + } + const contractInteractOptions = { + signature: this.getSignatures(messageHash), + ...options, + rawInput: false // rawInput shouldn't affect validating args of __execute__ + }; + + const contractInteractor = (( + this.starknetContract[choice.internalCommand] + )).bind(this.starknetContract); + const executionFunctionName = this.getExecutionFunctionName(); + return contractInteractor(executionFunctionName, args, contractInteractOptions); + } + + /** + * Prepares the calldata and hashes the message for the multicall execution + * + * @param accountAddress address of the account contract + * @param callParameters array with the call parameters + * @param nonce current nonce + * @param maxFee the maximum fee amount set for the contract interaction + * @param version the transaction version + * @param chainId the ID of the chain + * @param rawInput if `true`, interprets calldata as already adapted into an array + * @returns the message hash for the multicall and the arguments to execute it with + */ + private handleMultiInteract( + accountAddress: string, + callParameters: CallParameters[], + nonce: Numeric, + maxFee: Numeric, + version: Numeric, + chainId: StarknetChainId, + rawInput: boolean + ) { + const callArray: Call[] = callParameters.map((callParameters) => { + const calldata = rawInput + ? callParameters.calldata + : callParameters.toContract.adaptInput( + callParameters.functionName, + callParameters.calldata + ); + return { + contractAddress: callParameters.toContract.address, + entrypoint: callParameters.functionName, + calldata + }; + }); + + const executeCallArray: ExecuteCallParameters[] = []; + const rawCalldata: RawCalldata = []; + + // Parse the Call array to create the objects which will be accepted by the contract + callArray.forEach((call) => { + const calldata = call.calldata as BigNumberish[]; + executeCallArray.push({ + to: BigInt(call.contractAddress), + selector: selector.starknetKeccak(call.entrypoint), + data_offset: rawCalldata.length, + data_len: calldata.length + }); + rawCalldata.push(...calldata); + }); + + const adaptedNonce = nonce.toString(); + const adaptedMaxFee = numericToHexString(maxFee); + const adaptedVersion = numericToHexString(version); + const messageHash = this.getMessageHash( + TransactionHashPrefix.INVOKE, + accountAddress, + callArray, + adaptedNonce, + adaptedMaxFee, + adaptedVersion, + chainId + ); + + const args = { + call_array: executeCallArray, + calldata: rawCalldata + }; + return { messageHash, args }; + } + + protected abstract getMessageHash( + transactionHashPrefix: TransactionHashPrefix, + accountAddress: string, + callArray: Call[], + nonce: string, + maxFee: string, + version: string, + chainId: StarknetChainId + ): string; + + protected abstract getSignatures(messageHash: string): bigint[]; + + protected abstract estimateDeployAccountFee(): Promise; + + public abstract deployAccount(options?: DeployAccountOptions): Promise; + + protected getExecutionFunctionName() { + return "__execute__"; + } + + private async getNonce(): Promise { + const hre = await import("hardhat"); + return await getNonceUtil(hre, this.address, null); + } + + /** + * Declare the contract class corresponding to the `contractFactory` + * @param contractFactory + * @param options + * @returns transaction hash + */ + public async declare( + contractFactory: StarknetContractFactory, + options: DeclareOptions = {} + ): Promise { + if (contractFactory.isCairo1()) { + return await this.declareV2(contractFactory, options); + } + + let maxFee = options?.maxFee; + if (maxFee && options?.overhead) { + const msg = "maxFee and overhead cannot be specified together"; + throw new StarknetPluginError(msg); + } + + const nonce = options.nonce == null ? await this.getNonce() : options.nonce; + if (maxFee === undefined || maxFee === null) { + const estimatedDeclareFee = await this.estimateDeclareFee(contractFactory, options); + maxFee = estimatedFeeToMaxFee(estimatedDeclareFee.amount, options?.overhead); + } + + const hre = await import("hardhat"); + const classHash = await hre.starknetWrapper.getClassHash(contractFactory.metadataPath); + const chainId = hre.starknet.networkConfig.starknetChainId; + + const calldata = [classHash]; + const calldataHash = hash.computeHashOnElements(calldata); + + const messageHash = hash.computeHashOnElements([ + TransactionHashPrefix.DECLARE, + TRANSACTION_VERSION.toString(), + this.address, + 0, // entrypoint selector is implied + calldataHash, + maxFee.toString(), + chainId, + nonce.toString() + ]); + + const signature = this.getSignatures(messageHash); + return contractFactory.declare({ + nonce, + signature, + token: options.token, + sender: this.address, + maxFee: BigInt(maxFee) + }); + } + + private async declareV2( + contractFactory: StarknetContractFactory, + options: DeclareOptions = {} + ): Promise { + let maxFee = options?.maxFee; + if (maxFee && options?.overhead) { + const msg = "maxFee and overhead cannot be specified together"; + throw new StarknetPluginError(msg); + } + + const nonce = options.nonce == null ? await this.getNonce() : options.nonce; + if (maxFee === undefined || maxFee === null) { + const estimatedDeclareFee = await this.estimateDeclareV2Fee(contractFactory, options); + maxFee = estimatedFeeToMaxFee(estimatedDeclareFee.amount, options?.overhead); + } + + const version = hash.transactionVersion_2; + const hre = await import("hardhat"); + const chainId = hre.starknet.networkConfig.starknetChainId; + + const compiledClassHash = await hre.starknetWrapper.getCompiledClassHash( + contractFactory.casmPath + ); + const classHash = await hre.starknetWrapper.getSierraContractClassHash( + contractFactory.metadataPath + ); + + const messageHash = hash.calculateDeclareTransactionHash( + classHash, + this.address, + version, + maxFee, + chainId as unknown as constants.StarknetChainId, + nonce, + compiledClassHash + ); + const signatures = this.getSignatures(messageHash); + + return sendDeclareV2Tx( + bnToDecimalStringArray(signatures), + compiledClassHash, + maxFee, + this.address, + version, + nonce, + readCairo1Contract(contractFactory.metadataPath) + ); + } +} diff --git a/src/legacy/account/argent-account.ts b/src/legacy/account/argent-account.ts new file mode 100644 index 00000000..689dea99 --- /dev/null +++ b/src/legacy/account/argent-account.ts @@ -0,0 +1,339 @@ +import { ec, hash, selector, BigNumberish, Call, RawCalldata } from "starknet"; + +import { QUERY_VERSION, StarknetChainId, TransactionHashPrefix } from "../../constants"; +import { StarknetPluginError } from "../../starknet-plugin-error"; +import { DeployAccountOptions, InvokeOptions, starknetTypes } from "../../types"; +import { + numericToHexString, + generateRandomSalt, + bnToDecimalStringArray, + estimatedFeeToMaxFee +} from "../../utils"; +import { StarknetContract, StarknetContractFactory } from "../contract"; +import { + calculateDeployAccountHash, + CallParameters, + generateKeys, + handleInternalContractArtifacts, + sendDeployAccountTx, + sendEstimateFeeTx, + signMultiCall +} from "./account-utils"; +import { Account } from "./account"; + +/** + * Wrapper for the Argent implementation of Account + */ + +export class ArgentAccount extends Account { + private static readonly VERSION: string = "780760e4156afe592bb1feff7e769cf279ae9831"; + + private static proxyContractFactory: StarknetContractFactory; + private static implementationContractFactory: StarknetContractFactory; + + private static readonly PROXY_CLASS_HASH = + "0x25ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918"; + private static readonly IMPLEMENTATION_CLASS_HASH = + "0x33434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2"; + + public guardianPublicKey: string; + public guardianPrivateKey: string; + + protected constructor( + starknetContract: StarknetContract, + privateKey: string, + guardianPrivateKey: string, + salt: string, + deployed: boolean + ) { + super(starknetContract, privateKey, salt, deployed); + this.guardianPrivateKey = guardianPrivateKey; + if (this.guardianPrivateKey) { + const guardianSigner = generateKeys(this.guardianPrivateKey); + this.guardianPublicKey = guardianSigner.publicKey; + } + } + + private static async getImplementationContractFactory() { + const hre = await import("hardhat"); + if (!this.implementationContractFactory) { + const contractPath = handleInternalContractArtifacts( + "ArgentAccount", + "ArgentAccount", + this.VERSION, + hre + ); + this.implementationContractFactory = await hre.starknetLegacy.getContractFactory( + contractPath + ); + } + return this.implementationContractFactory; + } + + private static async getProxyContractFactory() { + const hre = await import("hardhat"); + if (!this.proxyContractFactory) { + const contractPath = handleInternalContractArtifacts( + "ArgentAccount", + "Proxy", + this.VERSION, + hre + ); + this.proxyContractFactory = await hre.starknetLegacy.getContractFactory(contractPath); + } + return this.proxyContractFactory; + } + + private static generateGuardianPublicKey(guardianPrivateKey: string) { + if (!guardianPrivateKey) { + return "0x0"; + } + return generateKeys(guardianPrivateKey).publicKey; + } + + /** + * Generates a new key pair if none specified. + * Does NOT generate a new guardian key pair if none specified. + * If you don't specify a guardian private key, no guardian will be assigned. + * The created account needs to be deployed using the `deployAccount` method. + * @param options + * @returns an undeployed instance of account + */ + public static async createAccount( + options: { + salt?: string; + privateKey?: string; + guardianPrivateKey?: string; + } = {} + ): Promise { + const signer = generateKeys(options.privateKey); + const guardianPrivateKey = options?.guardianPrivateKey; + const guardianPublicKey = this.generateGuardianPublicKey(guardianPrivateKey); + const salt = options.salt || generateRandomSalt(); + const constructorCalldata = [ + this.IMPLEMENTATION_CLASS_HASH, + selector.getSelectorFromName("initialize"), + "2", + signer.publicKey, + guardianPublicKey + ]; + const address = hash.calculateContractAddressFromHash( + salt, + this.PROXY_CLASS_HASH, + constructorCalldata, + "0x0" // deployer address + ); + + const proxyContractFactory = await this.getProxyContractFactory(); + const contract = proxyContractFactory.getContractAt(address); + return new this(contract, signer.privateKey, guardianPrivateKey, salt, false); + } + + protected getMessageHash( + transactionHashPrefix: TransactionHashPrefix, + accountAddress: string, + callArray: Call[], + nonce: string, + maxFee: string, + version: string, + chainId: StarknetChainId + ): string { + const hashable: BigNumberish[] = [callArray.length]; + const rawCalldata: RawCalldata = []; + callArray.forEach((call) => { + const calldata = call.calldata as BigNumberish[]; + hashable.push( + call.contractAddress, + selector.starknetKeccak(call.entrypoint), + rawCalldata.length, + calldata.length + ); + rawCalldata.push(...calldata); + }); + + hashable.push(rawCalldata.length, ...rawCalldata); + const calldataHash = hash.computeHashOnElements(hashable); + return hash.computeHashOnElements([ + transactionHashPrefix, + version, + accountAddress, + 0, + calldataHash, + maxFee, + chainId, + nonce + ]); + } + + protected override getSignatures(messageHash: string): bigint[] { + const signatures = signMultiCall(messageHash, this.privateKey); + if (this.guardianPrivateKey) { + const guardianSignatures = signMultiCall(messageHash, this.guardianPrivateKey); + signatures.push(...guardianSignatures); + } + return signatures; + } + + public override async estimateDeployAccountFee(): Promise { + this.assertNotDeployed(); + const hre = await import("hardhat"); + + const nonce = numericToHexString(0); + const maxFee = numericToHexString(0); + + const constructorCalldata: string[] = [ + ArgentAccount.IMPLEMENTATION_CLASS_HASH, + selector.getSelectorFromName("initialize"), + "2", + this.publicKey, + ArgentAccount.generateGuardianPublicKey(this.guardianPrivateKey) + ].map((val) => BigInt(val).toString()); + const calldataHash = hash.computeHashOnElements([ + ArgentAccount.PROXY_CLASS_HASH, + this.salt, + ...constructorCalldata + ]); + const msgHash = hash.computeHashOnElements([ + TransactionHashPrefix.DEPLOY_ACCOUNT, + numericToHexString(QUERY_VERSION), + this.address, + 0, + calldataHash, + maxFee, + hre.starknet.networkConfig.starknetChainId, + nonce + ]); + + const signature = this.getSignatures(msgHash); + const data = { + type: "DEPLOY_ACCOUNT", + class_hash: ArgentAccount.PROXY_CLASS_HASH, + constructor_calldata: constructorCalldata, + contract_address_salt: this.salt, + signature: bnToDecimalStringArray(signature || []), + version: numericToHexString(QUERY_VERSION), + nonce + }; + + return await sendEstimateFeeTx(data); + } + + /** + * Deploys (initializes) the account. + * @param options + * @returns the tx hash of the deployment + */ + public override async deployAccount(options: DeployAccountOptions = {}): Promise { + this.assertNotDeployed(); + const hre = await import("hardhat"); + + let maxFee = options?.maxFee; + if (maxFee && options?.overhead) { + const msg = "maxFee and overhead cannot be specified together"; + throw new StarknetPluginError(msg); + } + + if (maxFee === undefined || maxFee === null) { + const estimatedDeployFee = await this.estimateDeployAccountFee(); + maxFee = estimatedFeeToMaxFee(estimatedDeployFee.amount, options?.overhead); + } + + const constructorCalldata: string[] = [ + ArgentAccount.IMPLEMENTATION_CLASS_HASH, + selector.getSelectorFromName("initialize"), + "2", + this.publicKey, + ArgentAccount.generateGuardianPublicKey(this.guardianPrivateKey) + ].map((val) => BigInt(val).toString()); + + const msgHash = calculateDeployAccountHash( + this.address, + constructorCalldata, + this.salt, + ArgentAccount.PROXY_CLASS_HASH, + numericToHexString(maxFee), + hre.starknet.networkConfig.starknetChainId + ); + + const deploymentTxHash = await sendDeployAccountTx( + this.getSignatures(msgHash).map((val) => val.toString()), + ArgentAccount.PROXY_CLASS_HASH, + constructorCalldata, + this.salt, + numericToHexString(maxFee) + ); + + const implementationFactory = await ArgentAccount.getImplementationContractFactory(); + this.starknetContract.setImplementation(implementationFactory); + this.starknetContract.deployTxHash = deploymentTxHash; + this.deployed = true; + return deploymentTxHash; + } + + /** + * Updates the guardian key in the contract. Set it to `undefined` to remove the guardian. + * @param newGuardianPrivateKey private key of the guardian to update + * @returns hash of the transaction which changes the guardian + */ + public async setGuardian( + newGuardianPrivateKey?: string, + invokeOptions?: InvokeOptions + ): Promise { + let guardianPublicKey: string; + if (!BigInt(newGuardianPrivateKey || 0)) { + newGuardianPrivateKey = undefined; + guardianPublicKey = undefined; + } else { + guardianPublicKey = ec.starkCurve.getStarkKey(newGuardianPrivateKey); + } + + const call: CallParameters = { + functionName: "changeGuardian", + toContract: this.starknetContract, + calldata: { newGuardian: BigInt(guardianPublicKey || 0) } + }; + + const txHash = await this.multiInvoke([call], invokeOptions); + + // set after signing + this.guardianPrivateKey = newGuardianPrivateKey; + this.guardianPublicKey = guardianPublicKey; + + return txHash; + } + + /** + * Returns an account previously deployed to `address`. + * A check is performed if the public key stored in the account matches the provided `privateKey`. + * No check is done for the optional guardian private key. + * @param address + * @param privateKey + * @param options + * @returns the retrieved account + */ + static async getAccountFromAddress( + address: string, + privateKey: string, + options: { + guardianPrivateKey?: string; + } = {} + ): Promise { + const contractFactory = await this.getProxyContractFactory(); + const contract = contractFactory.getContractAt(address); + const implementationFactory = await this.getImplementationContractFactory(); + contract.setImplementation(implementationFactory); + + const { signer: expectedPubKey } = await contract.call("getSigner"); + const publicKey = ec.starkCurve.getStarkKey(privateKey); + + if (expectedPubKey === BigInt(0)) { + // not yet initialized + } else if (BigInt(publicKey) !== expectedPubKey) { + throw new StarknetPluginError( + "The provided private key is not compatible with the public key stored in the contract." + ); + } + + return new this(contract, privateKey, options.guardianPrivateKey, undefined, true); + } +} diff --git a/src/legacy/account/index.ts b/src/legacy/account/index.ts new file mode 100644 index 00000000..c3e4b75f --- /dev/null +++ b/src/legacy/account/index.ts @@ -0,0 +1,4 @@ +export * from "./account"; +export * from "./account-utils"; +export * from "./argent-account"; +export * from "./open-zeppelin-account"; diff --git a/src/legacy/account/open-zeppelin-account.ts b/src/legacy/account/open-zeppelin-account.ts new file mode 100644 index 00000000..082c8279 --- /dev/null +++ b/src/legacy/account/open-zeppelin-account.ts @@ -0,0 +1,218 @@ +import { ec, hash, BigNumberish, Call, RawCalldata } from "starknet"; + +import { QUERY_VERSION, StarknetChainId, TransactionHashPrefix } from "../../constants"; +import { StarknetPluginError } from "../../starknet-plugin-error"; +import { DeployAccountOptions, starknetTypes } from "../../types"; +import { StarknetContract, StarknetContractFactory } from "../contract"; +import { + numericToHexString, + generateRandomSalt, + bnToDecimalStringArray, + estimatedFeeToMaxFee +} from "../../utils"; +import { + calculateDeployAccountHash, + generateKeys, + handleInternalContractArtifacts, + sendDeployAccountTx, + sendEstimateFeeTx, + signMultiCall +} from "./account-utils"; +import { Account } from "./account"; + +/** + * Wrapper for the OpenZeppelin implementation of an Account + */ + +export class OpenZeppelinAccount extends Account { + private static contractFactory: StarknetContractFactory; + + protected constructor( + starknetContract: StarknetContract, + privateKey: string, + salt: string, + deployed: boolean + ) { + super(starknetContract, privateKey, salt, deployed); + } + + private static async getContractFactory() { + const hre = await import("hardhat"); + if (!this.contractFactory) { + const contractPath = handleInternalContractArtifacts( + "OpenZeppelinAccount", + "Account", + "0.5.1", + hre + ); + this.contractFactory = await hre.starknetLegacy.getContractFactory(contractPath); + } + return this.contractFactory; + } + + /** + * Generates a new key pair if none specified. + * The created account needs to be deployed using the `deployAccount` method. + * @param options + * @returns an undeployed instance of account + */ + public static async createAccount( + options: { + salt?: string; + privateKey?: string; + } = {} + ): Promise { + const signer = generateKeys(options.privateKey); + const salt = options.salt || generateRandomSalt(); + const contractFactory = await this.getContractFactory(); + const address = hash.calculateContractAddressFromHash( + salt, + await contractFactory.getClassHash(), + [signer.publicKey], + "0x0" // deployer address + ); + const contract = contractFactory.getContractAt(address); + return new this(contract, signer.privateKey, salt, false); + } + + protected override getMessageHash( + transactionHashPrefix: TransactionHashPrefix, + accountAddress: string, + callArray: Call[], + nonce: string, + maxFee: string, + version: string, + chainId: StarknetChainId + ): string { + const hashable: BigNumberish[] = [callArray.length]; + const rawCalldata: RawCalldata = []; + callArray.forEach((call) => { + const calldata = call.calldata as BigNumberish[]; + hashable.push( + call.contractAddress, + hash.starknetKeccak(call.entrypoint), + rawCalldata.length, + calldata.length + ); + rawCalldata.push(...calldata); + }); + + hashable.push(rawCalldata.length, ...rawCalldata); + const calldataHash = hash.computeHashOnElements(hashable); + return hash.computeHashOnElements([ + transactionHashPrefix, + version, + accountAddress, + 0, + calldataHash, + maxFee, + chainId, + nonce + ]); + } + + protected override getSignatures(messageHash: string): bigint[] { + return signMultiCall(messageHash, this.privateKey); + } + + public override async estimateDeployAccountFee(): Promise { + this.assertNotDeployed(); + const hre = await import("hardhat"); + + const contractFactory = await OpenZeppelinAccount.getContractFactory(); + const classHash = await contractFactory.getClassHash(); + const constructorCalldata = [BigInt(this.publicKey).toString()]; + + const maxFee = numericToHexString(0); + const nonce = numericToHexString(0); + + const calldataHash = hash.computeHashOnElements([ + classHash, + this.salt, + ...constructorCalldata + ]); + const msgHash = hash.computeHashOnElements([ + TransactionHashPrefix.DEPLOY_ACCOUNT, + numericToHexString(QUERY_VERSION), + this.address, + 0, + calldataHash, + maxFee, + hre.starknet.networkConfig.starknetChainId, + nonce + ]); + + const signature = this.getSignatures(msgHash); + const data = { + type: "DEPLOY_ACCOUNT", + class_hash: classHash, + constructor_calldata: constructorCalldata, + contract_address_salt: this.salt, + signature: bnToDecimalStringArray(signature || []), + version: numericToHexString(QUERY_VERSION), + nonce + }; + + return await sendEstimateFeeTx(data); + } + + public override async deployAccount(options: DeployAccountOptions = {}): Promise { + this.assertNotDeployed(); + const hre = await import("hardhat"); + + let maxFee = options?.maxFee; + if (maxFee && options?.overhead) { + const msg = "maxFee and overhead cannot be specified together"; + throw new StarknetPluginError(msg); + } + + if (maxFee === undefined || maxFee === null) { + const estimatedDeployFee = await this.estimateDeployAccountFee(); + maxFee = estimatedFeeToMaxFee(estimatedDeployFee.amount, options?.overhead); + } + + const contractFactory = await OpenZeppelinAccount.getContractFactory(); + const classHash = await contractFactory.getClassHash(); + const constructorCalldata = [BigInt(this.publicKey).toString()]; + + const msgHash = calculateDeployAccountHash( + this.address, + constructorCalldata, + this.salt, + classHash, + numericToHexString(maxFee), + hre.starknet.networkConfig.starknetChainId + ); + + const deploymentTxHash = await sendDeployAccountTx( + this.getSignatures(msgHash).map((val) => val.toString()), + classHash, + constructorCalldata, + this.salt, + numericToHexString(maxFee) + ); + + this.starknetContract.deployTxHash = deploymentTxHash; + this.deployed = true; + return deploymentTxHash; + } + + static async getAccountFromAddress( + address: string, + privateKey: string + ): Promise { + const contractFactory = await this.getContractFactory(); + const contract = contractFactory.getContractAt(address); + + const { publicKey: expectedPubKey } = await contract.call("getPublicKey"); + const publicKey = ec.starkCurve.getStarkKey(privateKey); + + if (BigInt(publicKey) !== expectedPubKey) { + throw new StarknetPluginError( + "The provided private key is not compatible with the public key stored in the contract." + ); + } + + return new this(contract, privateKey, undefined, true); + } +} diff --git a/src/legacy/contract/cairo1-contract-class.ts b/src/legacy/contract/cairo1-contract-class.ts new file mode 100644 index 00000000..29d49200 --- /dev/null +++ b/src/legacy/contract/cairo1-contract-class.ts @@ -0,0 +1,29 @@ +import { StarknetContract } from "./starknet-contract"; +import { ContractClassConfig, SierraEntryPointsByType } from "../../types"; + +export class Cairo1ContractClass extends StarknetContract { + protected sierraProgram: string; + protected contractClassVersion: string; + protected entryPointsByType: SierraEntryPointsByType; + + constructor(config: ContractClassConfig) { + super(config); + + this.sierraProgram = config.sierraProgram; + this.contractClassVersion = config.contractClassVersion; + this.entryPointsByType = config.entryPointsByType; + } + + /** + * Returns the compiled class. + * @returns object of a compiled contract class + */ + getCompiledClass() { + return { + sierra_program: this.sierraProgram, + contract_class_version: this.contractClassVersion, + entry_points_by_type: this.entryPointsByType, + abi: this.abiRaw + }; + } +} diff --git a/src/legacy/contract/index.ts b/src/legacy/contract/index.ts new file mode 100644 index 00000000..50cbdf88 --- /dev/null +++ b/src/legacy/contract/index.ts @@ -0,0 +1,3 @@ +export * from "./cairo1-contract-class"; +export * from "./starknet-contract"; +export * from "./starknet-contract-factory"; diff --git a/src/legacy/contract/starknet-contract-factory.ts b/src/legacy/contract/starknet-contract-factory.ts new file mode 100644 index 00000000..09514080 --- /dev/null +++ b/src/legacy/contract/starknet-contract-factory.ts @@ -0,0 +1,188 @@ +import { HardhatRuntimeEnvironment, StringMap } from "hardhat/types"; +import { + DeclareContractTransaction, + InvocationsDetailsWithNonce, + LegacyContractClass, + SierraContractClass, + provider as providerUtil, + selector +} from "starknet"; + +import { HEXADECIMAL_REGEX } from "../../constants"; +import { StarknetPluginError } from "../../starknet-plugin-error"; +import { Numeric, starknetTypes } from "../../types"; +import { readContractSync, findConstructor } from "../../utils"; +import { StarknetContractFactoryConfig, DeclareOptions } from "../types"; +import { readAbi, getFallbackAbi, mapAbi, iterativelyCheckStatus, adaptInputUtil } from "../utils"; +import { StarknetContract } from "./starknet-contract"; + +/** + * Add `signature` elements to to `starknetArgs`, if there are any. + * @param signature array of transaction signature elements + */ +function handleSignature(signature: Array): string[] { + if (signature) { + return signature.map((s) => s.toString()); + } + return []; +} + +export class StarknetContractFactory { + private classHash: string; + private constructorAbi: starknetTypes.CairoFunction; + private contract: LegacyContractClass | SierraContractClass; + private hre: HardhatRuntimeEnvironment; + + public abi: starknetTypes.Abi; + public abiPath?: string; + public abiRaw: string; + public metadataPath: string; + public casmPath: string; + + constructor(config: StarknetContractFactoryConfig) { + this.hre = config.hre; + this.metadataPath = config.metadataPath; + this.contract = providerUtil.parseContract(readContractSync(this.metadataPath)); + + this.abiPath = config.abiPath; + this.abiRaw = this.abiPath + ? readAbi(this.abiPath) + : getFallbackAbi(this.retrieveContract()); + this.abi = mapAbi(this.abiRaw); + this.metadataPath = config.metadataPath; + this.casmPath = config.casmPath; + + const constructorPredicate = this.resolveConstructorPredicate(); + this.constructorAbi = findConstructor(this.abi, constructorPredicate); + } + + private resolveConstructorPredicate(): (abiEntry: starknetTypes.AbiEntry) => boolean { + if (!this.isCairo1()) { + return (abiEntry: starknetTypes.AbiEntry): boolean => { + return abiEntry.type === "constructor"; + }; + } + + const casmJson = readContractSync(this.casmPath, "utf-8"); + if (casmJson?.compiler_version.split(".")[0] === "0") { + const msg = ".CASM json should have been generated with a compiler version >= 1"; + throw new StarknetPluginError(msg); + } + + const constructors = casmJson?.entry_points_by_type?.CONSTRUCTOR; + if (!constructors || constructors.length === 0) { + return () => false; + } + + // Can be removed after new cairo release. + if (constructors.length > 1) { + const msg = "There can be at most 1 constructor."; + throw new StarknetPluginError(msg); + } + + // Can be simplified once starkware fixes multiple constructor issue. + // Precomputed selector can be used if only 'constructor' name allowed + const constructorSelector = constructors[0].selector; + return (abiEntry: starknetTypes.AbiEntry): boolean => { + return selector.getSelectorFromName(abiEntry.name) === constructorSelector; + }; + } + + private retrieveContract() { + this.contract ??= providerUtil.parseContract(readContractSync(this.metadataPath)); + return this.contract; + } + + /** + * Declare a contract class. + * @param options optional arguments to class declaration + * @returns transaction hash as a hex string + */ + async declare(options: DeclareOptions = {}): Promise { + const transaction: DeclareContractTransaction = { + contract: this.retrieveContract(), + senderAddress: options.sender, + signature: handleSignature(options.signature) + }; + const details: InvocationsDetailsWithNonce = { + maxFee: options.maxFee, + nonce: options.nonce + }; + const contractResponse = await this.hre.starknetProvider + .declareContract(transaction, details) + .catch((error) => { + const msg = `Could not declare class: ${error}`; + throw new StarknetPluginError(msg); + }); + + const txHash = contractResponse.transaction_hash; + return new Promise((resolve, reject) => { + iterativelyCheckStatus( + txHash, + this.hre, + () => resolve(txHash), + (error) => { + reject(new StarknetPluginError(`Declare transaction ${txHash}: ${error}`)); + } + ); + }); + } + + handleConstructorArguments(constructorArguments: StringMap): string[] { + if (!this.constructorAbi) { + const argsProvided = Object.keys(constructorArguments || {}).length; + if (argsProvided) { + const msg = `No constructor arguments required but ${argsProvided} provided`; + throw new StarknetPluginError(msg); + } + return []; + } + return adaptInputUtil( + this.constructorAbi.name, + constructorArguments, + this.constructorAbi.inputs, + this.abi, + this.isCairo1() + ); + } + + /** + * Returns a contract instance with set address. + * No address validity checks are performed. + * @param address the address of a previously deployed contract + * @returns the contract instance at the provided address + */ + getContractAt(address: string) { + if (!address) { + throw new StarknetPluginError("No address provided"); + } + if (typeof address !== "string" || !HEXADECIMAL_REGEX.test(address)) { + throw new StarknetPluginError( + `Address must be 0x-prefixed hex string. Got: "${address}".` + ); + } + const contract = new StarknetContract({ + abiPath: this.abiPath, + abiRaw: this.abiRaw as undefined, + hre: this.hre, + isCairo1: this.isCairo1() + }); + contract.address = address; + return contract; + } + + getAbiPath() { + return this.abiPath; + } + + isCairo1() { + return !!this.casmPath; + } + + async getClassHash() { + const method = this.isCairo1() ? "getSierraContractClassHash" : "getClassHash"; + this.classHash = + this.classHash ?? (await this.hre.starknetWrapper[method](this.metadataPath)); + return this.classHash; + } +} diff --git a/src/legacy/contract/starknet-contract.ts b/src/legacy/contract/starknet-contract.ts new file mode 100644 index 00000000..718d5071 --- /dev/null +++ b/src/legacy/contract/starknet-contract.ts @@ -0,0 +1,315 @@ +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { CallData, ProviderInterface, events as eventUtil, json } from "starknet"; + +import { StarknetPluginError } from "../../starknet-plugin-error"; +import { + StarknetContractConfig, + StringMap, + InvokeOptions, + InvokeResponse, + CallOptions, + EstimateFeeOptions, + DecodedEvent, + BlockNumber, + starknetTypes +} from "../../types"; +import { copyWithBigint } from "../../utils"; +import { + readAbi, + mapAbi, + InteractChoice, + iterativelyCheckStatus, + formatFelt, + adaptInputUtil, + adaptOutputUtil +} from "../utils"; +import { StarknetContractFactory } from "./starknet-contract-factory"; + +/** + * Returns a modified copy of the provided object with its blockNumber set to pending. + * @param options the options object with a blockNumber key + */ +function defaultToPendingBlock(options: T): T { + const adaptedOptions = copyWithBigint(options); + if (adaptedOptions.blockNumber === undefined) { + // using || operator would not handle the zero case correctly + adaptedOptions.blockNumber = "pending"; + } + return adaptedOptions; +} + +export class StarknetContract { + private hre: HardhatRuntimeEnvironment; + protected abi: starknetTypes.Abi; + protected abiPath: string; + protected abiRaw: string; + private isCairo1: boolean; + private _address: string; + public deployTxHash: string; + + constructor(config: StarknetContractConfig) { + this.hre = config.hre; + this.abiPath = config.abiPath; + this.abiRaw = config.abiRaw ?? readAbi(this.abiPath); + this.abi = mapAbi(this.abiRaw); + this.isCairo1 = config.isCairo1; + } + + get address(): string { + return this._address; + } + + set address(address: string) { + this._address = address; + return; + } + + get provider(): ProviderInterface { + return this.hre.starknetProvider; + } + + /** + * Set a custom abi and abi path to the contract + * @param implementation the contract factory of the implementation to be set + */ + setImplementation(implementation: StarknetContractFactory): void { + this.abi = implementation.abi; + this.abiPath = implementation.abiPath; + } + + /** + * Invoke the function by name and optionally provide arguments in an array. + * For a usage example @see {@link call} + * @param functionName + * @param args arguments to Starknet contract function + * @options optional additions to invoking + * @returns a Promise that resolves when the status of the transaction is at least `PENDING` + */ + async invoke( + functionName: string, + args?: StringMap, + options: InvokeOptions = {} + ): Promise { + try { + const adaptedInput = options.rawInput + ? args + : this.adaptInput(functionName, args); + + const { transaction_hash: txHash } = await this.provider.invokeFunction( + { + contractAddress: this.address, + entrypoint: functionName, + calldata: adaptedInput, + signature: options.signature.map(String) + }, + { + nonce: options.nonce ?? (await this.provider.getNonceForAddress(this.address)), + maxFee: options.maxFee, + version: InteractChoice.INVOKE.transactionVersion + } + ); + + return new Promise((resolve, reject) => { + iterativelyCheckStatus( + txHash, + this.hre, + () => resolve(txHash), + (error) => { + reject(new StarknetPluginError(`Invoke transaction ${txHash}: ${error}`)); + } + ); + }); + } catch (error) { + if (!(error instanceof Error)) throw error; + + throw new StarknetPluginError(error.message, error); + } + } + + /** + * Call the function by name and optionally provide arguments in an array. + * + * E.g. If your contract has a function + * ```text + * func double_sum(x: felt, y: felt) -> (res: felt): + * return (res=(x + y) * 2) + * end + * ``` + * then you would call it like: + * ```typescript + * const contract = ...; + * const { res: sum } = await contract.call("double_sum", { x: 2, y: 3 }); + * console.log(sum); + * ``` + * which would result in: + * ```text + * > 10n + * ``` + * + * If options.rawOutput, the Promised object holds a property `response` with an array of strings. + * + * @param functionName + * @param args arguments to Starknet contract function + * @param options optional additions to calling + * @returns a Promise that resolves when the status of the transaction is at least `PENDING` + */ + async call( + functionName: string, + args?: StringMap, + options: CallOptions = {} + ): Promise { + try { + const adaptedOptions = defaultToPendingBlock(options); + const adaptedInput = adaptedOptions.rawInput + ? args + : this.adaptInput(functionName, args); + + const { result } = await this.provider.callContract( + { + contractAddress: this.address, + entrypoint: functionName, + calldata: adaptedInput + }, + adaptedOptions.blockNumber + ); + // align to legacy stdout output + const response = result.map(formatFelt).join(" "); + + if (options.rawOutput) { + return { response }; + } + return this.adaptOutput(functionName, response); + } catch (error) { + if (!(error instanceof Error)) throw error; + + throw new StarknetPluginError(error.message, error); + } + } + + /** + * Computes L1-to-L2 message fee estimation + * @param {string} functionName Function name for entry point selector + * @param {StringMap} args - Arguments to Starknet contract function + * @returns Fee estimation + */ + async estimateMessageFee(functionName: string, args: StringMap) { + // Check if functionName is annotated with @l1_handler + const func = this.abi[functionName]; + + if (!func?.type || func.type.toString() !== "l1_handler") { + throw new StarknetPluginError( + `Cannot estimate message fee on "${functionName}" - not an @l1_handler` + ); + } + const adaptedInput = this.adaptInput(functionName, args); + // Remove value of from_address from the input array + const fromAddress = adaptedInput.shift(); + return this.hre.starknetWrapper.estimateMessageFee( + functionName, + fromAddress, + this.address, + adaptedInput + ); + } + + /** + * Estimate the gas fee of executing `functionName` with `args`. + * @param functionName + * @param args arguments to Starknet contract function + * @param options optional execution specifications + * @returns an object containing the amount and the unit of the estimation + */ + async estimateFee( + functionName: string, + args?: StringMap, + options: EstimateFeeOptions = {} + ): Promise { + try { + const { nonce, maxFee, signature } = defaultToPendingBlock(options); + const result = await this.provider.getInvokeEstimateFee( + { + contractAddress: this.address, + calldata: args, + signature: signature.map(String) + }, + { + nonce: nonce ?? (await this.provider.getNonceForAddress(this.address)), + maxFee: maxFee, + version: InteractChoice.ESTIMATE_FEE.transactionVersion + }, + options.blockNumber + ); + + return { + amount: result.overall_fee, + unit: "wei", + gas_price: result.gas_price, + gas_usage: result.gas_consumed + }; + } catch (error) { + if (!(error instanceof Error)) throw error; + + throw new StarknetPluginError(error.message, error); + } + } + + /** + * Returns the ABI of the whole contract. + * @returns contract ABI + */ + getAbi(): starknetTypes.Abi { + return this.abi; + } + + /** + * Adapt structured `args` to unstructured array expected by e.g. Starknet CLI. + * @param functionName the name of the function to adapt + * @param args structured args + * @returns unstructured args + */ + adaptInput(functionName: string, args?: StringMap): string[] { + const func = this.abi[functionName]; + if (!func) { + const msg = `Function '${functionName}' doesn't exist on ${this.abiPath}.`; + throw new StarknetPluginError(msg); + } + + if (Array.isArray(args)) { + throw new StarknetPluginError("Arguments should be passed in the form of an object."); + } + + return adaptInputUtil(functionName, args, func.inputs, this.abi, this.isCairo1); + } + + /** + * Adapt unstructured `rawResult` to a structured object. + * @param functionName the name of the function that produced the output + * @param rawResult the function output as as unparsed space separated string + * @returns structured output + */ + adaptOutput(functionName: string, rawResult: string) { + const func = this.abi[functionName]; + return adaptOutputUtil(rawResult, func.outputs, this.abi); + } + + /** + * Decode the events to a structured object with parameter names. + * Only decodes the events originating from this contract. + * @param events as received from the server. + * @returns structured object with parameter names. + * @throws if no events decoded + */ + decodeEvents(events: starknetTypes.Event[]): DecodedEvent[] { + const abi = json.parse(this.abiRaw); + const abiEvents = eventUtil.getAbiEvents(abi); + const abiStructs = CallData.getAbiStruct(abi); + + const decodedEvents = eventUtil + .parseEvents(events, abiEvents, abiStructs, {}) + .map((event) => { + const [name, data] = Object.entries(event)[0]; + return { name, data }; + }); + return decodedEvents; + } +} diff --git a/src/extend-utils.ts b/src/legacy/extend-utils.ts similarity index 88% rename from src/extend-utils.ts rename to src/legacy/extend-utils.ts index 7b127f5d..d2a82c85 100644 --- a/src/extend-utils.ts +++ b/src/legacy/extend-utils.ts @@ -1,18 +1,18 @@ import { Block, HardhatRuntimeEnvironment, Transaction } from "hardhat/types"; -import path from "path"; +import path from "node:path"; import { SequencerProvider, uint256 } from "starknet"; -import { handleInternalContractArtifacts } from "./account-utils"; +import { handleInternalContractArtifacts } from "./account"; import { ABI_SUFFIX, CAIRO1_ASSEMBLY_SUFFIX, ETH_ADDRESS, SHORT_STRING_MAX_CHARACTERS -} from "./constants"; -import { StarknetPluginError } from "./starknet-plugin-error"; -import { TransactionReceipt, TransactionTrace } from "./starknet-types"; -import { BlockIdentifier, NonceQueryOptions, StarknetContractFactory } from "./types"; -import { checkArtifactExists, findPath } from "./utils"; +} from "../constants"; +import { StarknetContractFactory } from "./contract"; +import { StarknetPluginError } from "../starknet-plugin-error"; +import { BlockIdentifier, starknetTypes } from "../types"; +import { checkArtifactExists, findPath } from "../utils"; export async function getContractFactoryUtil(hre: HardhatRuntimeEnvironment, contractPath: string) { const artifactsPath = hre.config.paths.starknetArtifacts; @@ -102,10 +102,10 @@ export async function getTransactionUtil( export async function getTransactionReceiptUtil( txHash: string, hre: HardhatRuntimeEnvironment -): Promise { +): Promise { try { const receipt = await hre.starknetProvider.getTransactionReceipt(txHash); - return receipt as unknown as TransactionReceipt; + return receipt as unknown as starknetTypes.TransactionReceipt; } catch (error) { const msg = `Could not get the transaction receipt. Error: ${error}`; throw new StarknetPluginError(msg); @@ -115,10 +115,10 @@ export async function getTransactionReceiptUtil( export async function getTransactionTraceUtil( txHash: string, hre: HardhatRuntimeEnvironment -): Promise { +): Promise { try { const trace = await (hre.starknetProvider as SequencerProvider).getTransactionTrace(txHash); - return trace as TransactionTrace; + return trace as starknetTypes.TransactionTrace; } catch (error) { const msg = `Could not get the transaction trace. Error: ${error}`; throw new StarknetPluginError(msg); @@ -147,7 +147,7 @@ export async function getBlockUtil( export async function getNonceUtil( hre: HardhatRuntimeEnvironment, address: string, - options: NonceQueryOptions + options: BlockIdentifier ): Promise { try { const blockIdentifier = options?.blockHash ?? options?.blockNumber; @@ -164,7 +164,7 @@ export async function getBalanceUtil( hre: HardhatRuntimeEnvironment ): Promise { const contractPath = handleInternalContractArtifacts("Token", "ERC20", "", hre); - const contractFactory = await hre.starknet.getContractFactory(contractPath); + const contractFactory = await hre.starknetLegacy.getContractFactory(contractPath); const ethContract = contractFactory.getContractAt(ETH_ADDRESS); const result = await ethContract.call("balanceOf", { account: address }); diff --git a/src/legacy/index.ts b/src/legacy/index.ts new file mode 100644 index 00000000..06c60aa9 --- /dev/null +++ b/src/legacy/index.ts @@ -0,0 +1,3 @@ +export * from "./account"; +export * from "./contract"; +export * from "./extend-utils"; diff --git a/src/legacy/types/contract.ts b/src/legacy/types/contract.ts new file mode 100644 index 00000000..e8237af8 --- /dev/null +++ b/src/legacy/types/contract.ts @@ -0,0 +1,29 @@ +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { SierraEntryPointsByType } from "starknet"; + +export type StarknetContractFactoryConfig = { + abiPath?: string; + casmPath?: string; + metadataPath: string; + hre: HardhatRuntimeEnvironment; +}; + +export type StarknetContractConfig = { + hre: HardhatRuntimeEnvironment; + isCairo1: boolean; +} & ( + | { + abiPath: string; + abiRaw?: undefined; + } + | { + abiPath?: undefined; + abiRaw: string; + } +); + +export type ContractClassConfig = StarknetContractConfig & { + sierraProgram: string; + contractClassVersion: string; + entryPointsByType: SierraEntryPointsByType; +}; diff --git a/src/legacy/types/index.ts b/src/legacy/types/index.ts new file mode 100644 index 00000000..b4ac7949 --- /dev/null +++ b/src/legacy/types/index.ts @@ -0,0 +1,115 @@ +import { BlockNumber, Numeric, StringMap, starknetTypes } from "../../types"; + +export * from "./contract"; + +/** + * According to: https://starknet.io/docs/hello_starknet/intro.html#interact-with-the-contract + * Not using an enum to avoid code duplication and reverse mapping. + */ +export type TxStatus = + /** The transaction passed the validation and entered the pending block. */ + | "PENDING" + + /** The transaction has not been received yet (i.e., not written to storage). */ + | "NOT_RECEIVED" + + /** The transaction was received by the operator. */ + | "RECEIVED" + + /** The transaction failed validation and thus was skipped. */ + | "REJECTED" + + /** The transaction passed validation but failed execution, and will be (or was) + * included in a block (nonce will be incremented and an execution fee will be charged). + * This status does not distinguish between accepted on L2 / accepted on L1 blocks. + */ + | "REVERTED" + + /** The transaction passed the validation and entered an actual created block. */ + | "ACCEPTED_ON_L2" + + /** The transaction was accepted on-chain. */ + | "ACCEPTED_ON_L1"; + +export type InvokeResponse = string; + +/** + * The object returned by starknet tx_status. + */ +export type StatusObject = { + block_hash: string; + tx_status: TxStatus; + tx_failure_reason?: starknetTypes.TxFailureReason; +}; + +/** + * Object holding the event name and have a property data of type StingMap. + */ +export interface DecodedEvent { + name: string; + data: StringMap; +} + +export interface DeclareOptions { + token?: string; + signature?: Array; + sender?: string; // address + nonce?: Numeric; + maxFee?: Numeric; + overhead?: number; + version?: number; +} + +export interface DeployOptions { + salt?: string; + unique?: boolean; + maxFee?: Numeric; + nonce?: Numeric; +} + +export interface DeployAccountOptions { + maxFee?: Numeric; + overhead?: number; +} + +export interface InvokeOptions { + signature?: Array; + nonce?: Numeric; + maxFee?: Numeric; + rawInput?: boolean; + overhead?: number; +} + +export interface CallOptions { + signature?: Array; + blockNumber?: BlockNumber; + nonce?: Numeric; + maxFee?: Numeric; + rawInput?: boolean; + rawOutput?: boolean; + token?: string; + salt?: string; + unique?: boolean; + sender?: string; // address +} + +export type EstimateFeeOptions = CallOptions; + +export type InteractOptions = InvokeOptions | CallOptions | EstimateFeeOptions; + +export type ContractInteractionFunction = ( + functionName: string, + args?: StringMap, + options?: InteractOptions +) => Promise; + +export type SierraEntryPointsByType = { + CONSTRUCTOR: SierraContractEntryPointFields[]; + EXTERNAL: SierraContractEntryPointFields[]; + L1_HANDLER: SierraContractEntryPointFields[]; +}; + +export type SierraContractEntryPointFields = { + selector: string; + function_idx: number; +}; diff --git a/src/legacy/utils/abi.ts b/src/legacy/utils/abi.ts new file mode 100644 index 00000000..82fe7291 --- /dev/null +++ b/src/legacy/utils/abi.ts @@ -0,0 +1,48 @@ +import fs from "node:fs"; +import { LegacyContractClass, SierraContractClass, hash, json } from "starknet"; + +import { StarknetPluginError } from "../../starknet-plugin-error"; +import { starknetTypes } from "../../types"; + +/** + * Reads the ABI from `abiPath` + */ + +export function readAbi(abiPath: string): string { + return hash.formatSpaces(fs.readFileSync(abiPath).toString("ascii").trim()); +} +/** + * Extracts the ABI from the contract + */ + +export function getFallbackAbi(contract: LegacyContractClass | SierraContractClass): string { + return hash.formatSpaces( + typeof contract.abi === "string" ? contract.abi : json.stringify(contract.abi) + ); +} +/** + * Converts `rawAbi` to an object for lookup by name + */ + +export function mapAbi(rawAbi: string): starknetTypes.Abi { + const abiArray = json.parse(rawAbi); + const abi: starknetTypes.Abi = {}; + extractAbiEntries(abiArray, abi); + return abi; +} +/** + * Recursively extract abi entries and populate the provided `abi` object. + */ +function extractAbiEntries(abiArray: starknetTypes.AbiEntry[], abi: starknetTypes.Abi) { + for (const abiEntry of abiArray) { + if ("items" in abiEntry) { + extractAbiEntries(abiEntry.items, abi); + } else { + if (!abiEntry.name) { + const msg = `Abi entry has no name: ${abiEntry}`; + throw new StarknetPluginError(msg); + } + abi[abiEntry.name] = abiEntry; + } + } +} diff --git a/src/adapt.ts b/src/legacy/utils/adapt.ts similarity index 95% rename from src/adapt.ts rename to src/legacy/utils/adapt.ts index 496df7a7..9d64ec7b 100644 --- a/src/adapt.ts +++ b/src/legacy/utils/adapt.ts @@ -1,9 +1,8 @@ import { BigNumberish, num } from "starknet"; -import { StarknetPluginError } from "./starknet-plugin-error"; -import { HEXADECIMAL_REGEX, LEN_SUFFIX_DEPRECATED } from "./constants"; -import * as starknet from "./starknet-types"; -import { StringMap } from "./types"; +import { StarknetPluginError } from "../../starknet-plugin-error"; +import { HEXADECIMAL_REGEX, LEN_SUFFIX_DEPRECATED } from "../../constants"; +import { StringMap, starknetTypes } from "../../types"; const NAMED_TUPLE_DELIMITER = ": "; const ARGUMENTS_DELIMITER = ", "; @@ -103,7 +102,7 @@ function convertOutputToU256(lo: bigint, hi: bigint): bigint { // Can't use String.split since ':' also can be inside type // Ex: x : (y : felt, z: SomeStruct) -function parseNamedTuple(namedTuple: string): starknet.Argument { +function parseNamedTuple(namedTuple: string): starknetTypes.Argument { const index = namedTuple.indexOf(NAMED_TUPLE_DELIMITER); const name = namedTuple.substring(0, index); const type = namedTuple.substring(name.length + NAMED_TUPLE_DELIMITER.length); @@ -194,8 +193,8 @@ function extractMemberTypes(s: string): string[] { export function adaptInputUtil( functionName: string, input: any, - inputSpecs: starknet.Argument[], - abi: starknet.Abi, + inputSpecs: starknetTypes.Argument[], + abi: starknetTypes.Abi, isCairo1: boolean ): string[] { const adapted: string[] = []; @@ -215,7 +214,7 @@ export function adaptInputUtil( throw new StarknetPluginError(msg); } - let lastSpec: starknet.Argument = { type: null, name: null }; + let lastSpec: starknetTypes.Argument = { type: null, name: null }; for (let i = 0; i < inputSpecs.length; ++i) { const inputSpec = inputSpecs[i]; const currentValue = input[inputSpec.name]; @@ -310,8 +309,8 @@ export function adaptInputUtil( */ function adaptComplexInput( input: any, - inputSpec: starknet.Argument, - abi: starknet.Abi, + inputSpec: starknetTypes.Argument, + abi: starknetTypes.Abi, adaptedArray: string[] ): void { const type = inputSpec.type; @@ -395,8 +394,8 @@ function adaptComplexInput( function adaptStructInput( input: any, - inputSpec: starknet.Argument, - abi: starknet.Abi, + inputSpec: starknetTypes.Argument, + abi: starknetTypes.Abi, adaptedArray: string[] ) { const type = inputSpec.type; @@ -404,7 +403,7 @@ function adaptStructInput( throw new StarknetPluginError(`Type ${type} not present in ABI.`); } - const struct = abi[type]; + const struct = abi[type]; const countArrays = struct.members.filter((i) => isArrayDeprecated(i.type)).length; const expectedInputCount = struct.members.length - countArrays; @@ -428,7 +427,12 @@ function adaptStructInput( /** * resultIndex initially expected to be at value indicating array length */ -function adaptArray(result: bigint[], resultIndex: number, arrayType: string, abi: starknet.Abi) { +function adaptArray( + result: bigint[], + resultIndex: number, + arrayType: string, + abi: starknetTypes.Abi +) { const elementType = arrayType.slice( ARRAY_TYPE_PREFIX.length, arrayType.length - ARRAY_TYPE_SUFFIX.length @@ -462,8 +466,8 @@ function adaptArray(result: bigint[], resultIndex: number, arrayType: string, ab */ export function adaptOutputUtil( rawResult: string, - outputSpecs: starknet.Argument[], - abi: starknet.Abi + outputSpecs: starknetTypes.Argument[], + abi: starknetTypes.Abi ): any { const splitStr = rawResult.split(" "); const result: bigint[] = []; @@ -472,7 +476,7 @@ export function adaptOutputUtil( result.push(parsed); } let resultIndex = 0; - let lastSpec: starknet.Argument = { type: null, name: null }; + let lastSpec: starknetTypes.Argument = { type: null, name: null }; const adapted: StringMap = {}; for (const outputSpec of outputSpecs) { @@ -546,7 +550,12 @@ export function adaptOutputUtil( * @param abi the ABI from which types are taken * @returns an object consisting of the next unused index and the generated tuple/struct itself */ -function generateComplexOutput(raw: bigint[], rawIndex: number, type: string, abi: starknet.Abi) { +function generateComplexOutput( + raw: bigint[], + rawIndex: number, + type: string, + abi: starknetTypes.Abi +) { if (COMMON_NUMERIC_TYPES.includes(type)) { return { generatedComplex: raw[rawIndex], @@ -598,7 +607,7 @@ function generateComplexOutput(raw: bigint[], rawIndex: number, type: string, ab } generatedComplex = {}; - const struct = abi[type]; + const struct = abi[type]; for (const member of struct.members) { const ret = generateComplexOutput(raw, rawIndex, member.type, abi); generatedComplex[member.name] = ret.generatedComplex; diff --git a/src/legacy/utils/index.ts b/src/legacy/utils/index.ts new file mode 100644 index 00000000..4679c7fd --- /dev/null +++ b/src/legacy/utils/index.ts @@ -0,0 +1,123 @@ +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { SequencerProvider } from "starknet"; + +import { + CHECK_STATUS_RECOVER_TIMEOUT, + CHECK_STATUS_TIMEOUT, + QUERY_VERSION, + TRANSACTION_VERSION +} from "../../constants"; +import { StarknetPluginError } from "../../starknet-plugin-error"; +import { Numeric, StatusObject, TxStatus, starknetTypes } from "../../types"; +import { adaptLog, sleep, warn } from "../../utils"; +import { StarknetContract } from "../contract"; + +export * from "./abi"; +export * from "./adapt"; + +const ACCEPTABLE_STATUSES: TxStatus[] = ["PENDING", "ACCEPTED_ON_L2", "ACCEPTED_ON_L1"]; +export function isTxAccepted(statusObject: StatusObject): boolean { + return ACCEPTABLE_STATUSES.includes(statusObject.tx_status); +} + +const UNACCEPTABLE_STATUSES: TxStatus[] = ["REJECTED", "REVERTED"]; +export function isTxRejected(statusObject: StatusObject): boolean { + return UNACCEPTABLE_STATUSES.includes(statusObject.tx_status); +} + +export async function iterativelyCheckStatus( + txHash: string, + hre: HardhatRuntimeEnvironment, + resolve: (status: string) => void, + reject: (reason: Error) => void, + retryCount = 10 +) { + // eslint-disable-next-line no-constant-condition + while (true) { + let count = retryCount; + let statusObject: StatusObject; + let error; + while (count > 0) { + // This promise is rejected usually if the network is unavailable + statusObject = await (hre.starknetProvider as SequencerProvider) + .getTransactionStatus(txHash) + .catch((err) => { + error = new StarknetPluginError(err); + return undefined; + }); + + // Check count at 1 to avoid unnecessary waiting(sleep) in the last iteration + if (statusObject || count === 1) { + break; + } + + await sleep(CHECK_STATUS_RECOVER_TIMEOUT); + warn("Retrying transaction status check..."); + count--; + } + + if (!statusObject) { + warn("Checking transaction status failed."); + return reject(error); + } else if (isTxAccepted(statusObject)) { + return resolve(statusObject.tx_status); + } else if (isTxRejected(statusObject)) { + const adaptedError = adaptLog(JSON.stringify(statusObject, null, 4)); + return reject(new Error(adaptedError)); + } + + await sleep(CHECK_STATUS_TIMEOUT); + } +} + +/** + * Enumerates the ways of interacting with a contract. + */ +export class InteractChoice { + static readonly INVOKE = new InteractChoice(["invoke"], "invoke", true, TRANSACTION_VERSION); + + static readonly CALL = new InteractChoice(["call"], "call", false, QUERY_VERSION); + + static readonly ESTIMATE_FEE = new InteractChoice( + ["invoke", "--estimate_fee"], + "estimateFee", + false, + QUERY_VERSION + ); + + private constructor( + /** + * The way it's supposed to be used passed to CLI commands. + */ + public readonly cliCommand: string[], + /** + * The way it's supposed to be used internally in code. + */ + public readonly internalCommand: keyof StarknetContract, + + /** + * Indicates whether the belonging CLI option allows specifying max_fee. + */ + public readonly allowsMaxFee: boolean, + + /** + * The version of the transaction. + */ + public transactionVersion: Numeric + ) {} +} + +export function parseFeeEstimation(raw: string): starknetTypes.FeeEstimation { + const matchedAmount = raw.match(/^The estimated fee is: (\d*) WEI \(.* ETH\)\./m); + const matchedGasUsage = raw.match(/^Gas usage: (\d*)/m); + const matchedGasPrice = raw.match(/^Gas price: (\d*) WEI/m); + if (matchedAmount && matchedGasUsage && matchedGasPrice) { + return { + amount: BigInt(matchedAmount[1]), + unit: "wei", + gas_price: BigInt(matchedGasPrice[1]), + gas_usage: BigInt(matchedGasUsage[1]) + }; + } + throw new StarknetPluginError(`Cannot parse fee estimation response:\n${raw}`); +} diff --git a/src/starknet-wrappers.ts b/src/starknet-wrappers.ts index 95ff068d..7b0db37a 100644 --- a/src/starknet-wrappers.ts +++ b/src/starknet-wrappers.ts @@ -14,7 +14,7 @@ import { import { ExternalServer } from "./external-server"; import { StarknetDockerProxy } from "./starknet-docker-proxy"; import { StarknetPluginError } from "./starknet-plugin-error"; -import { FeeEstimation } from "./starknet-types"; +import { FeeEstimation } from "./types/starknet-types"; import { StarknetVenvProxy } from "./starknet-venv-proxy"; import { getPrefixedCommand, normalizeVenvPath } from "./utils/venv"; diff --git a/src/type-extensions.ts b/src/type-extensions.ts index f4c62956..ee4d5958 100644 --- a/src/type-extensions.ts +++ b/src/type-extensions.ts @@ -1,16 +1,16 @@ import "hardhat/types/config"; import "hardhat/types/runtime"; -import { GetBlockResponse, ProviderInterface } from "starknet"; +import type * as starknet from "starknet"; -import { Account } from "./account"; import { StarknetChainId } from "./constants"; import { AmarnaDocker } from "./external-server/docker-amarna"; -import { Transaction, TransactionReceipt, TransactionTrace } from "./starknet-types"; +import { Account, StarknetContractFactory, StarknetContract } from "./legacy"; +import { Transaction, TransactionReceipt, TransactionTrace } from "./types/starknet-types"; import { StarknetJsWrapper } from "./starknet-js-wrapper"; import { StarknetWrapper } from "./starknet-wrappers"; -import { StarknetContract, StarknetContractFactory, StringMap } from "./types"; +import { StringMap } from "./types"; import * as DevnetTypes from "./types/devnet"; -import * as StarknetTypes from "./types/starknet"; +import * as StarknetEnvironment from "./types/starknet-environment"; declare module "hardhat/types/config" { export interface ProjectPathsUserConfig { @@ -26,11 +26,11 @@ declare module "hardhat/types/config" { } export interface HardhatConfig { - starknet: StarknetTypes.StarknetConfig; + starknet: StarknetEnvironment.StarknetConfig; } export interface HardhatUserConfig { - starknet?: StarknetTypes.StarknetConfig; + starknet?: StarknetEnvironment.StarknetConfig; } export interface NetworksConfig { @@ -82,17 +82,26 @@ type AccountType = Account; type TransactionReceiptType = TransactionReceipt; type TransactionTraceType = TransactionTrace; type TransactionType = Transaction; -type BlockType = GetBlockResponse; +type BlockType = starknet.GetBlockResponse; declare module "hardhat/types/runtime" { export interface Devnet extends DevnetTypes.Devnet {} interface HardhatRuntimeEnvironment { starknetWrapper: StarknetWrapper; amarnaDocker: AmarnaDocker; - starknet: StarknetTypes.Starknet; + + starknet: typeof starknet & StarknetEnvironment.Starknet; + /** @deprecated + * The legacy utilities are meant to simplify the migration towards directly using `starknet.js` and will be removed in the future. + * + * If there is a functionality that you find difficult to replace, let us know in the corresponding Discord channels: + * - hardhat-plugin https://discord.com/channels/793094838509764618/912735106899275856 + * - starknet.js https://discord.com/channels/793094838509764618/927918707613786162 + */ + starknetLegacy: StarknetEnvironment.StarknetLegacy; starknetJs: StarknetJsWrapper; - starknetProvider: ProviderInterface; + starknetProvider: starknet.ProviderInterface; } type StarknetContract = StarknetContractType; diff --git a/src/types/devnet.ts b/src/types/devnet.ts index 7c5a4e8c..582c8516 100644 --- a/src/types/devnet.ts +++ b/src/types/devnet.ts @@ -1,4 +1,4 @@ -import { Numeric } from "."; +import { Numeric } from "./"; import { FlushResponse, IncreaseTimeResponse, @@ -8,8 +8,8 @@ import { L1ToL2MockTxResponse, L2ToL1MockTxResponse, NewBlockResponse -} from "../devnet-utils"; -import { MintResponse } from "../starknet-types"; +} from "../utils/devnet-utils"; +import { MintResponse } from "./starknet-types"; export interface Devnet { /** diff --git a/src/types/index.ts b/src/types/index.ts index fa903e6f..a8445bc9 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,85 +1,5 @@ -import { HardhatRuntimeEnvironment } from "hardhat/types"; -import fs from "node:fs"; -import { - CallData, - DeclareContractTransaction, - InvocationsDetailsWithNonce, - LegacyContractClass, - ProviderInterface, - SequencerProvider, - SierraContractClass, - events as eventUtil, - hash, - json, - provider as providerUtil, - selector -} from "starknet"; - -import { adaptInputUtil, adaptOutputUtil, formatFelt } from "../adapt"; -import { - CHECK_STATUS_RECOVER_TIMEOUT, - QUERY_VERSION, - TRANSACTION_VERSION, - HEXADECIMAL_REGEX, - CHECK_STATUS_TIMEOUT -} from "../constants"; -import { StarknetPluginError } from "../starknet-plugin-error"; -import * as starknet from "../starknet-types"; -import { adaptLog, copyWithBigint, findConstructor, readContractSync, sleep, warn } from "../utils"; - -/** - * According to: https://starknet.io/docs/hello_starknet/intro.html#interact-with-the-contract - * Not using an enum to avoid code duplication and reverse mapping. - */ -export type TxStatus = - /** The transaction passed the validation and entered the pending block. */ - | "PENDING" - - /** The transaction has not been received yet (i.e., not written to storage). */ - | "NOT_RECEIVED" - - /** The transaction was received by the operator. */ - | "RECEIVED" - - /** The transaction failed validation and thus was skipped. */ - | "REJECTED" - - /** The transaction passed validation but failed execution, and will be (or was) - * included in a block (nonce will be incremented and an execution fee will be charged). - * This status does not distinguish between accepted on L2 / accepted on L1 blocks. - */ - | "REVERTED" - - /** The transaction passed the validation and entered an actual created block. */ - | "ACCEPTED_ON_L2" - - /** The transaction was accepted on-chain. */ - | "ACCEPTED_ON_L1"; - -export type InvokeResponse = string; - -export type StarknetContractFactoryConfig = { - abiPath?: string; - casmPath?: string; - metadataPath: string; - hre: HardhatRuntimeEnvironment; -}; - -export type StarknetContractConfig = { - hre: HardhatRuntimeEnvironment; - isCairo1: boolean; -} & ( - | { - abiPath: string; - abiRaw?: undefined; - } - | { - abiPath?: undefined; - abiRaw: string; - } -); - -export type Numeric = number | bigint; +export * from "../legacy/types"; +export * as starknetTypes from "./starknet-types"; /** * Object whose keys are strings (names) and values are any object. @@ -88,266 +8,7 @@ export interface StringMap { [key: string]: any; } -/** - * Object holding the event name and have a property data of type StingMap. - */ -export interface DecodedEvent { - name: string; - data: StringMap; -} - -/** - * Enumerates the ways of interacting with a contract. - */ -export class InteractChoice { - static readonly INVOKE = new InteractChoice(["invoke"], "invoke", true, TRANSACTION_VERSION); - - static readonly CALL = new InteractChoice(["call"], "call", false, QUERY_VERSION); - - static readonly ESTIMATE_FEE = new InteractChoice( - ["invoke", "--estimate_fee"], - "estimateFee", - false, - QUERY_VERSION - ); - - private constructor( - /** - * The way it's supposed to be used passed to CLI commands. - */ - public readonly cliCommand: string[], - /** - * The way it's supposed to be used internally in code. - */ - public readonly internalCommand: keyof StarknetContract, - - /** - * Indicates whether the belonging CLI option allows specifying max_fee. - */ - public readonly allowsMaxFee: boolean, - - /** - * The version of the transaction. - */ - public transactionVersion: Numeric - ) {} -} - -/** - * The object returned by starknet tx_status. - */ -type StatusObject = { - block_hash: string; - tx_status: TxStatus; - tx_failure_reason?: starknet.TxFailureReason; -}; - -const ACCEPTABLE_STATUSES: TxStatus[] = ["PENDING", "ACCEPTED_ON_L2", "ACCEPTED_ON_L1"]; -export function isTxAccepted(statusObject: StatusObject): boolean { - return ACCEPTABLE_STATUSES.includes(statusObject.tx_status); -} - -const UNACCEPTABLE_STATUSES: TxStatus[] = ["REJECTED", "REVERTED"]; -function isTxRejected(statusObject: StatusObject): boolean { - return UNACCEPTABLE_STATUSES.includes(statusObject.tx_status); -} - -export async function iterativelyCheckStatus( - txHash: string, - hre: HardhatRuntimeEnvironment, - resolve: (status: string) => void, - reject: (reason: Error) => void, - retryCount = 10 -) { - // eslint-disable-next-line no-constant-condition - while (true) { - let count = retryCount; - let statusObject: StatusObject; - let error; - while (count > 0) { - // This promise is rejected usually if the network is unavailable - statusObject = await (hre.starknetProvider as SequencerProvider) - .getTransactionStatus(txHash) - .catch((err) => { - error = new StarknetPluginError(err); - return undefined; - }); - - // Check count at 1 to avoid unnecessary waiting(sleep) in the last iteration - if (statusObject || count === 1) { - break; - } - - await sleep(CHECK_STATUS_RECOVER_TIMEOUT); - warn("Retrying transaction status check..."); - count--; - } - - if (!statusObject) { - warn("Checking transaction status failed."); - return reject(error); - } else if (isTxAccepted(statusObject)) { - return resolve(statusObject.tx_status); - } else if (isTxRejected(statusObject)) { - const adaptedError = adaptLog(JSON.stringify(statusObject, null, 4)); - return reject(new Error(adaptedError)); - } - - await sleep(CHECK_STATUS_TIMEOUT); - } -} - -/** - * Reads the ABI from `abiPath` - */ -function readAbi(abiPath: string): string { - return hash.formatSpaces(fs.readFileSync(abiPath).toString("ascii").trim()); -} - -/** - * Extracts the ABI from the contract - */ -function getFallbackAbi(contract: LegacyContractClass | SierraContractClass): string { - return hash.formatSpaces( - typeof contract.abi === "string" ? contract.abi : json.stringify(contract.abi) - ); -} - -/** - * Converts `rawAbi` to an object for lookup by name - */ -function mapAbi(rawAbi: string): starknet.Abi { - const abiArray = json.parse(rawAbi); - const abi: starknet.Abi = {}; - extractAbiEntries(abiArray, abi); - return abi; -} - -/** - * Recursively extract abi entries and populate the provided `abi` object. - */ -function extractAbiEntries(abiArray: starknet.AbiEntry[], abi: starknet.Abi) { - for (const abiEntry of abiArray) { - if ("items" in abiEntry) { - extractAbiEntries(abiEntry.items, abi); - } else { - if (!abiEntry.name) { - const msg = `Abi entry has no name: ${abiEntry}`; - throw new StarknetPluginError(msg); - } - abi[abiEntry.name] = abiEntry; - } - } -} - -/** - * Add `signature` elements to to `starknetArgs`, if there are any. - * @param signature array of transaction signature elements - */ -function handleSignature(signature: Array): string[] { - if (signature) { - return signature.map((s) => s.toString()); - } - return []; -} - -/** - * Extract events from the ABI. - * @param abi the path where ABI is stored on disk. - * @returns an object mapping ABI entry names with their values. - */ -function extractEventSpecifications(abi: starknet.Abi) { - const events: starknet.EventAbi = {}; - for (const abiEntryName in abi) { - if (abi[abiEntryName].type === "event") { - const event = abi[abiEntryName]; - const encodedEventName = selector.getSelectorFromName(event.name); - events[encodedEventName] = event; - } - } - return events; -} - -export function parseFeeEstimation(raw: string): starknet.FeeEstimation { - const matchedAmount = raw.match(/^The estimated fee is: (\d*) WEI \(.* ETH\)\./m); - const matchedGasUsage = raw.match(/^Gas usage: (\d*)/m); - const matchedGasPrice = raw.match(/^Gas price: (\d*) WEI/m); - if (matchedAmount && matchedGasUsage && matchedGasPrice) { - return { - amount: BigInt(matchedAmount[1]), - unit: "wei", - gas_price: BigInt(matchedGasPrice[1]), - gas_usage: BigInt(matchedGasUsage[1]) - }; - } - throw new StarknetPluginError(`Cannot parse fee estimation response:\n${raw}`); -} - -/** - * Returns a modified copy of the provided object with its blockNumber set to pending. - * @param options the options object with a blockNumber key - */ -function defaultToPendingBlock(options: T): T { - const adaptedOptions = copyWithBigint(options); - if (adaptedOptions.blockNumber === undefined) { - // using || operator would not handle the zero case correctly - adaptedOptions.blockNumber = "pending"; - } - return adaptedOptions; -} - -export interface DeclareOptions { - token?: string; - signature?: Array; - sender?: string; // address - nonce?: Numeric; - maxFee?: Numeric; - overhead?: number; - version?: number; -} - -export interface DeployOptions { - salt?: string; - unique?: boolean; - maxFee?: Numeric; - nonce?: Numeric; -} - -export interface DeployAccountOptions { - maxFee?: Numeric; - overhead?: number; -} - -export interface InvokeOptions { - signature?: Array; - nonce?: Numeric; - maxFee?: Numeric; - rawInput?: boolean; - overhead?: number; -} - -export interface CallOptions { - signature?: Array; - blockNumber?: BlockNumber; - nonce?: Numeric; - maxFee?: Numeric; - rawInput?: boolean; - rawOutput?: boolean; - token?: string; - salt?: string; - unique?: boolean; - sender?: string; // address -} - -export type EstimateFeeOptions = CallOptions; - -export type InteractOptions = InvokeOptions | CallOptions | EstimateFeeOptions; - -export type ContractInteractionFunction = ( - functionName: string, - args?: StringMap, - options?: InteractOptions -) => Promise; +export type Numeric = number | bigint; export type BlockNumber = number | "pending" | "latest"; @@ -356,490 +17,6 @@ export interface BlockIdentifier { blockHash?: string; } -export type SierraEntryPointsByType = { - CONSTRUCTOR: SierraContractEntryPointFields[]; - EXTERNAL: SierraContractEntryPointFields[]; - L1_HANDLER: SierraContractEntryPointFields[]; -}; - -export type SierraContractEntryPointFields = { - selector: string; - function_idx: number; -}; - -export type NonceQueryOptions = BlockIdentifier; - -export class StarknetContractFactory { - private classHash: string; - private constructorAbi: starknet.CairoFunction; - private contract: LegacyContractClass | SierraContractClass; - private hre: HardhatRuntimeEnvironment; - - public abi: starknet.Abi; - public abiPath?: string; - public abiRaw: string; - public metadataPath: string; - public casmPath: string; - - constructor(config: StarknetContractFactoryConfig) { - this.hre = config.hre; - this.metadataPath = config.metadataPath; - this.contract = providerUtil.parseContract(readContractSync(this.metadataPath)); - - this.abiPath = config.abiPath; - this.abiRaw = this.abiPath - ? readAbi(this.abiPath) - : getFallbackAbi(this.retrieveContract()); - this.abi = mapAbi(this.abiRaw); - this.metadataPath = config.metadataPath; - this.casmPath = config.casmPath; - - const constructorPredicate = this.resolveConstructorPredicate(); - this.constructorAbi = findConstructor(this.abi, constructorPredicate); - } - - private resolveConstructorPredicate(): (abiEntry: starknet.AbiEntry) => boolean { - if (!this.isCairo1()) { - return (abiEntry: starknet.AbiEntry): boolean => { - return abiEntry.type === "constructor"; - }; - } - - const casmJson = readContractSync(this.casmPath, "utf-8"); - if (casmJson?.compiler_version.split(".")[0] === "0") { - const msg = ".CASM json should have been generated with a compiler version >= 1"; - throw new StarknetPluginError(msg); - } - - const constructors = casmJson?.entry_points_by_type?.CONSTRUCTOR; - if (!constructors || constructors.length === 0) { - return () => false; - } - - // Can be removed after new cairo release. - if (constructors.length > 1) { - const msg = "There can be at most 1 constructor."; - throw new StarknetPluginError(msg); - } - - // Can be simplified once starkware fixes multiple constructor issue. - // Precomputed selector can be used if only 'constructor' name allowed - const constructorSelector = constructors[0].selector; - return (abiEntry: starknet.AbiEntry): boolean => { - return selector.getSelectorFromName(abiEntry.name) === constructorSelector; - }; - } - - private retrieveContract() { - this.contract ??= providerUtil.parseContract(readContractSync(this.metadataPath)); - return this.contract; - } - - /** - * Declare a contract class. - * @param options optional arguments to class declaration - * @returns transaction hash as a hex string - */ - async declare(options: DeclareOptions = {}): Promise { - const transaction: DeclareContractTransaction = { - contract: this.retrieveContract(), - senderAddress: options.sender, - signature: handleSignature(options.signature) - }; - const details: InvocationsDetailsWithNonce = { - maxFee: options.maxFee, - nonce: options.nonce - }; - const contractResponse = await this.hre.starknetProvider - .declareContract(transaction, details) - .catch((error) => { - const msg = `Could not declare class: ${error}`; - throw new StarknetPluginError(msg); - }); - - const txHash = contractResponse.transaction_hash; - return new Promise((resolve, reject) => { - iterativelyCheckStatus( - txHash, - this.hre, - () => resolve(txHash), - (error) => { - reject(new StarknetPluginError(`Declare transaction ${txHash}: ${error}`)); - } - ); - }); - } - - handleConstructorArguments(constructorArguments: StringMap): string[] { - if (!this.constructorAbi) { - const argsProvided = Object.keys(constructorArguments || {}).length; - if (argsProvided) { - const msg = `No constructor arguments required but ${argsProvided} provided`; - throw new StarknetPluginError(msg); - } - return []; - } - return adaptInputUtil( - this.constructorAbi.name, - constructorArguments, - this.constructorAbi.inputs, - this.abi, - this.isCairo1() - ); - } - - /** - * Returns a contract instance with set address. - * No address validity checks are performed. - * @param address the address of a previously deployed contract - * @returns the contract instance at the provided address - */ - getContractAt(address: string) { - if (!address) { - throw new StarknetPluginError("No address provided"); - } - if (typeof address !== "string" || !HEXADECIMAL_REGEX.test(address)) { - throw new StarknetPluginError( - `Address must be 0x-prefixed hex string. Got: "${address}".` - ); - } - const contract = new StarknetContract({ - abiPath: this.abiPath, - abiRaw: this.abiRaw as undefined, - hre: this.hre, - isCairo1: this.isCairo1() - }); - contract.address = address; - return contract; - } - - getAbiPath() { - return this.abiPath; - } - - isCairo1() { - return !!this.casmPath; - } - - async getClassHash() { - const method = this.isCairo1() ? "getSierraContractClassHash" : "getClassHash"; - this.classHash = - this.classHash ?? (await this.hre.starknetWrapper[method](this.metadataPath)); - return this.classHash; - } -} - -export class StarknetContract { - private hre: HardhatRuntimeEnvironment; - protected abi: starknet.Abi; - protected abiPath: string; - protected abiRaw: string; - private isCairo1: boolean; - private eventsSpecifications: starknet.EventAbi; - private _address: string; - public deployTxHash: string; - - constructor(config: StarknetContractConfig) { - this.hre = config.hre; - this.abiPath = config.abiPath; - this.abiRaw = config.abiRaw ?? readAbi(this.abiPath); - this.abi = mapAbi(this.abiRaw); - this.isCairo1 = config.isCairo1; - this.eventsSpecifications = extractEventSpecifications(this.abi); - } - - get address(): string { - return this._address; - } - - set address(address: string) { - this._address = address; - return; - } - - get provider(): ProviderInterface { - return this.hre.starknetProvider; - } - - /** - * Set a custom abi and abi path to the contract - * @param implementation the contract factory of the implementation to be set - */ - setImplementation(implementation: StarknetContractFactory): void { - this.abi = implementation.abi; - this.abiPath = implementation.abiPath; - } - - /** - * Invoke the function by name and optionally provide arguments in an array. - * For a usage example @see {@link call} - * @param functionName - * @param args arguments to Starknet contract function - * @options optional additions to invoking - * @returns a Promise that resolves when the status of the transaction is at least `PENDING` - */ - async invoke( - functionName: string, - args?: StringMap, - options: InvokeOptions = {} - ): Promise { - try { - const adaptedInput = options.rawInput - ? args - : this.adaptInput(functionName, args); - - const { transaction_hash: txHash } = await this.provider.invokeFunction( - { - contractAddress: this.address, - entrypoint: functionName, - calldata: adaptedInput, - signature: options.signature.map(String) - }, - { - nonce: options.nonce ?? (await this.provider.getNonceForAddress(this.address)), - maxFee: options.maxFee, - version: InteractChoice.INVOKE.transactionVersion - } - ); - - return new Promise((resolve, reject) => { - iterativelyCheckStatus( - txHash, - this.hre, - () => resolve(txHash), - (error) => { - reject(new StarknetPluginError(`Invoke transaction ${txHash}: ${error}`)); - } - ); - }); - } catch (error) { - if (!(error instanceof Error)) throw error; - - throw new StarknetPluginError(error.message, error); - } - } - - /** - * Call the function by name and optionally provide arguments in an array. - * - * E.g. If your contract has a function - * ```text - * func double_sum(x: felt, y: felt) -> (res: felt): - * return (res=(x + y) * 2) - * end - * ``` - * then you would call it like: - * ```typescript - * const contract = ...; - * const { res: sum } = await contract.call("double_sum", { x: 2, y: 3 }); - * console.log(sum); - * ``` - * which would result in: - * ```text - * > 10n - * ``` - * - * If options.rawOutput, the Promised object holds a property `response` with an array of strings. - * - * @param functionName - * @param args arguments to Starknet contract function - * @param options optional additions to calling - * @returns a Promise that resolves when the status of the transaction is at least `PENDING` - */ - async call( - functionName: string, - args?: StringMap, - options: CallOptions = {} - ): Promise { - try { - const adaptedOptions = defaultToPendingBlock(options); - const adaptedInput = adaptedOptions.rawInput - ? args - : this.adaptInput(functionName, args); - - const { result } = await this.provider.callContract( - { - contractAddress: this.address, - entrypoint: functionName, - calldata: adaptedInput - }, - adaptedOptions.blockNumber - ); - // align to legacy stdout output - const response = result.map(formatFelt).join(" "); - - if (options.rawOutput) { - return { response }; - } - return this.adaptOutput(functionName, response); - } catch (error) { - if (!(error instanceof Error)) throw error; - - throw new StarknetPluginError(error.message, error); - } - } - - /** - * Computes L1-to-L2 message fee estimation - * @param {string} functionName Function name for entry point selector - * @param {StringMap} args - Arguments to Starknet contract function - * @returns Fee estimation - */ - async estimateMessageFee(functionName: string, args: StringMap) { - // Check if functionName is annotated with @l1_handler - const func = this.abi[functionName]; - - if (!func?.type || func.type.toString() !== "l1_handler") { - throw new StarknetPluginError( - `Cannot estimate message fee on "${functionName}" - not an @l1_handler` - ); - } - const adaptedInput = this.adaptInput(functionName, args); - // Remove value of from_address from the input array - const fromAddress = adaptedInput.shift(); - return this.hre.starknetWrapper.estimateMessageFee( - functionName, - fromAddress, - this.address, - adaptedInput - ); - } - - /** - * Estimate the gas fee of executing `functionName` with `args`. - * @param functionName - * @param args arguments to Starknet contract function - * @param options optional execution specifications - * @returns an object containing the amount and the unit of the estimation - */ - async estimateFee( - functionName: string, - args?: StringMap, - options: EstimateFeeOptions = {} - ): Promise { - try { - const { nonce, maxFee, signature } = defaultToPendingBlock(options); - const result = await this.provider.getInvokeEstimateFee( - { - contractAddress: this.address, - calldata: args, - signature: signature.map(String) - }, - { - nonce: nonce ?? (await this.provider.getNonceForAddress(this.address)), - maxFee: maxFee, - version: InteractChoice.ESTIMATE_FEE.transactionVersion - }, - options.blockNumber - ); - - return { - amount: result.overall_fee, - unit: "wei", - gas_price: result.gas_price, - gas_usage: result.gas_consumed - }; - } catch (error) { - if (!(error instanceof Error)) throw error; - - throw new StarknetPluginError(error.message, error); - } - } - - /** - * Returns the ABI of the whole contract. - * @returns contract ABI - */ - getAbi(): starknet.Abi { - return this.abi; - } - - /** - * Adapt structured `args` to unstructured array expected by e.g. Starknet CLI. - * @param functionName the name of the function to adapt - * @param args structured args - * @returns unstructured args - */ - adaptInput(functionName: string, args?: StringMap): string[] { - const func = this.abi[functionName]; - if (!func) { - const msg = `Function '${functionName}' doesn't exist on ${this.abiPath}.`; - throw new StarknetPluginError(msg); - } - - if (Array.isArray(args)) { - throw new StarknetPluginError("Arguments should be passed in the form of an object."); - } - - return adaptInputUtil(functionName, args, func.inputs, this.abi, this.isCairo1); - } - - /** - * Adapt unstructured `rawResult` to a structured object. - * @param functionName the name of the function that produced the output - * @param rawResult the function output as as unparsed space separated string - * @returns structured output - */ - adaptOutput(functionName: string, rawResult: string) { - const func = this.abi[functionName]; - return adaptOutputUtil(rawResult, func.outputs, this.abi); - } - - /** - * Decode the events to a structured object with parameter names. - * Only decodes the events originating from this contract. - * @param events as received from the server. - * @returns structured object with parameter names. - * @throws if no events decoded - */ - decodeEvents(events: starknet.Event[]): DecodedEvent[] { - const abi = json.parse(this.abiRaw); - const abiEvents = eventUtil.getAbiEvents(abi); - const abiStructs = CallData.getAbiStruct(abi); - - const decodedEvents = eventUtil - .parseEvents(events, abiEvents, abiStructs, {}) - .map((event) => { - const [name, data] = Object.entries(event)[0]; - return { name, data }; - }); - return decodedEvents; - } -} - -export type ContractClassConfig = StarknetContractConfig & { - sierraProgram: string; - contractClassVersion: string; - entryPointsByType: SierraEntryPointsByType; -}; - -export class Cairo1ContractClass extends StarknetContract { - protected sierraProgram: string; - protected contractClassVersion: string; - protected entryPointsByType: SierraEntryPointsByType; - - constructor(config: ContractClassConfig) { - super(config); - - this.sierraProgram = config.sierraProgram; - this.contractClassVersion = config.contractClassVersion; - this.entryPointsByType = config.entryPointsByType; - } - - /** - * Returns the compiled class. - * @returns object of a compiled contract class - */ - getCompiledClass() { - return { - sierra_program: this.sierraProgram, - contract_class_version: this.contractClassVersion, - entry_points_by_type: this.entryPointsByType, - abi: this.abiRaw - }; - } -} - export interface ScarbConfig { package: { name: string; diff --git a/src/types/starknet.ts b/src/types/starknet-environment.ts similarity index 88% rename from src/types/starknet.ts rename to src/types/starknet-environment.ts index 2df2bf6a..b64e57f4 100644 --- a/src/types/starknet.ts +++ b/src/types/starknet-environment.ts @@ -1,11 +1,28 @@ import { Block, HardhatNetworkConfig, NetworkConfig, Transaction } from "hardhat/types"; -import { BlockIdentifier, NonceQueryOptions, StarknetContractFactory } from "."; +import { BlockIdentifier } from "."; +import { StarknetContractFactory } from "../legacy/contract/starknet-contract-factory"; import { Devnet } from "./devnet"; -import { ArgentAccount, OpenZeppelinAccount } from "../account"; -import { TransactionReceipt, TransactionTrace } from "../starknet-types"; +import { OpenZeppelinAccount } from "../legacy/account/open-zeppelin-account"; +import { ArgentAccount } from "../legacy/account/argent-account"; +import { TransactionReceipt, TransactionTrace } from "./starknet-types"; export interface Starknet { + devnet: Devnet; + + /** + * The selected starknet-network name. + * Present if the called task relies on `--starknet-network` or `starknet["network"]` in the config object. + */ + network: string; + + /** + * The configuration object of the selected starknet-network. + */ + networkConfig: HardhatNetworkConfig; +} + +export interface StarknetLegacy { /** * Fetches a compiled contract by name. E.g. if the contract is defined in MyContract.cairo, * the provided string should be `MyContract`. @@ -33,19 +50,6 @@ export interface Starknet { */ bigIntToShortString: (convertibleBigInt: bigint) => string; - /** - * The selected starknet-network name. - * Present if the called task relies on `--starknet-network` or `starknet["network"]` in the config object. - */ - network: string; - - /** - * The configuration object of the selected starknet-network. - */ - networkConfig: HardhatNetworkConfig; - - devnet: Devnet; - getTransaction: (txHash: string) => Promise; getTransactionReceipt: (txHash: string) => Promise; @@ -70,7 +74,7 @@ export interface Starknet { * @param options optional arguments to specify the target * @returns the nonce */ - getNonce: (address: string, options?: NonceQueryOptions) => Promise; + getNonce: (address: string, options?: BlockIdentifier) => Promise; /** * Return balance of target contract whose `address` is specified. diff --git a/src/starknet-types.ts b/src/types/starknet-types.ts similarity index 100% rename from src/starknet-types.ts rename to src/types/starknet-types.ts diff --git a/src/utils/check-command-path.ts b/src/utils/check-command-path.ts deleted file mode 100644 index 2a6fc218..00000000 --- a/src/utils/check-command-path.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { StarknetPluginError } from "../starknet-plugin-error"; -import fs from "fs"; - -export function checkCommandPath(commandPath: string): void { - if (!fs.existsSync(commandPath)) { - throw new StarknetPluginError(`Command ${commandPath} not found.`); - } -} diff --git a/src/devnet-utils.ts b/src/utils/devnet-utils.ts similarity index 96% rename from src/devnet-utils.ts rename to src/utils/devnet-utils.ts index a2d97318..57f3b036 100644 --- a/src/devnet-utils.ts +++ b/src/utils/devnet-utils.ts @@ -2,10 +2,10 @@ import axios, { AxiosResponse, Method } from "axios"; import { Devnet, HardhatRuntimeEnvironment } from "hardhat/types"; import { selector } from "starknet"; -import { StarknetPluginError } from "./starknet-plugin-error"; -import { MintResponse, L2ToL1Message } from "./starknet-types"; -import { Numeric } from "./types"; -import { numericToHexString } from "./utils"; +import { StarknetPluginError } from "../starknet-plugin-error"; +import { MintResponse, L2ToL1Message } from "../types/starknet-types"; +import { Numeric } from "../types"; +import { numericToHexString } from "./"; interface L1ToL2Message { address: string; diff --git a/src/utils.ts b/src/utils/index.ts similarity index 95% rename from src/utils.ts rename to src/utils/index.ts index d8406794..9386240d 100644 --- a/src/utils.ts +++ b/src/utils/index.ts @@ -12,7 +12,7 @@ import fs, { promises as fsp } from "node:fs"; import path from "node:path"; import { CompiledSierra, LegacyCompiledContract, hash, json, stark } from "starknet"; -import { handleInternalContractArtifacts } from "./account-utils"; +import { handleInternalContractArtifacts } from "../legacy"; import { ABI_SUFFIX, ALPHA_MAINNET, @@ -28,11 +28,14 @@ import { StarknetChainId, UDC_ADDRESS, CAIRO_CLI_DEFAULT_DOCKER_IMAGE_TAG -} from "./constants"; -import { getContractFactoryUtil } from "./extend-utils"; -import { StarknetPluginError } from "./starknet-plugin-error"; -import { Abi, AbiEntry, CairoFunction } from "./starknet-types"; -import { Cairo1ContractClass, ContractClassConfig, Numeric, StarknetContract } from "./types"; +} from "../constants"; +import { getContractFactoryUtil } from "../legacy/extend-utils"; +import { StarknetPluginError } from "../starknet-plugin-error"; +import { Abi, AbiEntry, CairoFunction } from "../types/starknet-types"; +import { Numeric } from "../types"; +import { ContractClassConfig } from "../legacy/types"; +import { Cairo1ContractClass } from "../legacy"; +import { StarknetContract } from "../legacy"; /** * Replaces Starknet specific terminology with the terminology used in this plugin. diff --git a/src/utils/venv.ts b/src/utils/venv.ts index 02383127..d1e0287d 100644 --- a/src/utils/venv.ts +++ b/src/utils/venv.ts @@ -1,5 +1,7 @@ -import path from "path"; -import { checkCommandPath } from "./check-command-path"; +import fs from "node:fs"; +import path from "node:path"; + +import { StarknetPluginError } from "../starknet-plugin-error"; export function normalizeVenvPath(venvPath: string): string { if (venvPath[0] === "~") { @@ -9,6 +11,12 @@ export function normalizeVenvPath(venvPath: string): string { return path.normalize(venvPath); } +export function checkCommandPath(commandPath: string): void { + if (!fs.existsSync(commandPath)) { + throw new StarknetPluginError(`Command ${commandPath} not found.`); + } +} + export function getPrefixedCommand(venvPath: string, command: string): string { const prefixedCommand = path.join(venvPath, "bin", command); diff --git a/test/general-tests/short-string-test/short-string-test.ts b/test/general-tests/short-string-test/short-string-test.ts index e4863e88..8896386e 100644 --- a/test/general-tests/short-string-test/short-string-test.ts +++ b/test/general-tests/short-string-test/short-string-test.ts @@ -1,5 +1,5 @@ import { expect } from "chai"; -import { starknet } from "hardhat"; +import { starknetLegacy as starknet } from "hardhat"; describe("Starknet", function () { this.timeout(300_000); From d19c8d299239786cc0fbf2814dee9e04662d9fb0 Mon Sep 17 00:00:00 2001 From: Petar Penovic Date: Fri, 10 Nov 2023 12:07:24 +0100 Subject: [PATCH 4/5] Switch to underlying RPC provider --- config.json | 2 +- package-lock.json | 1332 +++++++---------- package.json | 2 +- scripts/devnet-run.sh | 6 +- scripts/set-devnet-vars.sh | 4 +- src/constants.ts | 2 +- src/legacy/account/account-utils.ts | 93 +- src/legacy/account/account.ts | 72 +- src/legacy/account/argent-account.ts | 27 +- src/legacy/account/open-zeppelin-account.ts | 27 +- src/legacy/contract/starknet-contract.ts | 29 +- src/legacy/extend-utils.ts | 20 +- src/legacy/utils/index.ts | 30 +- src/starknet-js-wrapper.ts | 6 +- src/starknet-wrappers.ts | 32 +- src/types/starknet-environment.ts | 10 +- .../account-test/hardhat.config.ts | 2 +- .../contract-test/hardhat.config.ts | 2 +- .../with-active-venv-args/hardhat.config.ts | 2 +- .../with-active-venv/hardhat.config.ts | 2 +- .../with-default/hardhat.config.ts | 2 +- .../hardhat.config.ts | 2 +- .../with-docker-args/hardhat.config.ts | 2 +- .../with-docker-vmlang-rust/hardhat.config.ts | 2 +- .../with-docker-wrong-cli/hardhat.config.ts | 2 +- .../with-docker/hardhat.config.ts | 2 +- .../with-stderr-to-STDERR/hardhat.config.ts | 2 +- .../with-stderr-to-file/hardhat.config.ts | 2 +- .../hardhat.config.ts | 2 +- .../with-venv-wrong-cli/hardhat.config.ts | 2 +- .../with-venv/hardhat.config.ts | 2 +- tsconfig.json | 3 +- 32 files changed, 707 insertions(+), 1020 deletions(-) diff --git a/config.json b/config.json index 92fdc643..3ada9786 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "CAIRO_LANG": "0.11.2", - "STARKNET_DEVNET": "0.6.3", + "STARKNET_DEVNET": "78527decb3f76c4c808fa35f46228557af3df385", "CAIRO_COMPILER": "2.2.0", "SCARB_VERSION": "0.7.0" } diff --git a/package-lock.json b/package-lock.json index efcc4b76..f3c1eabf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "form-data": "^4.0.0", "glob": "^10.0.0", "shelljs": "^0.8.5", - "starknet": "~5.19.3", + "starknet": "~5.24.5", "tar-fs": "^3.0.4" }, "devDependencies": { @@ -42,12 +42,21 @@ "hardhat": "^2.14.0" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@babel/runtime": { - "version": "7.22.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.3.tgz", - "integrity": "sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz", + "integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==", "dependencies": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" @@ -107,23 +116,23 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.1", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -139,9 +148,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", - "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", + "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -869,13 +878,22 @@ "@ethersproject/strings": "^5.7.0" } }, + "node_modules/@fastify/busboy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", + "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" }, @@ -897,9 +915,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, "node_modules/@iarna/toml": { @@ -935,9 +953,9 @@ } }, "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -974,14 +992,14 @@ } }, "node_modules/@messageformat/core": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@messageformat/core/-/core-3.1.0.tgz", - "integrity": "sha512-UxAnjecnRG4u2iaggwIyylYPHmk5BTErJcKmWyAKTXqYgSW1bFLp4D7fIzuh6bk17Qfcmf3qtufdrstCB23nBA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@messageformat/core/-/core-3.3.0.tgz", + "integrity": "sha512-YcXd3remTDdeMxAlbvW6oV9d/01/DZ8DHUFwSttO3LMzIZj3iO0NRw+u1xlsNNORFI+u0EQzD52ZX3+Udi0T3g==", "dev": true, "dependencies": { "@messageformat/date-skeleton": "^1.0.0", "@messageformat/number-skeleton": "^1.0.0", - "@messageformat/parser": "^5.0.0", + "@messageformat/parser": "^5.1.0", "@messageformat/runtime": "^3.0.1", "make-plural": "^7.0.0", "safe-identifier": "^0.4.1" @@ -994,15 +1012,15 @@ "dev": true }, "node_modules/@messageformat/number-skeleton": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@messageformat/number-skeleton/-/number-skeleton-1.1.0.tgz", - "integrity": "sha512-F0Io+GOSvFFxvp9Ze3L5kAoZ2NnOAT0Mr/jpGNd3fqo8A0t4NxNIAcCdggtl2B/gN2ErkIKSBVPrF7xcW1IGvA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@messageformat/number-skeleton/-/number-skeleton-1.2.0.tgz", + "integrity": "sha512-xsgwcL7J7WhlHJ3RNbaVgssaIwcEyFkBqxHdcdaiJzwTZAWEOD8BuUFxnxV9k5S0qHN3v/KzUpq0IUpjH1seRg==", "dev": true }, "node_modules/@messageformat/parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@messageformat/parser/-/parser-5.0.0.tgz", - "integrity": "sha512-WiDKhi8F0zQaFU8cXgqq69eYFarCnTVxKcvhAONufKf0oUxbqLMW6JX6rV4Hqh+BEQWGyKKKHY4g1XA6bCLylA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@messageformat/parser/-/parser-5.1.0.tgz", + "integrity": "sha512-jKlkls3Gewgw6qMjKZ9SFfHUpdzEVdovKFtW1qRhJ3WI4FW5R/NnGDqr8SDGz+krWDO3ki94boMmQvGke1HwUQ==", "dev": true, "dependencies": { "moo": "^0.5.1" @@ -1034,29 +1052,26 @@ } }, "node_modules/@noble/curves": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.0.0.tgz", - "integrity": "sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", "dependencies": { - "@noble/hashes": "1.3.0" + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, "node_modules/@noble/curves/node_modules/@noble/hashes": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz", - "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } }, "node_modules/@noble/hashes": { "version": "1.2.0", @@ -1118,16 +1133,16 @@ } }, "node_modules/@nomicfoundation/ethereumjs-block": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.1.tgz", - "integrity": "sha512-u1Yioemi6Ckj3xspygu/SfFvm8vZEO8/Yx5a1QLzi6nVU0jz3Pg2OmHKJ5w+D9Ogk1vhwRiqEBAqcb0GVhCyHw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.2.tgz", + "integrity": "sha512-hSe6CuHI4SsSiWWjHDIzWhSiAVpzMUcDRpWYzN0T9l8/Rz7xNn3elwVOJ/tAyS0LqL6vitUD78Uk7lQDXZun7Q==", "dev": true, "dependencies": { - "@nomicfoundation/ethereumjs-common": "4.0.1", - "@nomicfoundation/ethereumjs-rlp": "5.0.1", - "@nomicfoundation/ethereumjs-trie": "6.0.1", - "@nomicfoundation/ethereumjs-tx": "5.0.1", - "@nomicfoundation/ethereumjs-util": "9.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", "ethereum-cryptography": "0.1.3", "ethers": "^5.7.1" }, @@ -1159,18 +1174,18 @@ } }, "node_modules/@nomicfoundation/ethereumjs-blockchain": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.1.tgz", - "integrity": "sha512-NhzndlGg829XXbqJEYrF1VeZhAwSPgsK/OB7TVrdzft3y918hW5KNd7gIZ85sn6peDZOdjBsAXIpXZ38oBYE5A==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.2.tgz", + "integrity": "sha512-8UUsSXJs+MFfIIAKdh3cG16iNmWzWC/91P40sazNvrqhhdR/RtGDlFk2iFTGbBAZPs2+klZVzhRX8m2wvuvz3w==", "dev": true, "dependencies": { - "@nomicfoundation/ethereumjs-block": "5.0.1", - "@nomicfoundation/ethereumjs-common": "4.0.1", - "@nomicfoundation/ethereumjs-ethash": "3.0.1", - "@nomicfoundation/ethereumjs-rlp": "5.0.1", - "@nomicfoundation/ethereumjs-trie": "6.0.1", - "@nomicfoundation/ethereumjs-tx": "5.0.1", - "@nomicfoundation/ethereumjs-util": "9.0.1", + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-ethash": "3.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", "abstract-level": "^1.0.3", "debug": "^4.3.3", "ethereum-cryptography": "0.1.3", @@ -1206,24 +1221,24 @@ } }, "node_modules/@nomicfoundation/ethereumjs-common": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz", - "integrity": "sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.2.tgz", + "integrity": "sha512-I2WGP3HMGsOoycSdOTSqIaES0ughQTueOsddJ36aYVpI3SN8YSusgRFLwzDJwRFVIYDKx/iJz0sQ5kBHVgdDwg==", "dev": true, "dependencies": { - "@nomicfoundation/ethereumjs-util": "9.0.1", + "@nomicfoundation/ethereumjs-util": "9.0.2", "crc-32": "^1.2.0" } }, "node_modules/@nomicfoundation/ethereumjs-ethash": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.1.tgz", - "integrity": "sha512-KDjGIB5igzWOp8Ik5I6QiRH5DH+XgILlplsHR7TEuWANZA759G6krQ6o8bvj+tRUz08YygMQu/sGd9mJ1DYT8w==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.2.tgz", + "integrity": "sha512-8PfoOQCcIcO9Pylq0Buijuq/O73tmMVURK0OqdjhwqcGHYC2PwhbajDh7GZ55ekB0Px197ajK3PQhpKoiI/UPg==", "dev": true, "dependencies": { - "@nomicfoundation/ethereumjs-block": "5.0.1", - "@nomicfoundation/ethereumjs-rlp": "5.0.1", - "@nomicfoundation/ethereumjs-util": "9.0.1", + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", "abstract-level": "^1.0.3", "bigint-crypto-utils": "^3.0.23", "ethereum-cryptography": "0.1.3" @@ -1256,15 +1271,15 @@ } }, "node_modules/@nomicfoundation/ethereumjs-evm": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.1.tgz", - "integrity": "sha512-oL8vJcnk0Bx/onl+TgQOQ1t/534GKFaEG17fZmwtPFeH8S5soiBYPCLUrvANOl4sCp9elYxIMzIiTtMtNNN8EQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.2.tgz", + "integrity": "sha512-rBLcUaUfANJxyOx9HIdMX6uXGin6lANCulIm/pjMgRqfiCRMZie3WKYxTSd8ZE/d+qT+zTedBF4+VHTdTSePmQ==", "dev": true, "dependencies": { "@ethersproject/providers": "^5.7.1", - "@nomicfoundation/ethereumjs-common": "4.0.1", - "@nomicfoundation/ethereumjs-tx": "5.0.1", - "@nomicfoundation/ethereumjs-util": "9.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", "debug": "^4.3.3", "ethereum-cryptography": "0.1.3", "mcl-wasm": "^0.7.1", @@ -1298,9 +1313,9 @@ } }, "node_modules/@nomicfoundation/ethereumjs-rlp": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz", - "integrity": "sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.2.tgz", + "integrity": "sha512-QwmemBc+MMsHJ1P1QvPl8R8p2aPvvVcKBbvHnQOKBpBztEo0omN0eaob6FeZS/e3y9NSe+mfu3nNFBHszqkjTA==", "dev": true, "bin": { "rlp": "bin/rlp" @@ -1310,13 +1325,13 @@ } }, "node_modules/@nomicfoundation/ethereumjs-statemanager": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.1.tgz", - "integrity": "sha512-B5ApMOnlruVOR7gisBaYwFX+L/AP7i/2oAahatssjPIBVDF6wTX1K7Qpa39E/nzsH8iYuL3krkYeUFIdO3EMUQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.2.tgz", + "integrity": "sha512-dlKy5dIXLuDubx8Z74sipciZnJTRSV/uHG48RSijhgm1V7eXYFC567xgKtsKiVZB1ViTP9iFL4B6Je0xD6X2OA==", "dev": true, "dependencies": { - "@nomicfoundation/ethereumjs-common": "4.0.1", - "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", "debug": "^4.3.3", "ethereum-cryptography": "0.1.3", "ethers": "^5.7.1", @@ -1347,13 +1362,13 @@ } }, "node_modules/@nomicfoundation/ethereumjs-trie": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.1.tgz", - "integrity": "sha512-A64It/IMpDVODzCgxDgAAla8jNjNtsoQZIzZUfIV5AY6Coi4nvn7+VReBn5itlxMiL2yaTlQr9TRWp3CSI6VoA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.2.tgz", + "integrity": "sha512-yw8vg9hBeLYk4YNg5MrSJ5H55TLOv2FSWUTROtDtTMMmDGROsAu+0tBjiNGTnKRi400M6cEzoFfa89Fc5k8NTQ==", "dev": true, "dependencies": { - "@nomicfoundation/ethereumjs-rlp": "5.0.1", - "@nomicfoundation/ethereumjs-util": "9.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", "@types/readable-stream": "^2.3.13", "ethereum-cryptography": "0.1.3", "readable-stream": "^3.6.0" @@ -1400,16 +1415,16 @@ } }, "node_modules/@nomicfoundation/ethereumjs-tx": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", - "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.2.tgz", + "integrity": "sha512-T+l4/MmTp7VhJeNloMkM+lPU3YMUaXdcXgTGCf8+ZFvV9NYZTRLFekRwlG6/JMmVfIfbrW+dRRJ9A6H5Q/Z64g==", "dev": true, "dependencies": { "@chainsafe/ssz": "^0.9.2", "@ethersproject/providers": "^5.7.2", - "@nomicfoundation/ethereumjs-common": "4.0.1", - "@nomicfoundation/ethereumjs-rlp": "5.0.1", - "@nomicfoundation/ethereumjs-util": "9.0.1", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", "ethereum-cryptography": "0.1.3" }, "engines": { @@ -1440,13 +1455,13 @@ } }, "node_modules/@nomicfoundation/ethereumjs-util": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz", - "integrity": "sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.2.tgz", + "integrity": "sha512-4Wu9D3LykbSBWZo8nJCnzVIYGvGCuyiYLIJa9XXNVt1q1jUzHdB+sJvx95VGCpPkCT+IbLecW6yfzy3E1bQrwQ==", "dev": true, "dependencies": { "@chainsafe/ssz": "^0.10.0", - "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", "ethereum-cryptography": "0.1.3" }, "engines": { @@ -1496,20 +1511,20 @@ } }, "node_modules/@nomicfoundation/ethereumjs-vm": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.1.tgz", - "integrity": "sha512-rArhyn0jPsS/D+ApFsz3yVJMQ29+pVzNZ0VJgkzAZ+7FqXSRtThl1C1prhmlVr3YNUlfpZ69Ak+RUT4g7VoOuQ==", - "dev": true, - "dependencies": { - "@nomicfoundation/ethereumjs-block": "5.0.1", - "@nomicfoundation/ethereumjs-blockchain": "7.0.1", - "@nomicfoundation/ethereumjs-common": "4.0.1", - "@nomicfoundation/ethereumjs-evm": "2.0.1", - "@nomicfoundation/ethereumjs-rlp": "5.0.1", - "@nomicfoundation/ethereumjs-statemanager": "2.0.1", - "@nomicfoundation/ethereumjs-trie": "6.0.1", - "@nomicfoundation/ethereumjs-tx": "5.0.1", - "@nomicfoundation/ethereumjs-util": "9.0.1", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.2.tgz", + "integrity": "sha512-Bj3KZT64j54Tcwr7Qm/0jkeZXJMfdcAtRBedou+Hx0dPOSIgqaIr0vvLwP65TpHbak2DmAq+KJbW2KNtIoFwvA==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-blockchain": "7.0.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-evm": "2.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-statemanager": "2.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", "debug": "^4.3.3", "ethereum-cryptography": "0.1.3", "mcl-wasm": "^0.7.1", @@ -1781,89 +1796,13 @@ "node": ">=4.2.0" } }, - "node_modules/@rometools/cli-darwin-arm64": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/@rometools/cli-darwin-arm64/-/cli-darwin-arm64-12.1.3.tgz", - "integrity": "sha512-AmFTUDYjBuEGQp/Wwps+2cqUr+qhR7gyXAUnkL5psCuNCz3807TrUq/ecOoct5MIavGJTH6R4aaSL6+f+VlBEg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rometools/cli-darwin-x64": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/@rometools/cli-darwin-x64/-/cli-darwin-x64-12.1.3.tgz", - "integrity": "sha512-k8MbWna8q4LRlb005N2X+JS1UQ+s3ZLBBvwk4fP8TBxlAJXUz17jLLu/Fi+7DTTEmMhM84TWj4FDKW+rNar28g==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rometools/cli-linux-arm64": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/@rometools/cli-linux-arm64/-/cli-linux-arm64-12.1.3.tgz", - "integrity": "sha512-X/uLhJ2/FNA3nu5TiyeNPqiD3OZoFfNfRvw6a3ut0jEREPvEn72NI7WPijH/gxSz55znfQ7UQ6iM4DZumUknJg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rometools/cli-linux-x64": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/@rometools/cli-linux-x64/-/cli-linux-x64-12.1.3.tgz", - "integrity": "sha512-csP17q1eWiUXx9z6Jr/JJPibkplyKIwiWPYNzvPCGE8pHlKhwZj3YHRuu7Dm/4EOqx0XFIuqqWZUYm9bkIC8xg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rometools/cli-win32-arm64": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/@rometools/cli-win32-arm64/-/cli-win32-arm64-12.1.3.tgz", - "integrity": "sha512-RymHWeod57EBOJY4P636CgUwYA6BQdkQjh56XKk4pLEHO6X1bFyMet2XL7KlHw5qOTalzuzf5jJqUs+vf3jdXQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rometools/cli-win32-x64": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/@rometools/cli-win32-x64/-/cli-win32-x64-12.1.3.tgz", - "integrity": "sha512-yHSKYidqJMV9nADqg78GYA+cZ0hS1twANAjiFibQdXj9aGzD+s/IzIFEIi/U/OBLvWYg/SCw0QVozi2vTlKFDQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@scure/base": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", - "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.4.tgz", + "integrity": "sha512-wznebWtt+ejH8el87yuD4i9xLSbYZXf1Pe4DY0o/zq/eg5I0VQVXVbFs6XIM0pNVCJ/uE3t5wI9kh90mdLUxtw==", + "funding": { + "url": "https://paulmillr.com/funding/" + } }, "node_modules/@scure/bip32": { "version": "1.1.5", @@ -1898,6 +1837,32 @@ "@scure/base": "~1.1.0" } }, + "node_modules/@scure/starknet": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@scure/starknet/-/starknet-0.3.0.tgz", + "integrity": "sha512-Ma66yZlwa5z00qI5alSxdWtIpky5LBhy22acVFdoC5kwwbd9uDyMWEYzWHdNyKmQg9t5Y2UOXzINMeb3yez+Gw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/curves": "~1.2.0", + "@noble/hashes": "~1.3.2" + } + }, + "node_modules/@scure/starknet/node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@sentry/core": { "version": "5.30.0", "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", @@ -2019,39 +1984,39 @@ "dev": true }, "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true }, "node_modules/@types/bn.js": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", - "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.5.tgz", + "integrity": "sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/chai": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", - "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", + "version": "4.3.11", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", + "integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==", "dev": true }, "node_modules/@types/elliptic": { - "version": "6.4.14", - "resolved": "https://registry.npmjs.org/@types/elliptic/-/elliptic-6.4.14.tgz", - "integrity": "sha512-z4OBcDAU0GVwDTuwJzQCiL6188QvZMkvoERgcVjq0/mPM8jCfdwZ3x5zQEVoL9WCAru3aG5wl3Z5Ww5wBWn7ZQ==", + "version": "6.4.18", + "resolved": "https://registry.npmjs.org/@types/elliptic/-/elliptic-6.4.18.tgz", + "integrity": "sha512-UseG6H5vjRiNpQvrhy4VF/JXdA3V/Fp5amvveaL+fs28BZ6xIKJBPnUPRlEaZpysD9MbpfaLi8lbl7PGUAkpWw==", "dev": true, "dependencies": { "@types/bn.js": "*" } }, "node_modules/@types/eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", - "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", + "version": "8.44.8", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.8.tgz", + "integrity": "sha512-4K8GavROwhrYl2QXDXm0Rv9epkA8GBFu0EI+XrrnnuCl7u8CWBRusX7fXJfanhZTDWSAL24gDI/UqXyUM0Injw==", "dev": true, "dependencies": { "@types/estree": "*", @@ -2059,9 +2024,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "node_modules/@types/glob": { @@ -2075,9 +2040,9 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/lru-cache": { @@ -2093,30 +2058,33 @@ "dev": true }, "node_modules/@types/mocha": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", - "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", + "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", "dev": true }, "node_modules/@types/node": { - "version": "18.16.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz", - "integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q==", - "dev": true + "version": "18.19.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz", + "integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/pbkdf2": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", - "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", "dev": true }, "node_modules/@types/readable-stream": { @@ -2130,24 +2098,24 @@ } }, "node_modules/@types/secp256k1": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz", - "integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.6.tgz", + "integrity": "sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, "node_modules/@types/shelljs": { - "version": "0.8.12", - "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.12.tgz", - "integrity": "sha512-ZA8U81/gldY+rR5zl/7HSHrG2KDfEb3lzG6uCUDhW1DTQE9yC/VBQ45fXnXq8f3CgInfhZmjtdu/WOUlrXRQUg==", + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.15.tgz", + "integrity": "sha512-vzmnCHl6hViPu9GNLQJ+DZFd6BQI2DBTUeOvYHqkWQLMfKAAQYMb/xAmZkTogZI/vqXHCWkqDRymDI5p0QTi5Q==", "dev": true, "dependencies": { "@types/glob": "~7.2.0", @@ -2165,9 +2133,9 @@ } }, "node_modules/@types/tar-fs": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/tar-fs/-/tar-fs-2.0.1.tgz", - "integrity": "sha512-qlsQyIY9sN7p221xHuXKNoMfUenOcvEBN4zI8dGsYbYCqHtTarXOEXSIgUnK+GcR0fZDse6pAIc5pIrCh9NefQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/tar-fs/-/tar-fs-2.0.4.tgz", + "integrity": "sha512-ipPec0CjTmVDWE+QKr9cTmIIoTl7dFG/yARCM5MqK8i6CNLIG1P8x4kwDsOQY1ChZOZjH0wO9nvfgBvWl4R3kA==", "dev": true, "dependencies": { "@types/node": "*", @@ -2175,26 +2143,26 @@ } }, "node_modules/@types/tar-stream": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@types/tar-stream/-/tar-stream-2.2.2.tgz", - "integrity": "sha512-1AX+Yt3icFuU6kxwmPakaiGrJUwG44MpuiqPg4dSolRFk6jmvs4b3IbUol9wKDLIgU76gevn3EwE8y/DkSJCZQ==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/tar-stream/-/tar-stream-3.1.3.tgz", + "integrity": "sha512-Zbnx4wpkWBMBSu5CytMbrT5ZpMiF55qgM+EpHzR4yIDu7mv52cej8hTkOc6K+LzpkOAbxwn/m7j3iO+/l42YkQ==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.2.tgz", - "integrity": "sha512-yVrXupeHjRxLDcPKL10sGQ/QlVrA8J5IYOEWVqk0lJaSZP7X5DfnP7Ns3cc74/blmbipQ1htFNVGsHX6wsYm0A==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.59.2", - "@typescript-eslint/type-utils": "5.59.2", - "@typescript-eslint/utils": "5.59.2", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", "semver": "^7.3.7", @@ -2218,14 +2186,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.2.tgz", - "integrity": "sha512-uq0sKyw6ao1iFOZZGk9F8Nro/8+gfB5ezl1cA06SrqbgJAt0SRoFhb9pXaHvkrxUpZaoLxt8KlovHNk8Gp6/HQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.59.2", - "@typescript-eslint/types": "5.59.2", - "@typescript-eslint/typescript-estree": "5.59.2", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", "debug": "^4.3.4" }, "engines": { @@ -2245,13 +2213,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.2.tgz", - "integrity": "sha512-dB1v7ROySwQWKqQ8rEWcdbTsFjh2G0vn8KUyvTXdPoyzSL6lLGkiXEV5CvpJsEe9xIdKV+8Zqb7wif2issoOFA==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.2", - "@typescript-eslint/visitor-keys": "5.59.2" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2262,13 +2230,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.2.tgz", - "integrity": "sha512-b1LS2phBOsEy/T381bxkkywfQXkV1dWda/z0PhnIy3bC5+rQWQDS7fk9CSpcXBccPY27Z6vBEuaPBCKCgYezyQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.59.2", - "@typescript-eslint/utils": "5.59.2", + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -2289,9 +2257,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.2.tgz", - "integrity": "sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2302,13 +2270,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz", - "integrity": "sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.2", - "@typescript-eslint/visitor-keys": "5.59.2", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2329,17 +2297,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.2.tgz", - "integrity": "sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.2", - "@typescript-eslint/types": "5.59.2", - "@typescript-eslint/typescript-estree": "5.59.2", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", "eslint-scope": "^5.1.1", "semver": "^7.3.7" }, @@ -2355,12 +2323,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.59.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz", - "integrity": "sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.2", + "@typescript-eslint/types": "5.62.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -2371,148 +2339,11 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/abi-wan-kanabi": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/abi-wan-kanabi/-/abi-wan-kanabi-1.0.3.tgz", - "integrity": "sha512-Xwva0AnhXx/IVlzo3/kwkI7Oa7ZX7codtcSn+Gmoa2PmjGPF/0jeVud9puasIPtB7V50+uBdUj4Mh3iATqtBvg==", - "dependencies": { - "abi-wan-kanabi": "^1.0.1", - "fs-extra": "^10.0.0", - "rome": "^12.1.3", - "typescript": "^4.9.5", - "yargs": "^17.7.2" - }, - "bin": { - "generate": "dist/generate.js" - } - }, - "node_modules/abi-wan-kanabi/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/abi-wan-kanabi/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/abi-wan-kanabi/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/abi-wan-kanabi/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/abi-wan-kanabi/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/abi-wan-kanabi/node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/abi-wan-kanabi/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/abi-wan-kanabi/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/abi-wan-kanabi/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/abi-wan-kanabi/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dev": true, - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true }, "node_modules/abstract-level": { "version": "1.0.3", @@ -2533,9 +2364,9 @@ } }, "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -2554,9 +2385,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", + "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", "dev": true, "engines": { "node": ">=0.4.0" @@ -2735,9 +2566,9 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", - "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -2745,9 +2576,9 @@ } }, "node_modules/axios-retry": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.5.0.tgz", - "integrity": "sha512-g48qNrLX30VU6ECWltpFCPegKK6dWzMDYv2o83W2zUL/Zh/SLXbT6ksGoKqYZHtghzqeeXhZBcSXJkO1fPbCcw==", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.9.1.tgz", + "integrity": "sha512-8PJDLJv7qTTMMwdnbMvrLYuvB47M81wRtxQmEdV5w4rgbTXTt+vtPkXwajOfOdSyv/wZICJOC+/UhXH4aQ/R+w==", "dependencies": { "@babel/runtime": "^7.15.4", "is-retry-allowed": "^2.2.0" @@ -2799,9 +2630,9 @@ "dev": true }, "node_modules/bigint-crypto-utils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.2.2.tgz", - "integrity": "sha512-U1RbE3aX9ayCUVcIPHuPDPKcK3SFOXf93J1UK/iHlJuQB7bhagPIX06/CLpLEsDThJ7KA4Dhrnzynl+d2weTiw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.3.0.tgz", + "integrity": "sha512-jOTSb+drvEDxEq6OuUybOAv/xxoh3cuYRUIPyu8sSHQNKM303UQ2R1DAo45o1AkcIXw6fzbaFI1+xGGdaXs2lg==", "dev": true, "engines": { "node": ">=14.0.0" @@ -2976,18 +2807,6 @@ "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", "dev": true }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dev": true, - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -2997,19 +2816,6 @@ "node": ">= 0.8" } }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -3080,18 +2886,18 @@ } }, "node_modules/chai": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", - "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "version": "4.3.10", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", + "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", "dev": true, "dependencies": { "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^4.1.2", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", "pathval": "^1.1.1", - "type-detect": "^4.0.5" + "type-detect": "^4.0.8" }, "engines": { "node": ">=4" @@ -3114,10 +2920,13 @@ } }, "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, "engines": { "node": "*" } @@ -3333,9 +3142,9 @@ } }, "node_modules/core-js": { - "version": "3.30.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.30.1.tgz", - "integrity": "sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ==", + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.34.0.tgz", + "integrity": "sha512-aDdvlDder8QmY91H88GzNi9EtQi2TjvQhpCX6B1v/dAZHU1AuLgHvRh54RiOerpEhEW46Tkf+vgAViB/CWC0ag==", "dev": true, "hasInstallScript": true, "funding": { @@ -3642,12 +3451,13 @@ } }, "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", "dev": true, "dependencies": { - "ansi-colors": "^4.1.1" + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8.6" @@ -3666,6 +3476,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, "engines": { "node": ">=6" } @@ -3683,27 +3494,28 @@ } }, "node_modules/eslint": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", - "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", + "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.39.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.55.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.0", - "espree": "^9.5.1", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -3711,22 +3523,19 @@ "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -3753,9 +3562,9 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3765,9 +3574,9 @@ } }, "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -3790,14 +3599,14 @@ } }, "node_modules/espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -4009,15 +3818,6 @@ "npm": ">=3" } }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", @@ -4051,9 +3851,9 @@ "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -4149,12 +3949,13 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "dependencies": { - "flatted": "^3.1.0", + "flatted": "^3.2.9", + "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { @@ -4162,15 +3963,15 @@ } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", "funding": [ { "type": "individual", @@ -4244,9 +4045,9 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -4257,12 +4058,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, "node_modules/functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", @@ -4273,33 +4068,20 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, "engines": { "node": "*" } }, - "node_modules/get-intrinsic": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", - "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/get-stdin": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", @@ -4313,18 +4095,18 @@ } }, "node_modules/glob": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.2.tgz", - "integrity": "sha512-Xsa0BcxIC6th9UwNjZkhrMtNo/MnyRL8jGCP+uEwhA5oFOCY1f2s1/oNKY47xQ0Bg5nkjsfAEIej1VeH62bDDQ==", + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.0", - "minipass": "^5.0.0", - "path-scurry": "^1.7.0" + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" }, "bin": { - "glob": "dist/cjs/src/bin.js" + "glob": "dist/esm/bin.mjs" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -4354,9 +4136,9 @@ } }, "node_modules/glob/node_modules/minimatch": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", - "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4368,9 +4150,9 @@ } }, "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -4407,35 +4189,34 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "node_modules/hardhat": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.14.0.tgz", - "integrity": "sha512-73jsInY4zZahMSVFurSK+5TNCJTXMv+vemvGia0Ac34Mm19fYp6vEPVGF3sucbumszsYxiTT2TbS8Ii2dsDSoQ==", + "version": "2.19.2", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.19.2.tgz", + "integrity": "sha512-CRU3+0Cc8Qh9UpxKd8cLADDPes7ZDtKj4dTK+ERtLBomEzhRPLWklJn4VKOwjre9/k8GNd/e9DYxpfuzcxbXPQ==", "dev": true, "dependencies": { "@ethersproject/abi": "^5.1.2", "@metamask/eth-sig-util": "^4.0.0", - "@nomicfoundation/ethereumjs-block": "5.0.1", - "@nomicfoundation/ethereumjs-blockchain": "7.0.1", - "@nomicfoundation/ethereumjs-common": "4.0.1", - "@nomicfoundation/ethereumjs-evm": "2.0.1", - "@nomicfoundation/ethereumjs-rlp": "5.0.1", - "@nomicfoundation/ethereumjs-statemanager": "2.0.1", - "@nomicfoundation/ethereumjs-trie": "6.0.1", - "@nomicfoundation/ethereumjs-tx": "5.0.1", - "@nomicfoundation/ethereumjs-util": "9.0.1", - "@nomicfoundation/ethereumjs-vm": "7.0.1", + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-blockchain": "7.0.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-evm": "2.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-statemanager": "2.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "@nomicfoundation/ethereumjs-vm": "7.0.2", "@nomicfoundation/solidity-analyzer": "^0.1.0", "@sentry/node": "^5.18.1", "@types/bn.js": "^5.1.0", "@types/lru-cache": "^5.1.0", - "abort-controller": "^3.0.0", "adm-zip": "^0.4.16", "aggregate-error": "^3.0.0", "ansi-escapes": "^4.3.0", @@ -4458,7 +4239,6 @@ "mnemonist": "^0.38.0", "mocha": "^10.0.0", "p-map": "^4.0.0", - "qs": "^6.7.0", "raw-body": "^2.4.1", "resolve": "1.17.0", "semver": "^6.3.0", @@ -4473,9 +4253,6 @@ "bin": { "hardhat": "internal/cli/bootstrap.js" }, - "engines": { - "node": ">=14.0.0" - }, "peerDependencies": { "ts-node": "*", "typescript": "*" @@ -4627,9 +4404,9 @@ } }, "node_modules/hardhat/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -4647,18 +4424,6 @@ "node": ">=4" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", @@ -4689,18 +4454,6 @@ "node": ">=8" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/hash-base": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", @@ -4841,18 +4594,18 @@ ] }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "dev": true, "engines": { "node": ">= 4" } }, "node_modules/immutable": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", - "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", "dev": true }, "node_modules/import-fresh": { @@ -5064,9 +4817,9 @@ } }, "node_modules/jackspeak": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.0.tgz", - "integrity": "sha512-r5XBrqIJfwRIjRt/Xr5fv9Wh09qyhHfKnYddDlpM+ibRR20qrYActpCAgU6U+d53EOEjzkvxPMVHSlgR7leXrQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -5081,9 +4834,9 @@ } }, "node_modules/js-sdsl": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", - "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.2.tgz", + "integrity": "sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==", "dev": true, "funding": { "type": "opencollective", @@ -5108,6 +4861,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -5152,9 +4911,9 @@ } }, "node_modules/keccak": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.3.tgz", - "integrity": "sha512-JZrLIAJWuZxKbCilMpNz5Vj7Vtb4scDG3dMXLOsbzBmQGyjwE61BbW7bJkfKKCShXiQZt3T6sBgALRtmd+nZaQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", + "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -5180,6 +4939,15 @@ "node": ">= 6" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/klaw": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", @@ -5383,12 +5151,12 @@ "integrity": "sha512-BP0vn+NGYvzDielvBZaFain/wgeJ1hTvURCqtKvhr1SCPePdaaTanmmcplrHfEJSJOUql7hk4FHwToNJjWRY3g==" }, "node_modules/loupe": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", - "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, "dependencies": { - "get-func-name": "^2.0.0" + "get-func-name": "^2.0.1" } }, "node_modules/lru_map": { @@ -5482,32 +5250,6 @@ "node": ">= 8" } }, - "node_modules/micro-starknet": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/micro-starknet/-/micro-starknet-0.2.3.tgz", - "integrity": "sha512-6XBcC+GerlwJSR4iA0VaeXtS2wrayWFcA4PEzrJPMuFmWCaUtuGIq5K/DB5F/XgnL54/zl2Bxo690Lj7mYVA8A==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "@noble/curves": "~1.0.0", - "@noble/hashes": "~1.3.0" - } - }, - "node_modules/micro-starknet/node_modules/@noble/hashes": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", - "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", @@ -5572,11 +5314,11 @@ } }, "node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" } }, "node_modules/mkdirp": { @@ -5784,9 +5526,9 @@ "dev": true }, "node_modules/node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -5803,9 +5545,9 @@ } }, "node_modules/node-gyp-build": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", - "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.7.1.tgz", + "integrity": "sha512-wTSrZ+8lsRRa3I3H8Xr65dLWSgCvY2l4AOnaeKdPA9TB/WYMPaTcrzf3rXvFoVvjKNVnu0CcWSx54qq9GKRUYg==", "dev": true, "bin": { "node-gyp-build": "bin.js", @@ -5822,15 +5564,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/obliterator": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", @@ -5846,17 +5579,17 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -5973,12 +5706,12 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.7.0.tgz", - "integrity": "sha512-UkZUeDjczjYRE495+9thsgcVgsaCPkaw80slmfVFgllxY+IO8ubTsOpFVjDPROBqJdHfVPUFRHPBV/WciOVfWg==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", "dependencies": { - "lru-cache": "^9.0.0", - "minipass": "^5.0.0" + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -5988,9 +5721,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.1.tgz", - "integrity": "sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.1.0.tgz", + "integrity": "sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==", "engines": { "node": "14 || >=16.14" } @@ -6406,29 +6139,14 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" } }, - "node_modules/qs": { - "version": "6.11.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.1.tgz", - "integrity": "sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -6528,14 +6246,15 @@ } }, "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, "engines": { "node": ">=0.10.0" } @@ -6648,26 +6367,6 @@ "rlp": "bin/rlp" } }, - "node_modules/rome": { - "version": "12.1.3", - "resolved": "https://registry.npmjs.org/rome/-/rome-12.1.3.tgz", - "integrity": "sha512-e+ff72hxDpe/t5/Us7YRBVw3PBET7SeczTQNn6tvrWdrCaAw3qOukQQ+tDCkyFtS4yGsnhjrJbm43ctNbz27Yg==", - "hasInstallScript": true, - "bin": { - "rome": "bin/rome" - }, - "engines": { - "node": ">=14.*" - }, - "optionalDependencies": { - "@rometools/cli-darwin-arm64": "12.1.3", - "@rometools/cli-darwin-x64": "12.1.3", - "@rometools/cli-linux-arm64": "12.1.3", - "@rometools/cli-linux-x64": "12.1.3", - "@rometools/cli-win32-arm64": "12.1.3", - "@rometools/cli-win32-x64": "12.1.3" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -6730,9 +6429,9 @@ } }, "node_modules/rxjs/node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, "node_modules/safe-buffer": { @@ -6774,9 +6473,9 @@ } }, "node_modules/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -6900,24 +6599,10 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/signal-exit": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.1.tgz", - "integrity": "sha512-uUWsN4aOxJAS8KOuf3QMyFtgm1pkb6I+KRZbRF/ghdf5T7sM+B1lLLzPDxswUjkmHyxQAVzEgG35E3NzDM9GVw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "engines": { "node": ">=14" }, @@ -7012,9 +6697,9 @@ } }, "node_modules/solc/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "bin": { "semver": "bin/semver" @@ -7066,15 +6751,15 @@ } }, "node_modules/starknet": { - "version": "5.19.3", - "resolved": "https://registry.npmjs.org/starknet/-/starknet-5.19.3.tgz", - "integrity": "sha512-lftyE2mTnkguma3dTnIW2miTjLX25Snu7pBWpOB2LjFr9ja1nfXPITOjAkDHeOFwv1jRXLlGCAxxGbl3lxgbFQ==", + "version": "5.24.5", + "resolved": "https://registry.npmjs.org/starknet/-/starknet-5.24.5.tgz", + "integrity": "sha512-6N9AXNVv33cz0ZJ1YDsnLBdbTnHJ0Eo/wkSWhsUnbBTUK4svy9/8g6fbM/0goAOTCyclf6w1jnrkJ7DECUqZyw==", "dependencies": { - "@noble/curves": "~1.0.0", - "abi-wan-kanabi": "^1.0.3", + "@noble/curves": "~1.2.0", + "@scure/base": "^1.1.3", + "@scure/starknet": "~0.3.0", "isomorphic-fetch": "^3.0.0", "lossless-json": "^2.0.8", - "micro-starknet": "~0.2.1", "pako": "^2.0.4", "url-join": "^4.0.1" } @@ -7088,19 +6773,10 @@ "node": ">= 0.8" } }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/streamx": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.1.tgz", - "integrity": "sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA==", + "version": "2.15.6", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.6.tgz", + "integrity": "sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw==", "dependencies": { "fast-fifo": "^1.1.0", "queue-tick": "^1.0.1" @@ -7161,9 +6837,9 @@ } }, "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -7325,9 +7001,9 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -7454,30 +7130,36 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, "node_modules/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=12.20" + "node": ">=14.17" } }, "node_modules/undici": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.0.tgz", - "integrity": "sha512-fR9RXCc+6Dxav4P9VV/sp5w3eFiSdOjJYsbtWfd4s5L5C4ogyuVpdKIVHeW0vV1MloM65/f7W45nR9ZxwVdyiA==", + "version": "5.28.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.2.tgz", + "integrity": "sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==", "dev": true, "dependencies": { - "busboy": "^1.6.0" + "@fastify/busboy": "^2.0.0" }, "engines": { "node": ">=14.0" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -7554,9 +7236,9 @@ } }, "node_modules/vue-eslint-parser/node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -7584,9 +7266,9 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/whatwg-fetch": { - "version": "3.6.17", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.17.tgz", - "integrity": "sha512-c4ghIvG6th0eudYwKZY5keb81wtFz9/WeAHAoy8+r18kcWlitUIrmGFQ2rWEl4UCKUilD3zCLHOIPheHx5ypRQ==" + "version": "3.6.19", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.19.tgz", + "integrity": "sha512-d67JP4dHSbm2TrpFj8AbO8DnL1JXL5J9u0Kq2xW6d0TFDbCA3Muhdt8orXC22utleTVj7Prqt82baN6RBvnEgw==" }, "node_modules/whatwg-url": { "version": "5.0.0", @@ -7617,15 +7299,6 @@ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "dev": true }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/workerpool": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", @@ -7706,9 +7379,9 @@ } }, "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -7757,6 +7430,7 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, "engines": { "node": ">=10" } diff --git a/package.json b/package.json index 260e4219..0813cd32 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "form-data": "^4.0.0", "glob": "^10.0.0", "shelljs": "^0.8.5", - "starknet": "~5.19.3", + "starknet": "~5.24.5", "tar-fs": "^3.0.4" }, "peerDependencies": { diff --git a/scripts/devnet-run.sh b/scripts/devnet-run.sh index 8d70a750..a481d495 100755 --- a/scripts/devnet-run.sh +++ b/scripts/devnet-run.sh @@ -20,12 +20,12 @@ if [[ -n "${STARKNET_HARDHAT_DEV:-}" ]]; then fi STARKNET_DEVNET="${STARKNET_DEVNET:=$STARKNET_DEVNET_DEFAULT}" - docker pull -q shardlabs/starknet-devnet:$STARKNET_DEVNET - container_id=$(docker run --rm --name starknet_hardhat_devnet -d -p 0.0.0.0:$PORT:$PORT shardlabs/starknet-devnet --seed 42) + docker pull -q shardlabs/starknet-devnet-rs:$STARKNET_DEVNET + container_id=$(docker run --rm --name starknet_hardhat_devnet -d -p 0.0.0.0:$PORT:$PORT shardlabs/starknet-devnet-rs --seed 0) echo "Running devnet in container starknet_hardhat_devnet $container_id" else - starknet-devnet --host $HOST --port $PORT --seed 42 >/dev/null 2>&1 & + starknet-devnet --host $HOST --port $PORT --seed 0 >/dev/null 2>&1 & echo "Spawned devnet with PID $!" fi diff --git a/scripts/set-devnet-vars.sh b/scripts/set-devnet-vars.sh index 902512b3..054bab61 100755 --- a/scripts/set-devnet-vars.sh +++ b/scripts/set-devnet-vars.sh @@ -2,5 +2,5 @@ set -u -export OZ_ACCOUNT_ADDRESS=0x347be35996a21f6bf0623e75dbce52baba918ad5ae8d83b6f416045ab22961a -export OZ_ACCOUNT_PRIVATE_KEY=0xbdd640fb06671ad11c80317fa3b1799d +export OZ_ACCOUNT_ADDRESS=0x64b48806902a367c8598f4f95c305e8c1a1acba5f082d294a43793113115691 +export OZ_ACCOUNT_PRIVATE_KEY=0x71d7bb07b9a64f6f78ac4c816aff4da9 \ No newline at end of file diff --git a/src/constants.ts b/src/constants.ts index 11eb12ab..11649d40 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -15,7 +15,7 @@ export const DEFAULT_STARKNET_ARTIFACTS_PATH = "starknet-artifacts"; export const DEFAULT_STARKNET_ACCOUNT_PATH = "~/.starknet_accounts"; export const CAIRO_CLI_DOCKER_REPOSITORY = "shardlabs/cairo-cli"; export const CAIRO_CLI_DEFAULT_DOCKER_IMAGE_TAG = config["CAIRO_LANG"]; -export const DEVNET_DOCKER_REPOSITORY = "shardlabs/starknet-devnet"; +export const DEVNET_DOCKER_REPOSITORY = "shardlabs/starknet-devnet-rs"; export const DEFAULT_DEVNET_DOCKER_IMAGE_TAG = config["STARKNET_DEVNET"]; export const DEFAULT_DEVNET_CAIRO_VM = "python"; export const AMARNA_DOCKER_REPOSITORY = "shramee/amarna"; diff --git a/src/legacy/account/account-utils.ts b/src/legacy/account/account-utils.ts index c6640d82..258da022 100644 --- a/src/legacy/account/account-utils.ts +++ b/src/legacy/account/account-utils.ts @@ -1,8 +1,8 @@ -import axios, { AxiosError } from "axios"; +import { AxiosError } from "axios"; import { HardhatRuntimeEnvironment, StarknetContract, StringMap } from "hardhat/types"; import fs from "node:fs"; import path from "node:path"; -import { ec, hash, stark } from "starknet"; +import { EstimateFeeResponse, RpcProvider, SierraContractClass, ec, hash, stark } from "starknet"; import { INTERNAL_ARTIFACTS_DIR, @@ -138,17 +138,20 @@ export async function sendDeployAccountTx( maxFee: string ) { const hre = await import("hardhat"); - const resp = await axios - .post(`${hre.starknet.networkConfig.url}/gateway/add_transaction`, { - max_fee: maxFee, - signature: signatures, - nonce: INITIAL_NONCE, - class_hash: classHash, - contract_address_salt: salt, - constructor_calldata: constructorCalldata, - version: numericToHexString(TRANSACTION_VERSION), - type: "DEPLOY_ACCOUNT" - }) + const response = await (hre.starknetProvider as RpcProvider) + .deployAccountContract( + { + classHash, + constructorCalldata, + addressSalt: salt, + signature: signatures + }, + { + maxFee, + nonce: INITIAL_NONCE, + version: numericToHexString(TRANSACTION_VERSION) + } + ) .catch((error: AxiosError) => { const msg = `Deploying account failed: ${error.response.data.message}`; throw new StarknetPluginError(msg, error); @@ -156,9 +159,9 @@ export async function sendDeployAccountTx( return new Promise((resolve, reject) => { iterativelyCheckStatus( - resp.data.transaction_hash, + response.transaction_hash, hre, - () => resolve(resp.data.transaction_hash), + () => resolve(response.transaction_hash), reject ); }); @@ -174,52 +177,40 @@ export async function sendDeclareV2Tx( contractClass: Cairo1ContractClass ) { const hre = await import("hardhat"); - const resp = await axios - .post(`${hre.starknet.networkConfig.url}/gateway/add_transaction`, { - type: "DECLARE", - contract_class: contractClass.getCompiledClass(), - signature: signatures, - sender_address: senderAddress, - compiled_class_hash: compiledClassHash, - version: numericToHexString(version), - nonce: numericToHexString(nonce), - max_fee: numericToHexString(maxFee) - }) - .catch((error: AxiosError) => { - const msg = `Declaring contract failed: ${error.response.data.message}`; + const response = await hre.starknetProvider + .declareContract( + { + compiledClassHash, + senderAddress, + contract: contractClass.getCompiledClass() as SierraContractClass, + signature: signatures + }, + { + maxFee, + nonce, + version + } + ) + .catch((error) => { + const msg = `Declaring contract failed: ${error.message}`; throw new StarknetPluginError(msg, error); }); return new Promise((resolve, reject) => { iterativelyCheckStatus( - resp.data.transaction_hash, + response.transaction_hash, hre, - () => resolve(resp.data.transaction_hash), + () => resolve(response.transaction_hash), reject ); }); } -export async function sendEstimateFeeTx(data: unknown) { - const hre = await import("hardhat"); - // To resolve TypeError: Do not know how to serialize a BigInt - // coming from axios - (BigInt.prototype as any).toJSON = function () { - return this.toString(); - }; - - const resp = await axios - .post(`${hre.starknet.networkConfig.url}/feeder_gateway/estimate_fee`, data) - .catch((error: AxiosError) => { - const msg = `Estimating fees failed: ${error.response.data.message}`; - throw new StarknetPluginError(msg, error); - }); - - const { gas_price, gas_usage, overall_fee, unit } = resp.data; +export function mapToLegacyFee(estimate: EstimateFeeResponse): starknetTypes.FeeEstimation { return { - amount: BigInt(overall_fee), - unit, - gas_price: BigInt(gas_price), - gas_usage: BigInt(gas_usage) - } as starknetTypes.FeeEstimation; + amount: estimate.overall_fee, + unit: "wei", + gas_price: estimate.gas_price, + gas_usage: estimate.gas_consumed + }; } diff --git a/src/legacy/account/account.ts b/src/legacy/account/account.ts index dc0bc63b..295777bf 100644 --- a/src/legacy/account/account.ts +++ b/src/legacy/account/account.ts @@ -1,4 +1,14 @@ -import { constants, ec, hash, selector, BigNumberish, Call, RawCalldata } from "starknet"; +import { + constants, + ec, + hash, + selector, + BigNumberish, + Call, + RawCalldata, + SierraContractClass, + SuccessfulTransactionReceiptResponse +} from "starknet"; import { UDC_DEPLOY_FUNCTION_NAME, @@ -31,7 +41,7 @@ import { DeclareOptions } from "../types"; import { InteractChoice } from "../utils"; -import { sendEstimateFeeTx, CallParameters, sendDeclareV2Tx } from "./account-utils"; +import { CallParameters, mapToLegacyFee, sendDeclareV2Tx } from "./account-utils"; type ExecuteCallParameters = { to: bigint; @@ -121,7 +131,10 @@ export abstract class Account { ); const hre = await import("hardhat"); - const deploymentReceipt = await getTransactionReceiptUtil(deployTxHash, hre); + const deploymentReceipt = (await getTransactionReceiptUtil( + deployTxHash, + hre + )) as SuccessfulTransactionReceiptResponse; const decodedEvents = udc.decodeEvents(deploymentReceipt.events); // the only event should be ContractDeployed const deployedContractAddress = numericToHexString(decodedEvents[0].data.address); @@ -190,18 +203,24 @@ export abstract class Account { compiledClassHash ); const signatures = this.getSignatures(messageHash); + const contract = readCairo1Contract( + contractFactory.metadataPath + ).getCompiledClass() as SierraContractClass; - const data = { - type: "DECLARE", - sender_address: this.address, - compiled_class_hash: compiledClassHash, - contract_class: readCairo1Contract(contractFactory.metadataPath).getCompiledClass(), - signature: bnToDecimalStringArray(signatures || []), - version: numericToHexString(version), - nonce: numericToHexString(nonce) - }; - - return await sendEstimateFeeTx(data); + const estimate = await hre.starknetProvider.getDeclareEstimateFee( + { + compiledClassHash, + contract, + senderAddress: this.address, + signature: bnToDecimalStringArray(signatures || []) + }, + { + maxFee, + nonce, + version: numericToHexString(QUERY_VERSION) + } + ); + return mapToLegacyFee(estimate); } async estimateDeclareFee( @@ -232,17 +251,22 @@ export abstract class Account { chainId, numericToHexString(nonce) ]); - const signature = this.getSignatures(messageHash); - const data = { - type: "DECLARE", - sender_address: this.address, - contract_class: readContract(contractFactory.metadataPath), - signature: bnToDecimalStringArray(signature || []), - version: numericToHexString(QUERY_VERSION), - nonce: numericToHexString(nonce) - }; - return await sendEstimateFeeTx(data); + const contract = readContract(contractFactory.metadataPath); + + const estimate = await hre.starknetProvider.getDeclareEstimateFee( + { + contract, + senderAddress: this.address, + signature: bnToDecimalStringArray(signature || []) + }, + { + maxFee, + nonce, + version: numericToHexString(QUERY_VERSION) + } + ); + return mapToLegacyFee(estimate); } async estimateDeployFee( diff --git a/src/legacy/account/argent-account.ts b/src/legacy/account/argent-account.ts index 689dea99..87c1fd23 100644 --- a/src/legacy/account/argent-account.ts +++ b/src/legacy/account/argent-account.ts @@ -15,8 +15,8 @@ import { CallParameters, generateKeys, handleInternalContractArtifacts, + mapToLegacyFee, sendDeployAccountTx, - sendEstimateFeeTx, signMultiCall } from "./account-utils"; import { Account } from "./account"; @@ -203,19 +203,22 @@ export class ArgentAccount extends Account { hre.starknet.networkConfig.starknetChainId, nonce ]); - const signature = this.getSignatures(msgHash); - const data = { - type: "DEPLOY_ACCOUNT", - class_hash: ArgentAccount.PROXY_CLASS_HASH, - constructor_calldata: constructorCalldata, - contract_address_salt: this.salt, - signature: bnToDecimalStringArray(signature || []), - version: numericToHexString(QUERY_VERSION), - nonce - }; - return await sendEstimateFeeTx(data); + const estimate = await hre.starknetProvider.getDeployAccountEstimateFee( + { + classHash: ArgentAccount.PROXY_CLASS_HASH, + constructorCalldata, + addressSalt: this.salt, + signature: bnToDecimalStringArray(signature || []) + }, + { + maxFee, + nonce, + version: numericToHexString(QUERY_VERSION) + } + ); + return mapToLegacyFee(estimate); } /** diff --git a/src/legacy/account/open-zeppelin-account.ts b/src/legacy/account/open-zeppelin-account.ts index 082c8279..e6117f32 100644 --- a/src/legacy/account/open-zeppelin-account.ts +++ b/src/legacy/account/open-zeppelin-account.ts @@ -14,8 +14,8 @@ import { calculateDeployAccountHash, generateKeys, handleInternalContractArtifacts, + mapToLegacyFee, sendDeployAccountTx, - sendEstimateFeeTx, signMultiCall } from "./account-utils"; import { Account } from "./account"; @@ -141,19 +141,22 @@ export class OpenZeppelinAccount extends Account { hre.starknet.networkConfig.starknetChainId, nonce ]); - const signature = this.getSignatures(msgHash); - const data = { - type: "DEPLOY_ACCOUNT", - class_hash: classHash, - constructor_calldata: constructorCalldata, - contract_address_salt: this.salt, - signature: bnToDecimalStringArray(signature || []), - version: numericToHexString(QUERY_VERSION), - nonce - }; - return await sendEstimateFeeTx(data); + const estimate = await hre.starknetProvider.getDeployAccountEstimateFee( + { + classHash, + constructorCalldata, + addressSalt: this.salt, + signature: bnToDecimalStringArray(signature || []) + }, + { + maxFee, + nonce, + version: numericToHexString(QUERY_VERSION) + } + ); + return mapToLegacyFee(estimate); } public override async deployAccount(options: DeployAccountOptions = {}): Promise { diff --git a/src/legacy/contract/starknet-contract.ts b/src/legacy/contract/starknet-contract.ts index 718d5071..737ba43f 100644 --- a/src/legacy/contract/starknet-contract.ts +++ b/src/legacy/contract/starknet-contract.ts @@ -1,5 +1,12 @@ import { HardhatRuntimeEnvironment } from "hardhat/types"; -import { CallData, ProviderInterface, events as eventUtil, json } from "starknet"; +import { + CallData, + ProviderInterface, + RpcProvider, + events as eventUtil, + json, + selector +} from "starknet"; import { StarknetPluginError } from "../../starknet-plugin-error"; import { @@ -204,12 +211,20 @@ export class StarknetContract { const adaptedInput = this.adaptInput(functionName, args); // Remove value of from_address from the input array const fromAddress = adaptedInput.shift(); - return this.hre.starknetWrapper.estimateMessageFee( - functionName, - fromAddress, - this.address, - adaptedInput - ); + + const estimate = await (this.provider as RpcProvider).estimateMessageFee({ + from_address: fromAddress, + to_address: this.address, + entry_point_selector: selector.getSelectorFromName(functionName), + payload: adaptedInput + }); + + return { + amount: estimate.overall_fee, + unit: "wei", + gas_price: estimate.gas_price, + gas_usage: estimate.gas_consumed + }; } /** diff --git a/src/legacy/extend-utils.ts b/src/legacy/extend-utils.ts index d2a82c85..0823d95c 100644 --- a/src/legacy/extend-utils.ts +++ b/src/legacy/extend-utils.ts @@ -1,6 +1,6 @@ -import { Block, HardhatRuntimeEnvironment, Transaction } from "hardhat/types"; +import { Block, HardhatRuntimeEnvironment } from "hardhat/types"; import path from "node:path"; -import { SequencerProvider, uint256 } from "starknet"; +import { GetTransactionReceiptResponse, RPC, RpcProvider, uint256 } from "starknet"; import { handleInternalContractArtifacts } from "./account"; import { @@ -11,7 +11,7 @@ import { } from "../constants"; import { StarknetContractFactory } from "./contract"; import { StarknetPluginError } from "../starknet-plugin-error"; -import { BlockIdentifier, starknetTypes } from "../types"; +import { BlockIdentifier } from "../types"; import { checkArtifactExists, findPath } from "../utils"; export async function getContractFactoryUtil(hre: HardhatRuntimeEnvironment, contractPath: string) { @@ -89,10 +89,10 @@ export function bigIntToShortStringUtil(convertibleBigInt: bigint) { export async function getTransactionUtil( txHash: string, hre: HardhatRuntimeEnvironment -): Promise { +): Promise { try { const transaction = await hre.starknetProvider.getTransaction(txHash); - return transaction as Transaction; + return transaction as RPC.TransactionWithHash; } catch (error) { const msg = `Could not get the transaction. ${error}`; throw new StarknetPluginError(msg); @@ -102,10 +102,10 @@ export async function getTransactionUtil( export async function getTransactionReceiptUtil( txHash: string, hre: HardhatRuntimeEnvironment -): Promise { +): Promise { try { const receipt = await hre.starknetProvider.getTransactionReceipt(txHash); - return receipt as unknown as starknetTypes.TransactionReceipt; + return receipt; } catch (error) { const msg = `Could not get the transaction receipt. Error: ${error}`; throw new StarknetPluginError(msg); @@ -115,10 +115,10 @@ export async function getTransactionReceiptUtil( export async function getTransactionTraceUtil( txHash: string, hre: HardhatRuntimeEnvironment -): Promise { +): Promise { try { - const trace = await (hre.starknetProvider as SequencerProvider).getTransactionTrace(txHash); - return trace as starknetTypes.TransactionTrace; + const trace = await (hre.starknetProvider as RpcProvider).getTransactionTrace(txHash); + return trace; } catch (error) { const msg = `Could not get the transaction trace. Error: ${error}`; throw new StarknetPluginError(msg); diff --git a/src/legacy/utils/index.ts b/src/legacy/utils/index.ts index 4679c7fd..793a56bd 100644 --- a/src/legacy/utils/index.ts +++ b/src/legacy/utils/index.ts @@ -1,5 +1,5 @@ import { HardhatRuntimeEnvironment } from "hardhat/types"; -import { SequencerProvider } from "starknet"; +import { RPC, RpcProvider } from "starknet"; import { CHECK_STATUS_RECOVER_TIMEOUT, @@ -8,21 +8,27 @@ import { TRANSACTION_VERSION } from "../../constants"; import { StarknetPluginError } from "../../starknet-plugin-error"; -import { Numeric, StatusObject, TxStatus, starknetTypes } from "../../types"; +import { Numeric, starknetTypes } from "../../types"; import { adaptLog, sleep, warn } from "../../utils"; import { StarknetContract } from "../contract"; export * from "./abi"; export * from "./adapt"; -const ACCEPTABLE_STATUSES: TxStatus[] = ["PENDING", "ACCEPTED_ON_L2", "ACCEPTED_ON_L1"]; -export function isTxAccepted(statusObject: StatusObject): boolean { - return ACCEPTABLE_STATUSES.includes(statusObject.tx_status); +const ACCEPTABLE_STATUSES = ["SUCCEEDED", "ACCEPTED_ON_L2", "ACCEPTED_ON_L1"]; +export function isTxAccepted(statusObject: RPC.TransactionStatus): boolean { + return ( + ACCEPTABLE_STATUSES.includes(statusObject.execution_status) || + ACCEPTABLE_STATUSES.includes(statusObject.finality_status) + ); } -const UNACCEPTABLE_STATUSES: TxStatus[] = ["REJECTED", "REVERTED"]; -export function isTxRejected(statusObject: StatusObject): boolean { - return UNACCEPTABLE_STATUSES.includes(statusObject.tx_status); +const UNACCEPTABLE_STATUSES = ["REJECTED", "REVERTED"]; +export function isTxRejected(statusObject: RPC.TransactionStatus): boolean { + return ( + UNACCEPTABLE_STATUSES.includes(statusObject.execution_status) || + UNACCEPTABLE_STATUSES.includes(statusObject.finality_status) + ); } export async function iterativelyCheckStatus( @@ -35,11 +41,11 @@ export async function iterativelyCheckStatus( // eslint-disable-next-line no-constant-condition while (true) { let count = retryCount; - let statusObject: StatusObject; + let statusObject: RPC.TransactionStatus; let error; while (count > 0) { // This promise is rejected usually if the network is unavailable - statusObject = await (hre.starknetProvider as SequencerProvider) + statusObject = await (hre.starknetProvider as RpcProvider) .getTransactionStatus(txHash) .catch((err) => { error = new StarknetPluginError(err); @@ -59,11 +65,11 @@ export async function iterativelyCheckStatus( if (!statusObject) { warn("Checking transaction status failed."); return reject(error); - } else if (isTxAccepted(statusObject)) { - return resolve(statusObject.tx_status); } else if (isTxRejected(statusObject)) { const adaptedError = adaptLog(JSON.stringify(statusObject, null, 4)); return reject(new Error(adaptedError)); + } else if (isTxAccepted(statusObject)) { + return resolve(statusObject.execution_status ?? statusObject.finality_status); } await sleep(CHECK_STATUS_TIMEOUT); diff --git a/src/starknet-js-wrapper.ts b/src/starknet-js-wrapper.ts index eabde53d..64b7b8d4 100644 --- a/src/starknet-js-wrapper.ts +++ b/src/starknet-js-wrapper.ts @@ -1,5 +1,5 @@ import { HardhatRuntimeEnvironment } from "hardhat/types"; -import { ProviderInterface, SequencerProvider } from "starknet"; +import { ProviderInterface, RpcProvider } from "starknet"; export class StarknetJsWrapper { public provider: ProviderInterface; @@ -12,8 +12,8 @@ export class StarknetJsWrapper { } public setProvider() { - this.provider = new SequencerProvider({ - baseUrl: this.hre.config.starknet.networkConfig.url + this.provider = new RpcProvider({ + nodeUrl: this.hre.config.starknet.networkConfig.url }); this.hre.starknetProvider = this.provider; } diff --git a/src/starknet-wrappers.ts b/src/starknet-wrappers.ts index 7b0db37a..eb828904 100644 --- a/src/starknet-wrappers.ts +++ b/src/starknet-wrappers.ts @@ -1,8 +1,6 @@ import { Image, ProcessResult } from "@nomiclabs/hardhat-docker"; -import axios from "axios"; import { HardhatRuntimeEnvironment } from "hardhat/types"; -import path from "path"; -import { num, selector } from "starknet"; +import path from "node:path"; import { exec } from "./cairo1-compiler"; import { @@ -14,7 +12,6 @@ import { import { ExternalServer } from "./external-server"; import { StarknetDockerProxy } from "./starknet-docker-proxy"; import { StarknetPluginError } from "./starknet-plugin-error"; -import { FeeEstimation } from "./types/starknet-types"; import { StarknetVenvProxy } from "./starknet-venv-proxy"; import { getPrefixedCommand, normalizeVenvPath } from "./utils/venv"; @@ -212,33 +209,6 @@ export abstract class StarknetWrapper { } return executed.stdout.toString().trim(); } - - public async estimateMessageFee( - functionName: string, - fromAddress: string, - toAddress: string, - inputs: string[] - ): Promise { - const body = { - from_address: fromAddress, - to_address: toAddress, - entry_point_selector: selector.getSelectorFromName(functionName), - payload: inputs.map((item) => num.toHex(BigInt(item))) - }; - - const response = await axios.post( - `${this.hre.starknet.networkConfig.url}/feeder_gateway/estimate_message_fee`, - body - ); - - const { gas_price, gas_usage, overall_fee, unit } = response.data; - return { - amount: BigInt(overall_fee), - unit, - gas_price: BigInt(gas_price), - gas_usage: BigInt(gas_usage) - }; - } } function getFullImageName(image: Image): string { diff --git a/src/types/starknet-environment.ts b/src/types/starknet-environment.ts index b64e57f4..92540727 100644 --- a/src/types/starknet-environment.ts +++ b/src/types/starknet-environment.ts @@ -1,11 +1,11 @@ -import { Block, HardhatNetworkConfig, NetworkConfig, Transaction } from "hardhat/types"; +import { Block, HardhatNetworkConfig, NetworkConfig } from "hardhat/types"; +import { GetTransactionReceiptResponse, RPC } from "starknet"; import { BlockIdentifier } from "."; import { StarknetContractFactory } from "../legacy/contract/starknet-contract-factory"; import { Devnet } from "./devnet"; import { OpenZeppelinAccount } from "../legacy/account/open-zeppelin-account"; import { ArgentAccount } from "../legacy/account/argent-account"; -import { TransactionReceipt, TransactionTrace } from "./starknet-types"; export interface Starknet { devnet: Devnet; @@ -50,16 +50,16 @@ export interface StarknetLegacy { */ bigIntToShortString: (convertibleBigInt: bigint) => string; - getTransaction: (txHash: string) => Promise; + getTransaction: (txHash: string) => Promise; - getTransactionReceipt: (txHash: string) => Promise; + getTransactionReceipt: (txHash: string) => Promise; /** * Returns execution information in a nested structure of calls. * @param txHash the transaction hash * @returns the transaction trace */ - getTransactionTrace: (txHash: string) => Promise; + getTransactionTrace: (txHash: string) => Promise; /** * Returns an entire block and the transactions contained within it. diff --git a/test/general-tests/account-test/hardhat.config.ts b/test/general-tests/account-test/hardhat.config.ts index 7bf00e0f..24da13e7 100644 --- a/test/general-tests/account-test/hardhat.config.ts +++ b/test/general-tests/account-test/hardhat.config.ts @@ -12,7 +12,7 @@ module.exports = { // args: ["--seed", "42", "--fork-network", "alpha-goerli"] // _TODO: forking is currently not supported because testnet is at cairo-lang v0.12.2 - args: ["--seed", "42"] + args: ["--seed", "0"] } } }; diff --git a/test/general-tests/contract-test/hardhat.config.ts b/test/general-tests/contract-test/hardhat.config.ts index 9e3b0e14..3d6bc1ac 100644 --- a/test/general-tests/contract-test/hardhat.config.ts +++ b/test/general-tests/contract-test/hardhat.config.ts @@ -7,7 +7,7 @@ module.exports = { networks: { integratedDevnet: { url: "http://127.0.0.1:5050", - args: ["--seed", "42"] + args: ["--seed", "0"] } } }; diff --git a/test/integrated-devnet-tests/with-active-venv-args/hardhat.config.ts b/test/integrated-devnet-tests/with-active-venv-args/hardhat.config.ts index 16e8435d..0b6bbd92 100644 --- a/test/integrated-devnet-tests/with-active-venv-args/hardhat.config.ts +++ b/test/integrated-devnet-tests/with-active-venv-args/hardhat.config.ts @@ -8,7 +8,7 @@ module.exports = { integratedDevnet: { venv: "active", url: "http://127.0.0.1:5050", - args: ["--lite-mode", "--gas-price", process.env.EXPECTED_GAS_PRICE, "--seed", "42"] + args: ["--lite-mode", "--gas-price", process.env.EXPECTED_GAS_PRICE, "--seed", "0"] } } }; diff --git a/test/integrated-devnet-tests/with-active-venv/hardhat.config.ts b/test/integrated-devnet-tests/with-active-venv/hardhat.config.ts index 2613a33e..72755e47 100644 --- a/test/integrated-devnet-tests/with-active-venv/hardhat.config.ts +++ b/test/integrated-devnet-tests/with-active-venv/hardhat.config.ts @@ -8,7 +8,7 @@ module.exports = { integratedDevnet: { venv: "active", url: "http://127.0.0.1:5050", - args: ["--seed", "42"] + args: ["--seed", "0"] } } }; diff --git a/test/integrated-devnet-tests/with-default/hardhat.config.ts b/test/integrated-devnet-tests/with-default/hardhat.config.ts index a444af44..240af8c9 100644 --- a/test/integrated-devnet-tests/with-default/hardhat.config.ts +++ b/test/integrated-devnet-tests/with-default/hardhat.config.ts @@ -9,7 +9,7 @@ module.exports = { // using the default runner // neither venv nor dockerized version is specified url: "http://127.0.0.1:5050", - args: ["--seed", "42"] + args: ["--seed", "0"] } } }; diff --git a/test/integrated-devnet-tests/with-docker-address-occupied/hardhat.config.ts b/test/integrated-devnet-tests/with-docker-address-occupied/hardhat.config.ts index 6a02e085..7d4b0c71 100644 --- a/test/integrated-devnet-tests/with-docker-address-occupied/hardhat.config.ts +++ b/test/integrated-devnet-tests/with-docker-address-occupied/hardhat.config.ts @@ -8,7 +8,7 @@ module.exports = { integratedDevnet: { dockerizedVersion: process.env.STARKNET_DEVNET, url: "http://127.0.0.1:5050", - args: ["--seed", "42"] + args: ["--seed", "0"] } } }; diff --git a/test/integrated-devnet-tests/with-docker-args/hardhat.config.ts b/test/integrated-devnet-tests/with-docker-args/hardhat.config.ts index 26de82f1..576dad53 100644 --- a/test/integrated-devnet-tests/with-docker-args/hardhat.config.ts +++ b/test/integrated-devnet-tests/with-docker-args/hardhat.config.ts @@ -8,7 +8,7 @@ module.exports = { integratedDevnet: { dockerizedVersion: process.env.STARKNET_DEVNET, url: "http://127.0.0.1:5050", - args: ["--lite-mode", "--gas-price", process.env.EXPECTED_GAS_PRICE, "--seed", "42"] + args: ["--lite-mode", "--gas-price", process.env.EXPECTED_GAS_PRICE, "--seed", "0"] } } }; diff --git a/test/integrated-devnet-tests/with-docker-vmlang-rust/hardhat.config.ts b/test/integrated-devnet-tests/with-docker-vmlang-rust/hardhat.config.ts index 94b7a8c8..ebb52f41 100644 --- a/test/integrated-devnet-tests/with-docker-vmlang-rust/hardhat.config.ts +++ b/test/integrated-devnet-tests/with-docker-vmlang-rust/hardhat.config.ts @@ -9,7 +9,7 @@ module.exports = { dockerizedVersion: process.env.STARKNET_DEVNET, vmLang: "rust", url: "http://127.0.0.1:5050", - args: ["--seed", "42"], + args: ["--seed", "0"], stderr: "STDERR" } } diff --git a/test/integrated-devnet-tests/with-docker-wrong-cli/hardhat.config.ts b/test/integrated-devnet-tests/with-docker-wrong-cli/hardhat.config.ts index e23a3ac6..89a089e4 100644 --- a/test/integrated-devnet-tests/with-docker-wrong-cli/hardhat.config.ts +++ b/test/integrated-devnet-tests/with-docker-wrong-cli/hardhat.config.ts @@ -8,7 +8,7 @@ module.exports = { integratedDevnet: { dockerizedVersion: process.env.STARKNET_DEVNET, url: "http://127.0.0.1:5050", - args: ["--accounts", "invalid_value", "--seed", "42"] + args: ["--accounts", "invalid_value", "--seed", "0"] } } }; diff --git a/test/integrated-devnet-tests/with-docker/hardhat.config.ts b/test/integrated-devnet-tests/with-docker/hardhat.config.ts index 6a02e085..7d4b0c71 100644 --- a/test/integrated-devnet-tests/with-docker/hardhat.config.ts +++ b/test/integrated-devnet-tests/with-docker/hardhat.config.ts @@ -8,7 +8,7 @@ module.exports = { integratedDevnet: { dockerizedVersion: process.env.STARKNET_DEVNET, url: "http://127.0.0.1:5050", - args: ["--seed", "42"] + args: ["--seed", "0"] } } }; diff --git a/test/integrated-devnet-tests/with-stderr-to-STDERR/hardhat.config.ts b/test/integrated-devnet-tests/with-stderr-to-STDERR/hardhat.config.ts index d1289ba2..2bdf741b 100644 --- a/test/integrated-devnet-tests/with-stderr-to-STDERR/hardhat.config.ts +++ b/test/integrated-devnet-tests/with-stderr-to-STDERR/hardhat.config.ts @@ -10,7 +10,7 @@ module.exports = { url: "http://127.0.0.1:5050", stdout: "logs/stdout.log", stderr: "STDERR", - args: ["--seed", "42"] + args: ["--seed", "0"] } } }; diff --git a/test/integrated-devnet-tests/with-stderr-to-file/hardhat.config.ts b/test/integrated-devnet-tests/with-stderr-to-file/hardhat.config.ts index 05f24142..9701205f 100644 --- a/test/integrated-devnet-tests/with-stderr-to-file/hardhat.config.ts +++ b/test/integrated-devnet-tests/with-stderr-to-file/hardhat.config.ts @@ -10,7 +10,7 @@ module.exports = { url: "http://127.0.0.1:5050", stdout: "STDOUT", stderr: "logs/stderr.log", - args: ["--seed", "42"] + args: ["--seed", "0"] } } }; diff --git a/test/integrated-devnet-tests/with-venv-address-occupied/hardhat.config.ts b/test/integrated-devnet-tests/with-venv-address-occupied/hardhat.config.ts index 0302af8d..bee47553 100644 --- a/test/integrated-devnet-tests/with-venv-address-occupied/hardhat.config.ts +++ b/test/integrated-devnet-tests/with-venv-address-occupied/hardhat.config.ts @@ -8,7 +8,7 @@ module.exports = { integratedDevnet: { venv: process.env.STARKNET_DEVNET_PATH, url: "http://127.0.0.1:5050", - args: ["--seed", "42"] + args: ["--seed", "0"] } } }; diff --git a/test/integrated-devnet-tests/with-venv-wrong-cli/hardhat.config.ts b/test/integrated-devnet-tests/with-venv-wrong-cli/hardhat.config.ts index 6472047c..f2a5a390 100644 --- a/test/integrated-devnet-tests/with-venv-wrong-cli/hardhat.config.ts +++ b/test/integrated-devnet-tests/with-venv-wrong-cli/hardhat.config.ts @@ -8,7 +8,7 @@ module.exports = { integratedDevnet: { venv: process.env.STARKNET_DEVNET_PATH, url: "http://127.0.0.1:5050", - args: ["--accounts", "invalid_value", "--seed", "42"] + args: ["--accounts", "invalid_value", "--seed", "0"] } } }; diff --git a/test/integrated-devnet-tests/with-venv/hardhat.config.ts b/test/integrated-devnet-tests/with-venv/hardhat.config.ts index 0302af8d..bee47553 100644 --- a/test/integrated-devnet-tests/with-venv/hardhat.config.ts +++ b/test/integrated-devnet-tests/with-venv/hardhat.config.ts @@ -8,7 +8,7 @@ module.exports = { integratedDevnet: { venv: process.env.STARKNET_DEVNET_PATH, url: "http://127.0.0.1:5050", - args: ["--seed", "42"] + args: ["--seed", "0"] } } }; diff --git a/tsconfig.json b/tsconfig.json index 96dc0776..e5d9c36c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,8 @@ "declaration": true, "module": "commonjs", "noImplicitOverride": true, - "typeRoots": ["./node_modules/@types"] + "typeRoots": ["./node_modules/@types"], + "skipLibCheck": true }, "include": ["./src", "config.json", "contract-artifacts/**/*.json"] } From f5a731703c5b1442e596233966aed84a6c209c36 Mon Sep 17 00:00:00 2001 From: Petar Penovic Date: Tue, 28 Nov 2023 07:43:52 +0100 Subject: [PATCH 5/5] temp: example repo [skip ci] --- scripts/test-setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test-setup.sh b/scripts/test-setup.sh index dc6b0770..2a1244b7 100755 --- a/scripts/test-setup.sh +++ b/scripts/test-setup.sh @@ -12,7 +12,7 @@ trap 'for killable in $(jobs -p); do kill -9 $killable; done' EXIT # setup example repo rm -rf starknet-hardhat-example -EXAMPLE_REPO_BRANCH="plugin" +EXAMPLE_REPO_BRANCH="stjs" if [[ "$CIRCLE_BRANCH" == "master" ]] && [[ "$EXAMPLE_REPO_BRANCH" != "plugin" ]]; then # prevents using starknet-hardhat-example branch other than "plugin" when starknet-hardhat-plugin PRs are merged echo "Invalid example repo branch: $EXAMPLE_REPO_BRANCH"