@layr-labs/ecloud-sdk 0.1.2 → 0.2.0-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { Address, Hex } from 'viem';
2
- import { L as Logger, E as EnvironmentConfig, b as DeployAppOpts, A as AppId, U as UpgradeAppOpts, c as PrepareDeployOpts, P as PreparedDeploy, G as GasOpts, e as ExecuteDeployResult, d as PrepareUpgradeOpts, a as PreparedUpgrade, f as ExecuteUpgradeResult, o as AppProfile, p as AppProfileResponse, i as LifecycleOpts } from './index-Fb_S-Cqk.cjs';
2
+ import { L as Logger, E as EnvironmentConfig, b as DeployAppOpts, A as AppId, U as UpgradeAppOpts, c as PrepareDeployOpts, P as PreparedDeploy, e as PrepareDeployFromVerifiableBuildOpts, G as GasOpts, g as ExecuteDeployResult, d as PrepareUpgradeOpts, a as PreparedUpgrade, f as PrepareUpgradeFromVerifiableBuildOpts, h as ExecuteUpgradeResult, q as AppProfile, r as AppProfileResponse, k as LifecycleOpts } from './index-D2QufVB9.js';
3
3
 
4
4
  /**
5
5
  * Create command
@@ -208,12 +208,20 @@ interface AppModule {
208
208
  prepared: PreparedDeploy;
209
209
  gasEstimate: GasEstimate;
210
210
  }>;
211
+ prepareDeployFromVerifiableBuild: (opts: PrepareDeployFromVerifiableBuildOpts) => Promise<{
212
+ prepared: PreparedDeploy;
213
+ gasEstimate: GasEstimate;
214
+ }>;
211
215
  executeDeploy: (prepared: PreparedDeploy, gas?: GasOpts) => Promise<ExecuteDeployResult>;
212
216
  watchDeployment: (appId: AppId) => Promise<string | undefined>;
213
217
  prepareUpgrade: (appId: AppId, opts: PrepareUpgradeOpts) => Promise<{
214
218
  prepared: PreparedUpgrade;
215
219
  gasEstimate: GasEstimate;
216
220
  }>;
221
+ prepareUpgradeFromVerifiableBuild: (appId: AppId, opts: PrepareUpgradeFromVerifiableBuildOpts) => Promise<{
222
+ prepared: PreparedUpgrade;
223
+ gasEstimate: GasEstimate;
224
+ }>;
217
225
  executeUpgrade: (prepared: PreparedUpgrade, gas?: GasOpts) => Promise<ExecuteUpgradeResult>;
218
226
  watchUpgrade: (appId: AppId) => Promise<void>;
219
227
  setProfile: (appId: AppId, profile: AppProfile) => Promise<AppProfileResponse>;
@@ -1,5 +1,5 @@
1
1
  import { Address, Hex } from 'viem';
2
- import { L as Logger, E as EnvironmentConfig, b as DeployAppOpts, A as AppId, U as UpgradeAppOpts, c as PrepareDeployOpts, P as PreparedDeploy, G as GasOpts, e as ExecuteDeployResult, d as PrepareUpgradeOpts, a as PreparedUpgrade, f as ExecuteUpgradeResult, o as AppProfile, p as AppProfileResponse, i as LifecycleOpts } from './index-Fb_S-Cqk.js';
2
+ import { L as Logger, E as EnvironmentConfig, b as DeployAppOpts, A as AppId, U as UpgradeAppOpts, c as PrepareDeployOpts, P as PreparedDeploy, e as PrepareDeployFromVerifiableBuildOpts, G as GasOpts, g as ExecuteDeployResult, d as PrepareUpgradeOpts, a as PreparedUpgrade, f as PrepareUpgradeFromVerifiableBuildOpts, h as ExecuteUpgradeResult, q as AppProfile, r as AppProfileResponse, k as LifecycleOpts } from './index-D2QufVB9.cjs';
3
3
 
4
4
  /**
5
5
  * Create command
@@ -208,12 +208,20 @@ interface AppModule {
208
208
  prepared: PreparedDeploy;
209
209
  gasEstimate: GasEstimate;
210
210
  }>;
211
+ prepareDeployFromVerifiableBuild: (opts: PrepareDeployFromVerifiableBuildOpts) => Promise<{
212
+ prepared: PreparedDeploy;
213
+ gasEstimate: GasEstimate;
214
+ }>;
211
215
  executeDeploy: (prepared: PreparedDeploy, gas?: GasOpts) => Promise<ExecuteDeployResult>;
212
216
  watchDeployment: (appId: AppId) => Promise<string | undefined>;
213
217
  prepareUpgrade: (appId: AppId, opts: PrepareUpgradeOpts) => Promise<{
214
218
  prepared: PreparedUpgrade;
215
219
  gasEstimate: GasEstimate;
216
220
  }>;
221
+ prepareUpgradeFromVerifiableBuild: (appId: AppId, opts: PrepareUpgradeFromVerifiableBuildOpts) => Promise<{
222
+ prepared: PreparedUpgrade;
223
+ gasEstimate: GasEstimate;
224
+ }>;
217
225
  executeUpgrade: (prepared: PreparedUpgrade, gas?: GasOpts) => Promise<ExecuteUpgradeResult>;
218
226
  watchUpgrade: (appId: AppId) => Promise<void>;
219
227
  setProfile: (appId: AppId, profile: AppProfile) => Promise<AppProfileResponse>;
package/dist/compute.cjs CHANGED
@@ -115,7 +115,7 @@ function getEnvironmentConfig(environment, chainID) {
115
115
  };
116
116
  }
117
117
  function getBuildType() {
118
- const buildTimeType = true ? "prod"?.toLowerCase() : void 0;
118
+ const buildTimeType = true ? "dev"?.toLowerCase() : void 0;
119
119
  const runtimeType = process.env.BUILD_TYPE?.toLowerCase();
120
120
  const buildType = buildTimeType || runtimeType;
121
121
  if (buildType === "dev") {
@@ -330,9 +330,9 @@ async function pushDockerImage(docker, imageRef, logger) {
330
330
  if (!output.includes("digest:") && !output.includes("pushed") && !output.includes("Pushed")) {
331
331
  logger?.debug?.("No clear success indicator in push output, verifying...");
332
332
  }
333
- logger?.info?.("Image push completed successfully");
334
333
  try {
335
334
  await verifyImageExists(imageRef, logger);
335
+ logger?.info?.("Image push completed successfully");
336
336
  resolve2();
337
337
  } catch (error) {
338
338
  reject(error);
@@ -1171,6 +1171,67 @@ Please verify the image exists: docker manifest inspect ${finalImageRef}`
1171
1171
  };
1172
1172
  }
1173
1173
 
1174
+ // src/client/common/release/prebuilt.ts
1175
+ async function createReleaseFromImageDigest(options, logger) {
1176
+ const { imageRef, imageDigest, envFilePath, instanceType, environmentConfig, appId } = options;
1177
+ if (!/^sha256:[0-9a-f]{64}$/i.test(imageDigest)) {
1178
+ throw new Error(`imageDigest must be in format sha256:<64 hex>, got: ${imageDigest}`);
1179
+ }
1180
+ let publicEnv = {};
1181
+ let privateEnv = {};
1182
+ if (envFilePath) {
1183
+ logger.info("Parsing environment file...");
1184
+ const parsed = parseAndValidateEnvFile(envFilePath);
1185
+ publicEnv = parsed.public;
1186
+ privateEnv = parsed.private;
1187
+ } else {
1188
+ logger.info("Continuing without environment file");
1189
+ }
1190
+ publicEnv["EIGEN_MACHINE_TYPE_PUBLIC"] = instanceType;
1191
+ logger.info(`Instance type: ${instanceType}`);
1192
+ logger.info("Encrypting environment variables...");
1193
+ const { encryptionKey } = getKMSKeysForEnvironment(
1194
+ environmentConfig.name,
1195
+ environmentConfig.build
1196
+ );
1197
+ const protectedHeaders = getAppProtectedHeaders(appId);
1198
+ const privateEnvBytes = Buffer.from(JSON.stringify(privateEnv));
1199
+ const encryptedEnvStr = await encryptRSAOAEPAndAES256GCM(
1200
+ encryptionKey,
1201
+ privateEnvBytes,
1202
+ protectedHeaders
1203
+ );
1204
+ const digestHex = imageDigest.split(":")[1];
1205
+ const digestBytes = new Uint8Array(Buffer.from(digestHex, "hex"));
1206
+ if (digestBytes.length !== 32) {
1207
+ throw new Error(`Digest must be exactly 32 bytes, got ${digestBytes.length}`);
1208
+ }
1209
+ const registry = extractRegistryNameNoDocker(imageRef);
1210
+ return {
1211
+ rmsRelease: {
1212
+ artifacts: [{ digest: digestBytes, registry }],
1213
+ upgradeByTime: Math.floor(Date.now() / 1e3) + 3600
1214
+ },
1215
+ publicEnv: new Uint8Array(Buffer.from(JSON.stringify(publicEnv))),
1216
+ encryptedEnv: new Uint8Array(Buffer.from(encryptedEnvStr))
1217
+ };
1218
+ }
1219
+ function extractRegistryNameNoDocker(imageRef) {
1220
+ let name = imageRef;
1221
+ const tagIndex = name.lastIndexOf(":");
1222
+ if (tagIndex !== -1 && !name.substring(tagIndex + 1).includes("/")) {
1223
+ name = name.substring(0, tagIndex);
1224
+ }
1225
+ const digestIndex = name.indexOf("@");
1226
+ if (digestIndex !== -1) {
1227
+ name = name.substring(0, digestIndex);
1228
+ }
1229
+ if ([...name].filter((c) => c === "/").length === 1) {
1230
+ name = `docker.io/${name}`;
1231
+ }
1232
+ return name;
1233
+ }
1234
+
1174
1235
  // src/client/common/contract/caller.ts
1175
1236
  var import_accounts2 = require("viem/accounts");
1176
1237
 
@@ -2207,27 +2268,55 @@ var ERC7702Delegator_default = [
2207
2268
  ];
2208
2269
 
2209
2270
  // src/client/common/contract/eip7702.ts
2271
+ var EXECUTE_BATCH_MODE = "0x0100000000000000000000000000000000000000000000000000000000000000";
2272
+ var GAS_LIMIT_BUFFER_PERCENTAGE = 20n;
2273
+ var GAS_PRICE_BUFFER_PERCENTAGE = 100n;
2274
+ function encodeExecuteBatchData(executions) {
2275
+ const encodedExecutions = (0, import_viem.encodeAbiParameters)(
2276
+ [
2277
+ {
2278
+ type: "tuple[]",
2279
+ components: [
2280
+ { name: "target", type: "address" },
2281
+ { name: "value", type: "uint256" },
2282
+ { name: "callData", type: "bytes" }
2283
+ ]
2284
+ }
2285
+ ],
2286
+ [executions]
2287
+ );
2288
+ return (0, import_viem.encodeFunctionData)({
2289
+ abi: ERC7702Delegator_default,
2290
+ functionName: "execute",
2291
+ args: [EXECUTE_BATCH_MODE, encodedExecutions]
2292
+ });
2293
+ }
2210
2294
  async function estimateBatchGas(options) {
2211
- const { publicClient, executions } = options;
2212
- const fees = await publicClient.estimateFeesPerGas();
2213
- const baseGas = 100000n;
2214
- const perExecutionGas = 50000n;
2215
- const estimatedGas = baseGas + BigInt(executions.length) * perExecutionGas;
2216
- const gasLimit = estimatedGas * 120n / 100n;
2217
- const maxFeePerGas = fees.maxFeePerGas;
2218
- const maxPriorityFeePerGas = fees.maxPriorityFeePerGas;
2295
+ const { publicClient, account, executions } = options;
2296
+ const executeBatchData = encodeExecuteBatchData(executions);
2297
+ const [gasTipCap, block, estimatedGas] = await Promise.all([
2298
+ publicClient.estimateMaxPriorityFeePerGas(),
2299
+ publicClient.getBlock(),
2300
+ publicClient.estimateGas({
2301
+ account,
2302
+ to: account,
2303
+ data: executeBatchData
2304
+ })
2305
+ ]);
2306
+ const baseFee = block.baseFeePerGas ?? 0n;
2307
+ const maxFeePerGas = (baseFee + gasTipCap) * (100n + GAS_PRICE_BUFFER_PERCENTAGE) / 100n;
2308
+ const gasLimit = estimatedGas * (100n + GAS_LIMIT_BUFFER_PERCENTAGE) / 100n;
2219
2309
  const maxCostWei = gasLimit * maxFeePerGas;
2220
- const maxCostEth = formatETH(maxCostWei);
2221
2310
  return {
2222
2311
  gasLimit,
2223
2312
  maxFeePerGas,
2224
- maxPriorityFeePerGas,
2313
+ maxPriorityFeePerGas: gasTipCap,
2225
2314
  maxCostWei,
2226
- maxCostEth
2315
+ maxCostEth: formatETH(maxCostWei)
2227
2316
  };
2228
2317
  }
2229
2318
  async function checkERC7702Delegation(publicClient, account, delegatorAddress) {
2230
- const code = await publicClient.getBytecode({ address: account });
2319
+ const code = await publicClient.getCode({ address: account });
2231
2320
  if (!code) {
2232
2321
  return false;
2233
2322
  }
@@ -2244,36 +2333,7 @@ async function executeBatch(options, logger) {
2244
2333
  if (!chain) {
2245
2334
  throw new Error("Wallet client must have a chain");
2246
2335
  }
2247
- const encodedExecutions = (0, import_viem.encodeAbiParameters)(
2248
- [
2249
- {
2250
- type: "tuple[]",
2251
- components: [
2252
- { name: "target", type: "address" },
2253
- { name: "value", type: "uint256" },
2254
- { name: "callData", type: "bytes" }
2255
- ]
2256
- }
2257
- ],
2258
- [executions]
2259
- );
2260
- const executeBatchMode = "0x0100000000000000000000000000000000000000000000000000000000000000";
2261
- let executeBatchData;
2262
- try {
2263
- executeBatchData = (0, import_viem.encodeFunctionData)({
2264
- abi: ERC7702Delegator_default,
2265
- functionName: "execute",
2266
- args: [executeBatchMode, encodedExecutions]
2267
- });
2268
- } catch {
2269
- const functionSignature = "execute(bytes32,bytes)";
2270
- const selector = (0, import_viem.keccak256)((0, import_viem.toBytes)(functionSignature)).slice(0, 10);
2271
- const encodedParams = (0, import_viem.encodeAbiParameters)(
2272
- [{ type: "bytes32" }, { type: "bytes" }],
2273
- [executeBatchMode, encodedExecutions]
2274
- );
2275
- executeBatchData = (0, import_viem.concat)([selector, encodedParams]);
2276
- }
2336
+ const executeBatchData = encodeExecuteBatchData(executions);
2277
2337
  const isDelegated2 = await checkERC7702Delegation(
2278
2338
  publicClient,
2279
2339
  account.address,
@@ -2406,12 +2466,23 @@ function stripHexPrefix(value) {
2406
2466
  }
2407
2467
 
2408
2468
  // src/client/common/utils/userapi.ts
2469
+ function isJsonObject(value) {
2470
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2471
+ }
2472
+ function readString(obj, key) {
2473
+ const v = obj[key];
2474
+ return typeof v === "string" ? v : void 0;
2475
+ }
2476
+ function readNumber(obj, key) {
2477
+ const v = obj[key];
2478
+ return typeof v === "number" && Number.isFinite(v) ? v : void 0;
2479
+ }
2409
2480
  var MAX_ADDRESS_COUNT = 5;
2410
2481
  var CanViewAppLogsPermission = "0x2fd3f2fe";
2411
2482
  var CanViewSensitiveAppInfoPermission = "0x0e67b22f";
2412
2483
  var CanUpdateAppProfilePermission = "0x036fef61";
2413
2484
  function getDefaultClientId() {
2414
- const version = true ? "0.1.2" : "0.0.0";
2485
+ const version = true ? "0.2.0-dev.1" : "0.0.0";
2415
2486
  return `ecloud-sdk/v${version}`;
2416
2487
  }
2417
2488
  var UserApiClient = class {
@@ -2445,6 +2516,31 @@ var UserApiClient = class {
2445
2516
  };
2446
2517
  });
2447
2518
  }
2519
+ /**
2520
+ * Get app details from UserAPI (includes releases and build/provenance info when available).
2521
+ *
2522
+ * Endpoint: GET /apps/:appAddress
2523
+ */
2524
+ async getApp(appAddress) {
2525
+ const endpoint = `${this.config.userApiServerURL}/apps/${appAddress}`;
2526
+ const res = await this.makeAuthenticatedRequest(endpoint);
2527
+ const raw = await res.json();
2528
+ if (!isJsonObject(raw)) {
2529
+ throw new Error("Unexpected /apps/:id response: expected object");
2530
+ }
2531
+ const id = readString(raw, "id");
2532
+ if (!id) {
2533
+ throw new Error("Unexpected /apps/:id response: missing 'id'");
2534
+ }
2535
+ const releasesRaw = raw.releases;
2536
+ const releases = Array.isArray(releasesRaw) ? releasesRaw.map((r) => transformAppRelease(r)).filter((r) => !!r) : [];
2537
+ return {
2538
+ id,
2539
+ creator: readString(raw, "creator"),
2540
+ contractStatus: readString(raw, "contract_status") ?? readString(raw, "contractStatus"),
2541
+ releases
2542
+ };
2543
+ }
2448
2544
  /**
2449
2545
  * Get available SKUs (instance types) from UserAPI
2450
2546
  */
@@ -2617,6 +2713,48 @@ Please check:
2617
2713
  };
2618
2714
  }
2619
2715
  };
2716
+ function transformAppReleaseBuild(raw) {
2717
+ if (!isJsonObject(raw)) return void 0;
2718
+ const depsRaw = raw.dependencies;
2719
+ const deps = isJsonObject(depsRaw) ? Object.fromEntries(
2720
+ Object.entries(depsRaw).flatMap(([digest, depRaw]) => {
2721
+ const parsed = transformAppReleaseBuild(depRaw);
2722
+ return parsed ? [[digest, parsed]] : [];
2723
+ })
2724
+ ) : void 0;
2725
+ return {
2726
+ buildId: readString(raw, "build_id") ?? readString(raw, "buildId"),
2727
+ billingAddress: readString(raw, "billing_address") ?? readString(raw, "billingAddress"),
2728
+ repoUrl: readString(raw, "repo_url") ?? readString(raw, "repoUrl"),
2729
+ gitRef: readString(raw, "git_ref") ?? readString(raw, "gitRef"),
2730
+ status: readString(raw, "status"),
2731
+ buildType: readString(raw, "build_type") ?? readString(raw, "buildType"),
2732
+ imageName: readString(raw, "image_name") ?? readString(raw, "imageName"),
2733
+ imageDigest: readString(raw, "image_digest") ?? readString(raw, "imageDigest"),
2734
+ imageUrl: readString(raw, "image_url") ?? readString(raw, "imageUrl"),
2735
+ provenanceJson: raw.provenance_json ?? raw.provenanceJson,
2736
+ provenanceSignature: readString(raw, "provenance_signature") ?? readString(raw, "provenanceSignature"),
2737
+ createdAt: readString(raw, "created_at") ?? readString(raw, "createdAt"),
2738
+ updatedAt: readString(raw, "updated_at") ?? readString(raw, "updatedAt"),
2739
+ errorMessage: readString(raw, "error_message") ?? readString(raw, "errorMessage"),
2740
+ dependencies: deps
2741
+ };
2742
+ }
2743
+ function transformAppRelease(raw) {
2744
+ if (!isJsonObject(raw)) return void 0;
2745
+ return {
2746
+ appId: readString(raw, "appId") ?? readString(raw, "app_id"),
2747
+ rmsReleaseId: readString(raw, "rmsReleaseId") ?? readString(raw, "rms_release_id"),
2748
+ imageDigest: readString(raw, "imageDigest") ?? readString(raw, "image_digest"),
2749
+ registryUrl: readString(raw, "registryUrl") ?? readString(raw, "registry_url"),
2750
+ publicEnv: readString(raw, "publicEnv") ?? readString(raw, "public_env"),
2751
+ encryptedEnv: readString(raw, "encryptedEnv") ?? readString(raw, "encrypted_env"),
2752
+ upgradeByTime: readNumber(raw, "upgradeByTime") ?? readNumber(raw, "upgrade_by_time"),
2753
+ createdAt: readString(raw, "createdAt") ?? readString(raw, "created_at"),
2754
+ createdAtBlock: readString(raw, "createdAtBlock") ?? readString(raw, "created_at_block"),
2755
+ build: raw.build ? transformAppReleaseBuild(raw.build) : void 0
2756
+ };
2757
+ }
2620
2758
 
2621
2759
  // src/client/common/abis/AppController.json
2622
2760
  var AppController_default = [
@@ -5114,6 +5252,97 @@ async function withSDKTelemetry(options, action) {
5114
5252
  }
5115
5253
 
5116
5254
  // src/client/modules/compute/app/deploy.ts
5255
+ async function prepareDeployFromVerifiableBuild(options, logger = defaultLogger) {
5256
+ return withSDKTelemetry(
5257
+ {
5258
+ functionName: "prepareDeployFromVerifiableBuild",
5259
+ skipTelemetry: options.skipTelemetry,
5260
+ properties: {
5261
+ environment: options.environment || "sepolia"
5262
+ }
5263
+ },
5264
+ async () => {
5265
+ if (!options.privateKey) throw new Error("privateKey is required for deployment");
5266
+ if (!options.imageRef) throw new Error("imageRef is required for deployment");
5267
+ if (!options.imageDigest) throw new Error("imageDigest is required for deployment");
5268
+ assertValidImageReference(options.imageRef);
5269
+ validateAppName(options.appName);
5270
+ validateLogVisibility(options.logVisibility);
5271
+ if (!/^sha256:[0-9a-f]{64}$/i.test(options.imageDigest)) {
5272
+ throw new Error(
5273
+ `imageDigest must be in format sha256:<64 hex>, got: ${options.imageDigest}`
5274
+ );
5275
+ }
5276
+ const { publicLogs } = validateLogVisibility(options.logVisibility);
5277
+ validateResourceUsageMonitoring(options.resourceUsageMonitoring);
5278
+ logger.debug("Performing preflight checks...");
5279
+ const preflightCtx = await doPreflightChecks(
5280
+ {
5281
+ privateKey: options.privateKey,
5282
+ rpcUrl: options.rpcUrl,
5283
+ environment: options.environment
5284
+ },
5285
+ logger
5286
+ );
5287
+ logger.debug("Checking quota availability...");
5288
+ await checkQuotaAvailable(preflightCtx);
5289
+ const salt = generateRandomSalt();
5290
+ logger.debug(`Generated salt: ${Buffer.from(salt).toString("hex")}`);
5291
+ logger.debug("Calculating app ID...");
5292
+ const appIDToBeDeployed = await calculateAppID(
5293
+ preflightCtx.privateKey,
5294
+ options.rpcUrl || preflightCtx.rpcUrl,
5295
+ preflightCtx.environmentConfig,
5296
+ salt
5297
+ );
5298
+ logger.info(``);
5299
+ logger.info(`App ID: ${appIDToBeDeployed}`);
5300
+ logger.info(``);
5301
+ const release = await createReleaseFromImageDigest(
5302
+ {
5303
+ imageRef: options.imageRef,
5304
+ imageDigest: options.imageDigest,
5305
+ envFilePath: options.envFilePath,
5306
+ instanceType: options.instanceType,
5307
+ environmentConfig: preflightCtx.environmentConfig,
5308
+ appId: appIDToBeDeployed
5309
+ },
5310
+ logger
5311
+ );
5312
+ logger.debug("Preparing deploy batch...");
5313
+ const batch = await prepareDeployBatch(
5314
+ {
5315
+ privateKey: preflightCtx.privateKey,
5316
+ rpcUrl: options.rpcUrl || preflightCtx.rpcUrl,
5317
+ environmentConfig: preflightCtx.environmentConfig,
5318
+ salt,
5319
+ release,
5320
+ publicLogs
5321
+ },
5322
+ logger
5323
+ );
5324
+ logger.debug("Estimating gas...");
5325
+ const gasEstimate = await estimateBatchGas({
5326
+ publicClient: batch.publicClient,
5327
+ account: batch.walletClient.account.address,
5328
+ executions: batch.executions
5329
+ });
5330
+ const data = {
5331
+ appId: batch.appId,
5332
+ salt: batch.salt,
5333
+ executions: batch.executions
5334
+ };
5335
+ return {
5336
+ prepared: {
5337
+ data,
5338
+ appName: options.appName,
5339
+ imageRef: options.imageRef
5340
+ },
5341
+ gasEstimate
5342
+ };
5343
+ }
5344
+ );
5345
+ }
5117
5346
  function validateDeployOptions(options) {
5118
5347
  if (!options.privateKey) {
5119
5348
  throw new Error("privateKey is required for deployment");
@@ -5334,7 +5563,7 @@ async function prepareDeploy(options, logger = defaultLogger) {
5334
5563
  logger.debug("Estimating gas...");
5335
5564
  const gasEstimate = await estimateBatchGas({
5336
5565
  publicClient: batch.publicClient,
5337
- environmentConfig: batch.environmentConfig,
5566
+ account: batch.walletClient.account.address,
5338
5567
  executions: batch.executions
5339
5568
  });
5340
5569
  const data = {
@@ -5424,6 +5653,81 @@ async function checkAppLogPermission(preflightCtx, appAddress, logger) {
5424
5653
  }
5425
5654
 
5426
5655
  // src/client/modules/compute/app/upgrade.ts
5656
+ async function prepareUpgradeFromVerifiableBuild(options, logger = defaultLogger) {
5657
+ return withSDKTelemetry(
5658
+ {
5659
+ functionName: "prepareUpgradeFromVerifiableBuild",
5660
+ skipTelemetry: options.skipTelemetry,
5661
+ properties: {
5662
+ environment: options.environment || "sepolia"
5663
+ }
5664
+ },
5665
+ async () => {
5666
+ logger.debug("Performing preflight checks...");
5667
+ const preflightCtx = await doPreflightChecks(
5668
+ {
5669
+ privateKey: options.privateKey,
5670
+ rpcUrl: options.rpcUrl,
5671
+ environment: options.environment
5672
+ },
5673
+ logger
5674
+ );
5675
+ const appID = validateUpgradeOptions(options);
5676
+ assertValidImageReference(options.imageRef);
5677
+ if (!/^sha256:[0-9a-f]{64}$/i.test(options.imageDigest)) {
5678
+ throw new Error(
5679
+ `imageDigest must be in format sha256:<64 hex>, got: ${options.imageDigest}`
5680
+ );
5681
+ }
5682
+ const { publicLogs } = validateLogVisibility(options.logVisibility);
5683
+ validateResourceUsageMonitoring(options.resourceUsageMonitoring);
5684
+ const envFilePath = options.envFilePath || "";
5685
+ logger.info("Preparing release (verifiable build, no local layering)...");
5686
+ const release = await createReleaseFromImageDigest(
5687
+ {
5688
+ imageRef: options.imageRef,
5689
+ imageDigest: options.imageDigest,
5690
+ envFilePath,
5691
+ instanceType: options.instanceType,
5692
+ environmentConfig: preflightCtx.environmentConfig,
5693
+ appId: appID
5694
+ },
5695
+ logger
5696
+ );
5697
+ logger.debug("Checking current log permission state...");
5698
+ const currentlyPublic = await checkAppLogPermission(preflightCtx, appID, logger);
5699
+ const needsPermissionChange = currentlyPublic !== publicLogs;
5700
+ logger.debug("Preparing upgrade batch...");
5701
+ const batch = await prepareUpgradeBatch({
5702
+ privateKey: preflightCtx.privateKey,
5703
+ rpcUrl: options.rpcUrl || preflightCtx.rpcUrl,
5704
+ environmentConfig: preflightCtx.environmentConfig,
5705
+ appId: appID,
5706
+ release,
5707
+ publicLogs,
5708
+ needsPermissionChange
5709
+ });
5710
+ logger.debug("Estimating gas...");
5711
+ const gasEstimate = await estimateBatchGas({
5712
+ publicClient: batch.publicClient,
5713
+ account: batch.walletClient.account.address,
5714
+ executions: batch.executions
5715
+ });
5716
+ const data = {
5717
+ appId: batch.appId,
5718
+ executions: batch.executions
5719
+ };
5720
+ return {
5721
+ prepared: {
5722
+ data,
5723
+ appId: appID,
5724
+ imageRef: options.imageRef
5725
+ },
5726
+ gasEstimate
5727
+ };
5728
+ }
5729
+ );
5730
+ }
5427
5731
  function validateUpgradeOptions(options) {
5428
5732
  if (!options.privateKey) {
5429
5733
  throw new Error("privateKey is required for upgrade");
@@ -5586,7 +5890,7 @@ async function prepareUpgrade(options, logger = defaultLogger) {
5586
5890
  logger.debug("Estimating gas...");
5587
5891
  const gasEstimate = await estimateBatchGas({
5588
5892
  publicClient: batch.publicClient,
5589
- environmentConfig: batch.environmentConfig,
5893
+ account: batch.walletClient.account.address,
5590
5894
  executions: batch.executions
5591
5895
  });
5592
5896
  const data = {
@@ -6406,6 +6710,24 @@ function createAppModule(ctx) {
6406
6710
  logger
6407
6711
  );
6408
6712
  },
6713
+ async prepareDeployFromVerifiableBuild(opts) {
6714
+ return prepareDeployFromVerifiableBuild(
6715
+ {
6716
+ privateKey,
6717
+ rpcUrl: ctx.rpcUrl,
6718
+ environment: ctx.environment,
6719
+ appName: opts.name,
6720
+ instanceType: opts.instanceType,
6721
+ envFilePath: opts.envFile,
6722
+ imageRef: opts.imageRef,
6723
+ imageDigest: opts.imageDigest,
6724
+ logVisibility: opts.logVisibility,
6725
+ resourceUsageMonitoring: opts.resourceUsageMonitoring,
6726
+ skipTelemetry
6727
+ },
6728
+ logger
6729
+ );
6730
+ },
6409
6731
  async executeDeploy(prepared, gas) {
6410
6732
  const account = (0, import_accounts5.privateKeyToAccount)(privateKey);
6411
6733
  const chain = getChainFromID(environment.chainID);
@@ -6466,6 +6788,24 @@ function createAppModule(ctx) {
6466
6788
  logger
6467
6789
  );
6468
6790
  },
6791
+ async prepareUpgradeFromVerifiableBuild(appId, opts) {
6792
+ return prepareUpgradeFromVerifiableBuild(
6793
+ {
6794
+ appId,
6795
+ privateKey,
6796
+ rpcUrl: ctx.rpcUrl,
6797
+ environment: ctx.environment,
6798
+ instanceType: opts.instanceType,
6799
+ envFilePath: opts.envFile,
6800
+ imageRef: opts.imageRef,
6801
+ imageDigest: opts.imageDigest,
6802
+ logVisibility: opts.logVisibility,
6803
+ resourceUsageMonitoring: opts.resourceUsageMonitoring,
6804
+ skipTelemetry
6805
+ },
6806
+ logger
6807
+ );
6808
+ },
6469
6809
  async executeUpgrade(prepared, gas) {
6470
6810
  const account = (0, import_accounts5.privateKeyToAccount)(privateKey);
6471
6811
  const chain = getChainFromID(environment.chainID);