diff --git a/.changeset/sharp-bugs-dance.md b/.changeset/sharp-bugs-dance.md new file mode 100644 index 00000000000..65cf175a16a --- /dev/null +++ b/.changeset/sharp-bugs-dance.md @@ -0,0 +1,5 @@ +--- +"thirdweb": patch +--- + +Support Stylus contracts in CLI and SDK diff --git a/packages/thirdweb/package.json b/packages/thirdweb/package.json index 6dc2aaec662..527ed302f47 100644 --- a/packages/thirdweb/package.json +++ b/packages/thirdweb/package.json @@ -137,66 +137,26 @@ }, "typesVersions": { "*": { - "adapters/*": [ - "./dist/types/exports/adapters/*.d.ts" - ], - "auth": [ - "./dist/types/exports/auth.d.ts" - ], - "chains": [ - "./dist/types/exports/chains.d.ts" - ], - "contract": [ - "./dist/types/exports/contract.d.ts" - ], - "deploys": [ - "./dist/types/exports/deploys.d.ts" - ], - "event": [ - "./dist/types/exports/event.d.ts" - ], - "extensions/*": [ - "./dist/types/exports/extensions/*.d.ts" - ], - "pay": [ - "./dist/types/exports/pay.d.ts" - ], - "react": [ - "./dist/types/exports/react.d.ts" - ], - "react-native": [ - "./dist/types/exports/react-native.d.ts" - ], - "rpc": [ - "./dist/types/exports/rpc.d.ts" - ], - "storage": [ - "./dist/types/exports/storage.d.ts" - ], - "transaction": [ - "./dist/types/exports/transaction.d.ts" - ], - "utils": [ - "./dist/types/exports/utils.d.ts" - ], - "wallets": [ - "./dist/types/exports/wallets.d.ts" - ], - "wallets/*": [ - "./dist/types/exports/wallets/*.d.ts" - ], - "modules": [ - "./dist/types/exports/modules.d.ts" - ], - "social": [ - "./dist/types/exports/social.d.ts" - ], - "ai": [ - "./dist/types/exports/ai.d.ts" - ], - "bridge": [ - "./dist/types/exports/bridge.d.ts" - ] + "adapters/*": ["./dist/types/exports/adapters/*.d.ts"], + "auth": ["./dist/types/exports/auth.d.ts"], + "chains": ["./dist/types/exports/chains.d.ts"], + "contract": ["./dist/types/exports/contract.d.ts"], + "deploys": ["./dist/types/exports/deploys.d.ts"], + "event": ["./dist/types/exports/event.d.ts"], + "extensions/*": ["./dist/types/exports/extensions/*.d.ts"], + "pay": ["./dist/types/exports/pay.d.ts"], + "react": ["./dist/types/exports/react.d.ts"], + "react-native": ["./dist/types/exports/react-native.d.ts"], + "rpc": ["./dist/types/exports/rpc.d.ts"], + "storage": ["./dist/types/exports/storage.d.ts"], + "transaction": ["./dist/types/exports/transaction.d.ts"], + "utils": ["./dist/types/exports/utils.d.ts"], + "wallets": ["./dist/types/exports/wallets.d.ts"], + "wallets/*": ["./dist/types/exports/wallets/*.d.ts"], + "modules": ["./dist/types/exports/modules.d.ts"], + "social": ["./dist/types/exports/social.d.ts"], + "ai": ["./dist/types/exports/ai.d.ts"], + "bridge": ["./dist/types/exports/bridge.d.ts"] } }, "browser": { @@ -233,7 +193,11 @@ "fuse.js": "7.1.0", "input-otp": "^1.4.1", "mipd": "0.0.7", + "open": "10.1.0", + "ora": "8.2.0", "ox": "0.6.10", + "prompts": "2.4.2", + "toml": "3.0.0", "uqr": "0.1.2", "viem": "2.23.10" }, @@ -358,6 +322,7 @@ "@testing-library/react": "^16.2.0", "@testing-library/user-event": "^14.6.1", "@types/cross-spawn": "^6.0.6", + "@types/prompts": "2.4.9", "@types/react": "19.0.10", "@viem/anvil": "0.0.10", "@vitejs/plugin-react": "^4.3.4", diff --git a/packages/thirdweb/scripts/generate/abis/stylus/IArbWasm.json b/packages/thirdweb/scripts/generate/abis/stylus/IArbWasm.json new file mode 100644 index 00000000000..44e1a961f48 --- /dev/null +++ b/packages/thirdweb/scripts/generate/abis/stylus/IArbWasm.json @@ -0,0 +1,3 @@ +[ + "function activateProgram(address program) returns (uint16,uint256)" +] \ No newline at end of file diff --git a/packages/thirdweb/src/cli/bin.ts b/packages/thirdweb/src/cli/bin.ts old mode 100644 new mode 100755 index 98ea2babcfb..18c62e926a5 --- a/packages/thirdweb/src/cli/bin.ts +++ b/packages/thirdweb/src/cli/bin.ts @@ -4,9 +4,19 @@ import { generate, isValidChainIdAndContractAddress, } from "./commands/generate/generate.js"; +import { deployStylus, publishStylus } from "./commands/stylus/builder.js"; +import { createStylusProject } from "./commands/stylus/create.js"; + // skip the first two args? const [, , command = "", ...rest] = process.argv; +let secretKey: string | undefined; +const keyIndex = rest.indexOf("-k"); +if (keyIndex !== -1 && rest.length > keyIndex + 1) { + secretKey = rest[keyIndex + 1]; + rest.splice(keyIndex, 2); +} + async function main() { switch (command) { case "generate": { @@ -20,6 +30,21 @@ async function main() { break; } + case "publish-stylus": { + await publishStylus(secretKey); + break; + } + + case "deploy-stylus": { + await deployStylus(secretKey); + break; + } + + case "create-stylus": { + await createStylusProject(); + break; + } + case "login": { // Not implemented yet console.info( diff --git a/packages/thirdweb/src/cli/commands/stylus/builder.ts b/packages/thirdweb/src/cli/commands/stylus/builder.ts new file mode 100644 index 00000000000..48a6f16aced --- /dev/null +++ b/packages/thirdweb/src/cli/commands/stylus/builder.ts @@ -0,0 +1,201 @@ +import { spawnSync } from "node:child_process"; +import { existsSync, readFileSync } from "node:fs"; +import { join } from "node:path"; +import open from "open"; +import ora, { type Ora } from "ora"; +import { parse } from "toml"; +import { createThirdwebClient } from "../../../client/client.js"; +import { upload } from "../../../storage/upload.js"; + +const THIRDWEB_URL = "https://thirdweb.com"; + +export async function publishStylus(secretKey?: string) { + const spinner = ora("Checking if this is a Stylus project...").start(); + const uri = await buildStylus(spinner, secretKey); + + const url = getUrl(uri, "publish").toString(); + spinner.succeed(`Upload complete, navigate to ${url}`); + await open(url); +} + +export async function deployStylus(secretKey?: string) { + const spinner = ora("Checking if this is a Stylus project...").start(); + const uri = await buildStylus(spinner, secretKey); + + const url = getUrl(uri, "deploy").toString(); + spinner.succeed(`Upload complete, navigate to ${url}`); + await open(url); +} + +async function buildStylus(spinner: Ora, secretKey?: string) { + if (!secretKey) { + spinner.fail("Error: Secret key is required."); + process.exit(1); + } + + try { + // Step 1: Validate stylus project + const root = process.cwd(); + if (!root) { + spinner.fail("Error: No package directory found."); + process.exit(1); + } + + const cargoTomlPath = join(root, "Cargo.toml"); + if (!existsSync(cargoTomlPath)) { + spinner.fail("Error: No Cargo.toml found. Not a Stylus/Rust project."); + process.exit(1); + } + + const cargoToml = readFileSync(cargoTomlPath, "utf8"); + const parsedCargoToml = parse(cargoToml); + if (!parsedCargoToml.dependencies?.["stylus-sdk"]) { + spinner.fail( + "Error: Not a Stylus project. Missing stylus-sdk dependency.", + ); + process.exit(1); + } + + spinner.succeed("Stylus project detected."); + + // Step 2: Run stylus command to generate initcode + spinner.start("Generating initcode..."); + const initcodeResult = spawnSync("cargo", ["stylus", "get-initcode"], { + encoding: "utf-8", + }); + if (initcodeResult.status !== 0) { + spinner.fail("Failed to generate initcode."); + process.exit(1); + } + + const initcode = extractBytecode(initcodeResult.stdout); + if (!initcode) { + spinner.fail("Failed to generate initcode."); + process.exit(1); + } + spinner.succeed("Initcode generated."); + + // Step 3: Run stylus command to generate abi + spinner.start("Generating ABI..."); + const abiResult = spawnSync("cargo", ["stylus", "export-abi", "--json"], { + encoding: "utf-8", + }); + if (abiResult.status !== 0) { + spinner.fail("Failed to generate ABI."); + process.exit(1); + } + + const abiContent = abiResult.stdout.trim(); + if (!abiContent) { + spinner.fail("Failed to generate ABI."); + process.exit(1); + } + spinner.succeed("ABI generated."); + + // Step 4: Process the output + const contractName = extractContractNameFromExportAbi(abiContent); + if (!contractName) { + spinner.fail("Error: Could not determine contract name from ABI output."); + process.exit(1); + } + + let cleanedAbi = ""; + try { + const jsonMatch = abiContent.match(/\[.*\]/s); + if (jsonMatch) { + cleanedAbi = jsonMatch[0]; + } else { + throw new Error("No valid JSON ABI found in the file."); + } + } catch (error) { + spinner.fail("Error: ABI file contains invalid format."); + console.error(error); + process.exit(1); + } + + const metadata = { + compiler: {}, + language: "rust", + output: { + abi: JSON.parse(cleanedAbi), + devdoc: {}, + userdoc: {}, + }, + settings: { + compilationTarget: { + "src/main.rs": contractName, + }, + }, + sources: {}, + }; + spinner.succeed("Stylus contract exported successfully."); + + // Step 5: Upload to IPFS + spinner.start("Uploading to IPFS..."); + const client = createThirdwebClient({ + secretKey, + }); + + const metadataUri = await upload({ + client, + files: [metadata], + }); + + const bytecodeUri = await upload({ + client, + files: [initcode], + }); + + const uri = await upload({ + client, + files: [ + { + name: contractName, + metadataUri, + bytecodeUri, + analytics: { + command: "publish-stylus", + contract_name: contractName, + cli_version: "", + project_type: "stylus", + }, + compilers: { + stylus: [ + { compilerVersion: "", evmVersion: "", metadataUri, bytecodeUri }, + ], + }, + }, + ], + }); + spinner.succeed("Upload complete"); + + return uri; + } catch (error) { + spinner.fail(`Error: ${error}`); + process.exit(1); + } +} + +function extractContractNameFromExportAbi(abiRawOutput: string): string | null { + const match = abiRawOutput.match(/:(I[A-Za-z0-9_]+)/); + if (match?.[1]) { + return match[1].replace(/^I/, ""); + } + return null; +} + +function getUrl(hash: string, command: string) { + const url = new URL( + `${THIRDWEB_URL}/contracts/${command}/${encodeURIComponent(hash.replace("ipfs://", ""))}`, + ); + + return url; +} + +function extractBytecode(rawOutput: string): string { + const hexStart = rawOutput.indexOf("7f000000"); + if (hexStart === -1) { + throw new Error("Could not find start of bytecode"); + } + return rawOutput.slice(hexStart).trim(); +} diff --git a/packages/thirdweb/src/cli/commands/stylus/create.ts b/packages/thirdweb/src/cli/commands/stylus/create.ts new file mode 100644 index 00000000000..561517067b1 --- /dev/null +++ b/packages/thirdweb/src/cli/commands/stylus/create.ts @@ -0,0 +1,51 @@ +import { spawnSync } from "node:child_process"; +import ora from "ora"; +import prompts from "prompts"; + +export async function createStylusProject() { + const spinner = ora(); + + // Step 1: Ensure cargo is installed + const cargoCheck = spawnSync("cargo", ["--version"]); + if (cargoCheck.status !== 0) { + console.error("Error: `cargo` is not installed"); + process.exit(1); + } + + // Step 2: Install stylus etc. + spinner.start("Installing Stylus..."); + const install = spawnSync("cargo", ["install", "--force", "cargo-stylus"], { + stdio: "inherit", + }); + if (install.status !== 0) { + spinner.fail("Failed to install Stylus."); + process.exit(1); + } + spinner.succeed("Stylus installed."); + + spawnSync("rustup", ["default", "1.83"], { + stdio: "inherit", + }); + spawnSync("rustup", ["target", "add", "wasm32-unknown-unknown"], { + stdio: "inherit", + }); + + // Step 3: Create the project + const { projectName } = await prompts({ + type: "text", + name: "projectName", + message: "Project name:", + initial: "my-stylus-project", + }); + spinner.start(`Creating new Stylus project: ${projectName}...`); + const newProject = spawnSync("cargo", ["stylus", "new", projectName], { + stdio: "inherit", + }); + if (newProject.status !== 0) { + spinner.fail("Failed to create Stylus project."); + process.exit(1); + } + spinner.succeed("Project created successfully."); + + console.log(`\n✅ Done! cd into your project: ${projectName}`); +} diff --git a/packages/thirdweb/src/contract/deployment/deploy-deterministic.ts b/packages/thirdweb/src/contract/deployment/deploy-deterministic.ts index c6775514b84..8e63fc8e5a9 100644 --- a/packages/thirdweb/src/contract/deployment/deploy-deterministic.ts +++ b/packages/thirdweb/src/contract/deployment/deploy-deterministic.ts @@ -52,7 +52,7 @@ export function prepareDeterministicDeployTransaction( data: async () => { const infraContractInfo = await computeDeploymentInfoFromContractId(options); - return infraContractInfo.initBytecodeWithsalt; + return infraContractInfo.initCalldata; }, }); } diff --git a/packages/thirdweb/src/contract/deployment/deploy-with-abi.ts b/packages/thirdweb/src/contract/deployment/deploy-with-abi.ts index 73f0bd3bb5b..fea0c687e61 100644 --- a/packages/thirdweb/src/contract/deployment/deploy-with-abi.ts +++ b/packages/thirdweb/src/contract/deployment/deploy-with-abi.ts @@ -1,5 +1,7 @@ import type { Abi, AbiConstructor } from "abitype"; +import { activateStylusContract } from "../../extensions/stylus/write/activateStylusContract.js"; import { sendAndConfirmTransaction } from "../../transaction/actions/send-and-confirm-transaction.js"; +import { sendTransaction } from "../../transaction/actions/send-transaction.js"; import { prepareTransaction } from "../../transaction/prepare-transaction.js"; import { encodeAbiParameters } from "../../utils/abi/encodeAbiParameters.js"; import { normalizeFunctionParams } from "../../utils/abi/normalizeFunctionParams.js"; @@ -24,6 +26,7 @@ export type PrepareDirectDeployTransactionOptions = Prettify< abi: Abi; bytecode: Hex; constructorParams?: Record; + extraDataWithUri?: string; } >; @@ -70,6 +73,7 @@ export function prepareDirectDeployTransaction( constructorAbi?.inputs || [], // Leave an empty array if there's no constructor normalizeFunctionParams(constructorAbi, options.constructorParams), ), + (options.extraDataWithUri as `0x${string}`) || "0x", ]), }); } @@ -121,6 +125,8 @@ export async function deployContract( options: PrepareDirectDeployTransactionOptions & { account: Account; salt?: string; + extraDataWithUri?: Hex; + isStylus?: boolean; }, ) { if (await isZkSyncChain(options.chain)) { @@ -135,14 +141,16 @@ export async function deployContract( }); } + let address: string | null | undefined; if (options.salt !== undefined) { // Deploy with CREATE2 if salt is provided const info = await computeDeploymentInfoFromBytecode(options); - const address = computeDeploymentAddress({ + address = computeDeploymentAddress({ bytecode: options.bytecode, encodedArgs: info.encodedArgs, create2FactoryAddress: info.create2FactoryAddress, salt: options.salt, + extraDataWithUri: options.extraDataWithUri, }); const isDeployed = await isContractDeployed( getContract({ @@ -160,21 +168,39 @@ export async function deployContract( chain: options.chain, client: options.client, to: info.create2FactoryAddress, - data: info.initBytecodeWithsalt, + data: info.initCalldata, }), }); - return address; + } else { + const deployTx = prepareDirectDeployTransaction(options); + const receipt = await sendAndConfirmTransaction({ + account: options.account, + transaction: deployTx, + }); + address = receipt.contractAddress; + if (!address) { + throw new Error( + `Could not find deployed contract address in transaction: ${receipt.transactionHash}`, + ); + } } - const deployTx = prepareDirectDeployTransaction(options); - const receipt = await sendAndConfirmTransaction({ - account: options.account, - transaction: deployTx, - }); - if (!receipt.contractAddress) { - throw new Error( - `Could not find deployed contract address in transaction: ${receipt.transactionHash}`, - ); + if (options.isStylus) { + try { + const activationTransaction = await activateStylusContract({ + chain: options.chain, + client: options.client, + contractAddress: address, + }); + + await sendTransaction({ + transaction: activationTransaction, + account: options.account, + }); + } catch { + console.error("Error: Contract could not be activated."); + } } - return receipt.contractAddress; + + return address; } diff --git a/packages/thirdweb/src/contract/deployment/utils/bootstrap.ts b/packages/thirdweb/src/contract/deployment/utils/bootstrap.ts index 5226ce9df49..256392288f5 100644 --- a/packages/thirdweb/src/contract/deployment/utils/bootstrap.ts +++ b/packages/thirdweb/src/contract/deployment/utils/bootstrap.ts @@ -1,4 +1,6 @@ +import { activateStylusContract } from "../../../extensions/stylus/write/activateStylusContract.js"; import { sendAndConfirmTransaction } from "../../../transaction/actions/send-and-confirm-transaction.js"; +import { sendTransaction } from "../../../transaction/actions/send-transaction.js"; import { type FetchDeployMetadataResult, fetchBytecodeFromCompilerMetadata, @@ -255,5 +257,24 @@ export async function getOrDeployInfraContractFromMetadata( if (!deployedInfraContract) { throw new Error(`Failed to deploy ${options.contractMetadata.name}`); } + + const isStylus = options.contractMetadata.metadata.language === "rust"; + if (isStylus) { + try { + const activationTransaction = await activateStylusContract({ + chain: options.chain, + client: options.client, + contractAddress: deployedInfraContract.address, + }); + + await sendTransaction({ + transaction: activationTransaction, + account: options.account, + }); + } catch { + console.error("Error: Contract could not be activated."); + } + } + return deployedInfraContract; } diff --git a/packages/thirdweb/src/contract/deployment/utils/infra.ts b/packages/thirdweb/src/contract/deployment/utils/infra.ts index b2f2a5c59e9..932a060566a 100644 --- a/packages/thirdweb/src/contract/deployment/utils/infra.ts +++ b/packages/thirdweb/src/contract/deployment/utils/infra.ts @@ -100,7 +100,7 @@ export function prepareInfraContractDeployTransactionFromMetadata(options: { data: async () => { const infraContractInfo = await computeDeploymentInfoFromMetadata(options); - return infraContractInfo.initBytecodeWithsalt; + return infraContractInfo.initCalldata; }, }); } diff --git a/packages/thirdweb/src/exports/extensions/stylus.ts b/packages/thirdweb/src/exports/extensions/stylus.ts new file mode 100644 index 00000000000..b4c9dd165dc --- /dev/null +++ b/packages/thirdweb/src/exports/extensions/stylus.ts @@ -0,0 +1,7 @@ +/** + * Write + */ +export { + activateStylusContract, + type ActivateStylusContractOptions, +} from "../../extensions/stylus/write/activateStylusContract.js"; diff --git a/packages/thirdweb/src/extensions/prebuilts/deploy-published.ts b/packages/thirdweb/src/extensions/prebuilts/deploy-published.ts index 752dd48d2b7..df29f6d26fb 100644 --- a/packages/thirdweb/src/extensions/prebuilts/deploy-published.ts +++ b/packages/thirdweb/src/extensions/prebuilts/deploy-published.ts @@ -16,6 +16,7 @@ import { fetchBytecodeFromCompilerMetadata, } from "../../utils/any-evm/deploy-metadata.js"; import type { FetchDeployMetadataResult } from "../../utils/any-evm/deploy-metadata.js"; +import { encodeExtraDataWithUri } from "../../utils/any-evm/encode-extra-data-with-uri.js"; import type { Hex } from "../../utils/encoding/hex.js"; import type { Account } from "../../wallets/interfaces/wallet.js"; import { getAllDefaultConstructorParamsForImplementation } from "./get-required-transactions.js"; @@ -194,6 +195,7 @@ export async function deployContractfromDeployMetadata( compilerMetadata: deployMetadata, contractParams: processedInitializeParams, salt, + metadataUri: deployMetadata.metadataUri, }); } case "autoFactory": { @@ -320,6 +322,7 @@ export async function deployContractfromDeployMetadata( compilerMetadata: deployMetadata, contractParams: processedInitializeParams, salt, + metadataUri: deployMetadata.metadataUri, }); } default: @@ -335,6 +338,7 @@ async function directDeploy(options: { compilerMetadata: CompilerMetadata; contractParams?: Record; salt?: string; + metadataUri?: string; }): Promise { const { account, client, chain, compilerMetadata, contractParams, salt } = options; @@ -342,6 +346,7 @@ async function directDeploy(options: { const { deployContract } = await import( "../../contract/deployment/deploy-with-abi.js" ); + const isStylus = options.compilerMetadata.metadata.language === "rust"; return deployContract({ account, client, @@ -354,6 +359,13 @@ async function directDeploy(options: { abi: compilerMetadata.abi, constructorParams: contractParams, salt, + extraDataWithUri: + isStylus && options.metadataUri + ? encodeExtraDataWithUri({ + metadataUri: options.metadataUri, + }) + : undefined, + isStylus, }); } diff --git a/packages/thirdweb/src/extensions/stylus/__generated__/IArbWasm/write/activateProgram.ts b/packages/thirdweb/src/extensions/stylus/__generated__/IArbWasm/write/activateProgram.ts new file mode 100644 index 00000000000..9a400364f18 --- /dev/null +++ b/packages/thirdweb/src/extensions/stylus/__generated__/IArbWasm/write/activateProgram.ts @@ -0,0 +1,144 @@ +import type { AbiParameterToPrimitiveType } from "abitype"; +import type { + BaseTransactionOptions, + WithOverrides, +} from "../../../../../transaction/types.js"; +import { prepareContractCall } from "../../../../../transaction/prepare-contract-call.js"; +import { encodeAbiParameters } from "../../../../../utils/abi/encodeAbiParameters.js"; +import { once } from "../../../../../utils/promise/once.js"; +import { detectMethod } from "../../../../../utils/bytecode/detectExtension.js"; + +/** + * Represents the parameters for the "activateProgram" function. + */ +export type ActivateProgramParams = WithOverrides<{ + program: AbiParameterToPrimitiveType<{ type: "address"; name: "program" }>; +}>; + +export const FN_SELECTOR = "0x58c780c2" as const; +const FN_INPUTS = [ + { + type: "address", + name: "program", + }, +] as const; +const FN_OUTPUTS = [ + { + type: "uint16", + }, + { + type: "uint256", + }, +] as const; + +/** + * Checks if the `activateProgram` method is supported by the given contract. + * @param availableSelectors An array of 4byte function selectors of the contract. You can get this in various ways, such as using "whatsabi" or if you have the ABI of the contract available you can use it to generate the selectors. + * @returns A boolean indicating if the `activateProgram` method is supported. + * @extension STYLUS + * @example + * ```ts + * import { isActivateProgramSupported } from "thirdweb/extensions/stylus"; + * + * const supported = isActivateProgramSupported(["0x..."]); + * ``` + */ +export function isActivateProgramSupported(availableSelectors: string[]) { + return detectMethod({ + availableSelectors, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + }); +} + +/** + * Encodes the parameters for the "activateProgram" function. + * @param options - The options for the activateProgram function. + * @returns The encoded ABI parameters. + * @extension STYLUS + * @example + * ```ts + * import { encodeActivateProgramParams } from "thirdweb/extensions/stylus"; + * const result = encodeActivateProgramParams({ + * program: ..., + * }); + * ``` + */ +export function encodeActivateProgramParams(options: ActivateProgramParams) { + return encodeAbiParameters(FN_INPUTS, [options.program]); +} + +/** + * Encodes the "activateProgram" function into a Hex string with its parameters. + * @param options - The options for the activateProgram function. + * @returns The encoded hexadecimal string. + * @extension STYLUS + * @example + * ```ts + * import { encodeActivateProgram } from "thirdweb/extensions/stylus"; + * const result = encodeActivateProgram({ + * program: ..., + * }); + * ``` + */ +export function encodeActivateProgram(options: ActivateProgramParams) { + // we do a "manual" concat here to avoid the overhead of the "concatHex" function + // we can do this because we know the specific formats of the values + return (FN_SELECTOR + + encodeActivateProgramParams(options).slice( + 2, + )) as `${typeof FN_SELECTOR}${string}`; +} + +/** + * Prepares a transaction to call the "activateProgram" function on the contract. + * @param options - The options for the "activateProgram" function. + * @returns A prepared transaction object. + * @extension STYLUS + * @example + * ```ts + * import { sendTransaction } from "thirdweb"; + * import { activateProgram } from "thirdweb/extensions/stylus"; + * + * const transaction = activateProgram({ + * contract, + * program: ..., + * overrides: { + * ... + * } + * }); + * + * // Send the transaction + * await sendTransaction({ transaction, account }); + * ``` + */ +export function activateProgram( + options: BaseTransactionOptions< + | ActivateProgramParams + | { + asyncParams: () => Promise; + } + >, +) { + const asyncOptions = once(async () => { + return "asyncParams" in options ? await options.asyncParams() : options; + }); + + return prepareContractCall({ + contract: options.contract, + method: [FN_SELECTOR, FN_INPUTS, FN_OUTPUTS] as const, + params: async () => { + const resolvedOptions = await asyncOptions(); + return [resolvedOptions.program] as const; + }, + value: async () => (await asyncOptions()).overrides?.value, + accessList: async () => (await asyncOptions()).overrides?.accessList, + gas: async () => (await asyncOptions()).overrides?.gas, + gasPrice: async () => (await asyncOptions()).overrides?.gasPrice, + maxFeePerGas: async () => (await asyncOptions()).overrides?.maxFeePerGas, + maxPriorityFeePerGas: async () => + (await asyncOptions()).overrides?.maxPriorityFeePerGas, + nonce: async () => (await asyncOptions()).overrides?.nonce, + extraGas: async () => (await asyncOptions()).overrides?.extraGas, + erc20Value: async () => (await asyncOptions()).overrides?.erc20Value, + }); +} diff --git a/packages/thirdweb/src/extensions/stylus/write/activateStylusContract.ts b/packages/thirdweb/src/extensions/stylus/write/activateStylusContract.ts new file mode 100644 index 00000000000..03a05722cbe --- /dev/null +++ b/packages/thirdweb/src/extensions/stylus/write/activateStylusContract.ts @@ -0,0 +1,95 @@ +import { + decodeAbiParameters, + formatTransactionRequest, + parseEther, +} from "viem"; +import type { Chain } from "../../../chains/types.js"; +import type { ThirdwebClient } from "../../../client/client.js"; +import { getContract } from "../../../contract/contract.js"; +import { eth_call } from "../../../rpc/actions/eth_call.js"; +import { getRpcClient } from "../../../rpc/rpc.js"; +import { encode } from "../../../transaction/actions/encode.js"; +import type { PreparedTransaction } from "../../../transaction/prepare-transaction.js"; +import { activateProgram } from "../__generated__/IArbWasm/write/activateProgram.js"; + +const ARB_WASM_ADDRESS = "0x0000000000000000000000000000000000000071"; + +export type ActivateStylusContractOptions = { + chain: Chain; + client: ThirdwebClient; + contractAddress: string; +}; + +/** + * Activate a stylus contract by calling ArbWasm Precompile + * @param options - The options for activating the contract + * @returns A prepared transaction to send + * @example + * ```ts + * import { activateStylusContract } from "thirdweb/stylus"; + * const transaction = activateStylusContract({ + * client, + * chain, + * contractAddress, + * }); + * await sendTransaction({ transaction, account }); + * ``` + */ +export async function activateStylusContract( + options: ActivateStylusContractOptions, +) { + const { chain, client, contractAddress } = options; + const arbWasmPrecompile = getContract({ + client, + chain, + address: ARB_WASM_ADDRESS, + }); + + const dataFee = await estimateDataFee({ + transaction: activateProgram({ + program: contractAddress, + contract: arbWasmPrecompile, + }), + }); + + return activateProgram({ + program: contractAddress, + contract: arbWasmPrecompile, + overrides: { + value: dataFee, + }, + }); +} + +async function estimateDataFee(options: { + // biome-ignore lint/suspicious/noExplicitAny: + transaction: PreparedTransaction; +}) { + const data = await encode(options.transaction); + + const serializedTx = formatTransactionRequest({ + data, + to: ARB_WASM_ADDRESS, + value: parseEther("1"), // only for simulation. it will be replaced with estimated data fee. + }); + + const rpcRequest = getRpcClient(options.transaction); + try { + const result = await eth_call(rpcRequest, serializedTx); + const [, dataFee] = decodeAbiParameters( + [ + { + type: "uint16", + }, + { + type: "uint256", + }, + ], + result, + ); + + return (dataFee * BigInt(100 + 10)) / BigInt(100); // bump 10% + } catch { + return 0n; + } +} diff --git a/packages/thirdweb/src/utils/any-evm/compute-deployment-address.ts b/packages/thirdweb/src/utils/any-evm/compute-deployment-address.ts index ccd0793db79..80338db8929 100644 --- a/packages/thirdweb/src/utils/any-evm/compute-deployment-address.ts +++ b/packages/thirdweb/src/utils/any-evm/compute-deployment-address.ts @@ -11,6 +11,7 @@ type ComputeDeploymentAddressOptions = { encodedArgs: Hex; create2FactoryAddress: string; salt?: string; + extraDataWithUri?: Hex; }; /** @@ -40,10 +41,12 @@ export function computeDeploymentAddress( : getSaltHash(bytecode); // 1. create init bytecode hash with contract's bytecode and encoded args - const initBytecode = encodePacked( - ["bytes", "bytes"], - [bytecode, options.encodedArgs], - ); + const initBytecode = options.extraDataWithUri + ? encodePacked( + ["bytes", "bytes", "bytes"], + [bytecode, options.encodedArgs, options.extraDataWithUri], + ) + : encodePacked(["bytes", "bytes"], [bytecode, options.encodedArgs]); // 2. abi-encode pack the deployer address, salt, and bytecode hash const deployInfoPacked = encodePacked( diff --git a/packages/thirdweb/src/utils/any-evm/compute-published-contract-deploy-info.ts b/packages/thirdweb/src/utils/any-evm/compute-published-contract-deploy-info.ts index e95d6fe66ac..7bc63eb34af 100644 --- a/packages/thirdweb/src/utils/any-evm/compute-published-contract-deploy-info.ts +++ b/packages/thirdweb/src/utils/any-evm/compute-published-contract-deploy-info.ts @@ -1,4 +1,5 @@ import type { Abi, AbiConstructor } from "abitype"; +import { encodePacked } from "viem"; import type { Chain } from "../../chains/types.js"; import type { ThirdwebClient } from "../../client/client.js"; import { fetchPublishedContractMetadata } from "../../contract/deployment/publisher.js"; @@ -13,6 +14,7 @@ import { type FetchDeployMetadataResult, fetchBytecodeFromCompilerMetadata, } from "./deploy-metadata.js"; +import { encodeExtraDataWithUri } from "./encode-extra-data-with-uri.js"; import { getInitBytecodeWithSalt } from "./get-init-bytecode-with-salt.js"; /** @@ -70,6 +72,7 @@ export async function computeDeploymentInfoFromMetadata(args: { } } + const isStylus = contractMetadata.metadata.language === "rust"; return computeDeploymentInfoFromBytecode({ client: args.client, chain: args.chain, @@ -81,6 +84,11 @@ export async function computeDeploymentInfoFromMetadata(args: { }), constructorParams: processedConstructorParams, salt: args.salt, + extraDataWithUri: isStylus + ? encodeExtraDataWithUri({ + metadataUri: contractMetadata.metadataUri, + }) + : undefined, }); } @@ -91,8 +99,9 @@ export async function computeDeploymentInfoFromBytecode(args: { bytecode: Hex; constructorParams?: Record; salt?: string; + extraDataWithUri?: Hex; }) { - const { client, chain, constructorParams, salt } = args; + const { client, chain, constructorParams, salt, extraDataWithUri } = args; const create2FactoryAddress = await computeCreate2FactoryAddress({ client, chain, @@ -110,11 +119,16 @@ export async function computeDeploymentInfoFromBytecode(args: { encodedArgs, salt, }); + + const initCalldata = extraDataWithUri + ? encodePacked(["bytes", "bytes"], [initBytecodeWithsalt, extraDataWithUri]) + : initBytecodeWithsalt; return { bytecode, - initBytecodeWithsalt, + initCalldata, encodedArgs, create2FactoryAddress, salt, + extraDataWithUri, }; } diff --git a/packages/thirdweb/src/utils/any-evm/deploy-metadata.ts b/packages/thirdweb/src/utils/any-evm/deploy-metadata.ts index 7dfb326bf76..d956cae6154 100644 --- a/packages/thirdweb/src/utils/any-evm/deploy-metadata.ts +++ b/packages/thirdweb/src/utils/any-evm/deploy-metadata.ts @@ -253,7 +253,7 @@ export type ExtendedMetadata = { >; compositeAbi?: Abi; compilers?: Record< - "solc" | "zksolc", + "solc" | "zksolc" | "stylus", { evmVersion: string; compilerVersion: string; diff --git a/packages/thirdweb/src/utils/any-evm/encode-extra-data-with-uri.ts b/packages/thirdweb/src/utils/any-evm/encode-extra-data-with-uri.ts new file mode 100644 index 00000000000..056cf8fad04 --- /dev/null +++ b/packages/thirdweb/src/utils/any-evm/encode-extra-data-with-uri.ts @@ -0,0 +1,13 @@ +import { encodePacked } from "ox/AbiParameters"; +import { numberToHex, stringToHex } from "../encoding/hex.js"; + +export function encodeExtraDataWithUri(options: { + metadataUri: string; +}) { + const uriHex = stringToHex(options.metadataUri); + const lengthHex = numberToHex(uriHex.replace("0x", "").length / 2, { + size: 1, + }); + + return encodePacked(["bytes", "bytes"], [uriHex, lengthHex]); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d33efceb23d..5b9143cbc27 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1091,9 +1091,21 @@ importers: mipd: specifier: 0.0.7 version: 0.0.7(typescript@5.8.2) + open: + specifier: 10.1.0 + version: 10.1.0 + ora: + specifier: 8.2.0 + version: 8.2.0 ox: specifier: 0.6.10 version: 0.6.10(typescript@5.8.2)(zod@3.24.2) + prompts: + specifier: 2.4.2 + version: 2.4.2 + toml: + specifier: 3.0.0 + version: 3.0.0 uqr: specifier: 0.1.2 version: 0.1.2 @@ -1164,6 +1176,9 @@ importers: '@types/cross-spawn': specifier: ^6.0.6 version: 6.0.6 + '@types/prompts': + specifier: 2.4.9 + version: 2.4.9 '@types/react': specifier: 19.0.10 version: 19.0.10 @@ -6342,6 +6357,9 @@ packages: '@types/pluralize@0.0.33': resolution: {integrity: sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg==} + '@types/prompts@2.4.9': + resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==} + '@types/qrcode@1.5.5': resolution: {integrity: sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==} @@ -7493,6 +7511,10 @@ packages: bundle-n-require@1.1.1: resolution: {integrity: sha512-EB2wFjXF106LQLe/CYnKCMCdLeTW47AtcEtUfiqAOgr2a08k0+YgRklur2aLfEYHlhz6baMskZ8L2U92Hh0vyA==} + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} @@ -7741,6 +7763,10 @@ packages: resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} @@ -8236,6 +8262,14 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + default-browser-id@5.0.0: + resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==} + engines: {node: '>=18'} + + default-browser@5.2.1: + resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==} + engines: {node: '>=18'} + default-gateway@4.2.0: resolution: {integrity: sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==} engines: {node: '>=6'} @@ -8255,6 +8289,10 @@ packages: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} @@ -9408,6 +9446,10 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-east-asian-width@1.3.0: + resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==} + engines: {node: '>=18'} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -9982,6 +10024,11 @@ packages: engines: {node: '>=8'} hasBin: true + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + is-empty@1.2.0: resolution: {integrity: sha512-F2FnH/otLNJv0J6wc73A5Xo7oHLNnqplYqZhUu01tD54DIPvxIRSTSLkrUB/M0nHO4vo1O9PDfN4KoTxCzLh/w==} @@ -10015,6 +10062,11 @@ packages: is-hexadecimal@2.0.1: resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + is-installed-globally@0.4.0: resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} engines: {node: '>=10'} @@ -10135,6 +10187,10 @@ packages: resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} engines: {node: '>=12'} + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -10155,6 +10211,10 @@ packages: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} + is-wsl@3.1.0: + resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + engines: {node: '>=16'} + is-yarn-global@0.4.1: resolution: {integrity: sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==} engines: {node: '>=12'} @@ -10708,6 +10768,10 @@ packages: resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==} engines: {node: '>=12'} + log-symbols@6.0.0: + resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} + engines: {node: '>=18'} + lokijs@1.5.12: resolution: {integrity: sha512-Q5ALD6JiS6xAUWCwX3taQmgwxyveCtIIuL08+ml0nHwT3k0S/GIFJN+Hd38b1qYIMaE5X++iqsqWVksz7SYW+Q==} @@ -11278,6 +11342,10 @@ packages: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + mimic-response@3.1.0: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} @@ -11868,9 +11936,17 @@ packages: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + oniguruma-to-es@1.0.0: resolution: {integrity: sha512-kihvp0O4lFwf5tZMkfanwQLIZ9ORe9OeOFgZonH0BQeThgwfJiaZFeOfvvJVnJIM9TiVmx0RDD35hUJDR0++rQ==} + open@10.1.0: + resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==} + engines: {node: '>=18'} + open@7.4.2: resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} engines: {node: '>=8'} @@ -11910,6 +11986,10 @@ packages: resolution: {integrity: sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==} engines: {node: '>=16'} + ora@8.2.0: + resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} + engines: {node: '>=18'} + os-browserify@0.3.0: resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} @@ -13175,6 +13255,10 @@ packages: resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + ret@0.2.2: resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} engines: {node: '>=4'} @@ -13221,6 +13305,10 @@ packages: rpc-websockets@9.1.1: resolution: {integrity: sha512-1IXGM/TfPT6nfYMIXkJdzn+L4JEsmb0FL1O2OBjaH03V3yuUDdKFulGLMFG6ErV+8pZ5HVC0limve01RyO+saA==} + run-applescript@7.0.0: + resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} + engines: {node: '>=18'} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -13612,6 +13700,10 @@ packages: resolution: {integrity: sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + stdin-discarder@0.2.2: + resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} + engines: {node: '>=18'} + storybook@8.6.4: resolution: {integrity: sha512-XXh1Acvf1r3BQX0BDLQw6yhZ7yUGvYxIcKOBuMdetnX7iXtczipJTfw0uyFwk0ltkKEE9PpJvivYmARF3u64VQ==} hasBin: true @@ -13660,6 +13752,10 @@ packages: resolution: {integrity: sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==} engines: {node: '>=16'} + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + string.prototype.codepointat@0.2.1: resolution: {integrity: sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==} @@ -14038,6 +14134,9 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + toml@3.0.0: + resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} + totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} @@ -15263,7 +15362,7 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.592.0(@aws-sdk/client-sts@3.592.0) + '@aws-sdk/client-sso-oidc': 3.592.0 '@aws-sdk/client-sts': 3.592.0 '@aws-sdk/core': 3.592.0 '@aws-sdk/credential-provider-node': 3.592.0(@aws-sdk/client-sso-oidc@3.592.0)(@aws-sdk/client-sts@3.592.0) @@ -15309,7 +15408,7 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.592.0(@aws-sdk/client-sts@3.592.0) + '@aws-sdk/client-sso-oidc': 3.592.0 '@aws-sdk/client-sts': 3.592.0 '@aws-sdk/core': 3.592.0 '@aws-sdk/credential-provider-node': 3.592.0(@aws-sdk/client-sso-oidc@3.592.0)(@aws-sdk/client-sts@3.592.0) @@ -15355,7 +15454,7 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.592.0(@aws-sdk/client-sts@3.592.0) + '@aws-sdk/client-sso-oidc': 3.592.0 '@aws-sdk/client-sts': 3.592.0 '@aws-sdk/core': 3.592.0 '@aws-sdk/credential-provider-node': 3.592.0(@aws-sdk/client-sso-oidc@3.592.0)(@aws-sdk/client-sts@3.592.0) @@ -15402,7 +15501,7 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sso-oidc@3.592.0(@aws-sdk/client-sts@3.592.0)': + '@aws-sdk/client-sso-oidc@3.592.0': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 @@ -15445,7 +15544,6 @@ snapshots: '@smithy/util-utf8': 3.0.0 tslib: 2.8.1 transitivePeerDependencies: - - '@aws-sdk/client-sts' - aws-crt '@aws-sdk/client-sso-oidc@3.758.0': @@ -15582,7 +15680,7 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.592.0(@aws-sdk/client-sts@3.592.0) + '@aws-sdk/client-sso-oidc': 3.592.0 '@aws-sdk/core': 3.592.0 '@aws-sdk/credential-provider-node': 3.592.0(@aws-sdk/client-sso-oidc@3.592.0)(@aws-sdk/client-sts@3.592.0) '@aws-sdk/middleware-host-header': 3.577.0 @@ -16024,7 +16122,7 @@ snapshots: '@aws-sdk/token-providers@3.587.0(@aws-sdk/client-sso-oidc@3.592.0)': dependencies: - '@aws-sdk/client-sso-oidc': 3.592.0(@aws-sdk/client-sts@3.592.0) + '@aws-sdk/client-sso-oidc': 3.592.0 '@aws-sdk/types': 3.577.0 '@smithy/property-provider': 3.1.11 '@smithy/shared-ini-file-loader': 3.1.12 @@ -22926,6 +23024,11 @@ snapshots: '@types/pluralize@0.0.33': {} + '@types/prompts@2.4.9': + dependencies: + '@types/node': 22.13.10 + kleur: 3.0.3 + '@types/qrcode@1.5.5': dependencies: '@types/node': 22.13.10 @@ -24857,6 +24960,10 @@ snapshots: esbuild: 0.20.2 node-eval: 2.0.0 + bundle-name@4.1.0: + dependencies: + run-applescript: 7.0.0 + busboy@1.6.0: dependencies: streamsearch: 1.1.0 @@ -25132,6 +25239,10 @@ snapshots: dependencies: restore-cursor: 4.0.0 + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + cli-spinners@2.9.2: {} cli-welcome@2.2.3: @@ -25625,6 +25736,13 @@ snapshots: deepmerge@4.3.1: {} + default-browser-id@5.0.0: {} + + default-browser@5.2.1: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.0 + default-gateway@4.2.0: dependencies: execa: 1.0.0 @@ -25644,6 +25762,8 @@ snapshots: define-lazy-prop@2.0.0: {} + define-lazy-prop@3.0.0: {} + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 @@ -26174,8 +26294,8 @@ snapshots: '@typescript-eslint/parser': 7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) eslint: 9.22.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)) + eslint-import-resolver-typescript: 3.8.3(eslint-plugin-import@2.31.0)(eslint@9.22.0(jiti@2.4.2)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.3)(eslint@9.22.0(jiti@2.4.2)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.22.0(jiti@2.4.2)) eslint-plugin-react: 7.37.4(eslint@9.22.0(jiti@2.4.2)) eslint-plugin-react-hooks: 5.1.0(eslint@9.22.0(jiti@2.4.2)) @@ -26194,33 +26314,33 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)): + eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0)(eslint@8.57.0): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0(supports-color@8.1.1) enhanced-resolve: 5.18.1 - eslint: 9.22.0(jiti@2.4.2) + eslint: 8.57.0 get-tsconfig: 4.10.0 is-bun-module: 1.3.0 stable-hash: 0.0.4 tinyglobby: 0.2.12 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.3)(eslint@8.57.0) transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0)(eslint@8.57.0): + eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0)(eslint@9.22.0(jiti@2.4.2)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0(supports-color@8.1.1) enhanced-resolve: 5.18.1 - eslint: 8.57.0 + eslint: 9.22.0(jiti@2.4.2) get-tsconfig: 4.10.0 is-bun-module: 1.3.0 stable-hash: 0.0.4 tinyglobby: 0.2.12 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.3)(eslint@8.57.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.3)(eslint@9.22.0(jiti@2.4.2)) transitivePeerDependencies: - supports-color @@ -26256,14 +26376,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0)(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2) eslint: 9.22.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)) + eslint-import-resolver-typescript: 3.8.3(eslint-plugin-import@2.31.0)(eslint@9.22.0(jiti@2.4.2)) transitivePeerDependencies: - supports-color @@ -26296,7 +26416,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint-import-resolver-typescript@3.8.3)(eslint@9.22.0(jiti@2.4.2)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -26307,7 +26427,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.22.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.14.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.8.3(eslint-plugin-import@2.31.0)(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -27389,6 +27509,8 @@ snapshots: get-caller-file@2.0.5: {} + get-east-asian-width@1.3.0: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -28057,6 +28179,8 @@ snapshots: is-docker@2.2.1: {} + is-docker@3.0.0: {} + is-empty@1.2.0: {} is-extglob@2.1.1: {} @@ -28084,6 +28208,10 @@ snapshots: is-hexadecimal@2.0.1: {} + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + is-installed-globally@0.4.0: dependencies: global-dirs: 3.0.1 @@ -28179,6 +28307,8 @@ snapshots: is-unicode-supported@1.3.0: {} + is-unicode-supported@2.1.0: {} + is-weakmap@2.0.2: {} is-weakref@1.1.1: @@ -28196,6 +28326,10 @@ snapshots: dependencies: is-docker: 2.2.1 + is-wsl@3.1.0: + dependencies: + is-inside-container: 1.0.0 + is-yarn-global@0.4.1: {} isarray@1.0.0: {} @@ -28789,6 +28923,11 @@ snapshots: chalk: 5.4.1 is-unicode-supported: 1.3.0 + log-symbols@6.0.0: + dependencies: + chalk: 5.4.1 + is-unicode-supported: 1.3.0 + lokijs@1.5.12: {} longest-streak@3.1.0: {} @@ -29986,6 +30125,8 @@ snapshots: mimic-fn@4.0.0: {} + mimic-function@5.0.1: {} + mimic-response@3.1.0: {} mimic-response@4.0.0: {} @@ -30510,12 +30651,23 @@ snapshots: dependencies: mimic-fn: 4.0.0 + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + oniguruma-to-es@1.0.0: dependencies: emoji-regex-xs: 1.0.0 regex: 5.1.1 regex-recursion: 5.1.1 + open@10.1.0: + dependencies: + default-browser: 5.2.1 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + is-wsl: 3.1.0 + open@7.4.2: dependencies: is-docker: 2.2.1 @@ -30575,6 +30727,18 @@ snapshots: string-width: 6.1.0 strip-ansi: 7.1.0 + ora@8.2.0: + dependencies: + chalk: 5.4.1 + cli-cursor: 5.0.0 + cli-spinners: 2.9.2 + is-interactive: 2.0.0 + is-unicode-supported: 2.1.0 + log-symbols: 6.0.0 + stdin-discarder: 0.2.2 + string-width: 7.2.0 + strip-ansi: 7.1.0 + os-browserify@0.3.0: {} os-tmpdir@1.0.2: {} @@ -32101,6 +32265,11 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + ret@0.2.2: {} retry@0.12.0: {} @@ -32190,6 +32359,8 @@ snapshots: bufferutil: 4.0.9 utf-8-validate: 5.0.10 + run-applescript@7.0.0: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -32651,6 +32822,8 @@ snapshots: dependencies: bl: 5.1.0 + stdin-discarder@0.2.2: {} + storybook@8.6.4(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10): dependencies: '@storybook/core': 8.6.4(bufferutil@4.0.9)(prettier@3.5.3)(storybook@8.6.4(bufferutil@4.0.9)(prettier@3.5.3)(utf-8-validate@5.0.10))(utf-8-validate@5.0.10) @@ -32708,6 +32881,12 @@ snapshots: emoji-regex: 10.4.0 strip-ansi: 7.1.0 + string-width@7.2.0: + dependencies: + emoji-regex: 10.4.0 + get-east-asian-width: 1.3.0 + strip-ansi: 7.1.0 + string.prototype.codepointat@0.2.1: {} string.prototype.includes@2.0.1: @@ -33185,6 +33364,8 @@ snapshots: toidentifier@1.0.1: {} + toml@3.0.0: {} + totalist@3.0.1: {} tough-cookie@4.1.4: