---
title: "Deploy Scripts"
description: "Create ordered, fee-aware TypeScript deploy scripts for Intelligent Contracts."
source: https://docs.genlayer.com/developers/intelligent-contracts/deploying/deploy-scripts
last_updated: 2026-09-03
---

# Deploy Scripts

Deploy scripts automate multi-contract deployments, constructor configuration, and follow-up writes. The CLI loads TypeScript or JavaScript files from `deploy/` in filename order and passes a configured GenLayerJS client to each script.

## File order

```text
your-project/
├── deploy/
│   ├── 001_deploy_main_contract.ts
│   ├── 002_deploy_helper_contract.ts
│   └── 003_configure_contracts.ts
├── contracts/
└── fee-profile.json
```

Use numeric prefixes because scripts execute alphabetically. A later script should not assume an earlier transaction merely returned an ID; the earlier script must wait for and verify its required lifecycle outcome.

## Fee-aware deploy helper

On a fee-charging deployment, raw `deployContract` and `writeContract` calls need the estimate produced from the matching profile entry. This helper converts a JSON profile entry into live estimate options:

```typescript
import type { GenLayerClient } from 'genlayer-js/types';

type ProfileEntry = {
  leaderTimeunitsAllocation: string;
  validatorTimeunitsAllocation: string;
  executionBudgetPerRound: string;
  totalMessageFees?: string;
  rotationsPerRound?: string;
};

async function quoteProfile(
  client: GenLayerClient<any>,
  entry: ProfileEntry,
  appealRounds = 1n,
) {
  const rotationsPerRound = BigInt(entry.rotationsPerRound ?? '0');
  return client.estimateTransactionFees({
    leaderTimeunitsAllocation: BigInt(entry.leaderTimeunitsAllocation),
    validatorTimeunitsAllocation: BigInt(entry.validatorTimeunitsAllocation),
    executionBudgetPerRound: BigInt(entry.executionBudgetPerRound),
    totalMessageFees: BigInt(entry.totalMessageFees ?? '0'),
    appealRounds,
    rotations: Array.from(
      { length: Number(appealRounds) + 1 },
      () => rotationsPerRound,
    ),
  });
}
```

The committed profile supplies measured quantities; `estimateTransactionFees` reads current network prices and ceilings. See [Fee Profiling and Estimation](/developers/decentralized-applications/fee-profiling-and-estimation).

## Basic deploy script

```typescript
import { readFileSync } from 'node:fs';
import { isSuccessful } from 'genlayer-js';
import type { DecodedDeployData, GenLayerClient } from 'genlayer-js/types';
import feeProfile from '../fee-profile.json';

export default async function main(client: GenLayerClient<any>) {
  const code = new Uint8Array(
    readFileSync(new URL('../contracts/my_contract.py', import.meta.url)),
  );
  const estimate = await quoteProfile(client, feeProfile.deploy);

  const txId = await client.deployContract({
    code,
    args: [],
    fees: {
      distribution: estimate.distribution,
      feeValue: estimate.feeValue,
    },
  });

  const transaction = await client.waitForFinalization({ hash: txId });
  if (!isSuccessful(transaction)) {
    throw new Error(
      `Deployment failed: ${transaction.statusName} / ${transaction.txExecutionResultName}`,
    );
  }

  const decoded = transaction.txDataDecoded as DecodedDeployData | undefined;
  const contractAddress = decoded?.contractAddress ?? transaction.recipient;
  if (!contractAddress) throw new Error('Finalized deployment has no contract address');

  console.log('Contract deployed', { txId, contractAddress });
  return contractAddress;
}
```

> **Note:**
> `initializeConsensusSmartContract()` is deprecated on the v2 client. The consensus deployment comes from the selected chain definition; deploy scripts should not initialize or reset it.

## Multi-step configuration

Use the same rule for follow-up writes: select the method profile, estimate against the live policy, submit, and verify the execution result.

```typescript
async function configureContract(
  client: GenLayerClient<any>,
  mainAddress: `0x${string}`,
  helperAddress: `0x${string}`,
) {
  const args = [helperAddress];
  const estimate = await quoteProfile(
    client,
    feeProfile.methods.setHelperContract,
  );

  const txId = await client.writeContract({
    address: mainAddress,
    functionName: 'setHelperContract',
    args,
    fees: {
      distribution: estimate.distribution,
      feeValue: estimate.feeValue,
    },
  });

  const transaction = await client.waitForFinalization({ hash: txId });
  if (!isSuccessful(transaction)) {
    throw new Error(
      `Configuration failed: ${transaction.statusName} / ${transaction.txExecutionResultName}`,
    );
  }
}
```

Keep all addresses and transaction IDs in the deployment output or a deployment manifest. If a process stops after submission, resume tracking the recorded transaction ID instead of blindly sending the same deploy or write again.

## Run scripts

Select and verify the network before executing the directory:

```bash
genlayer network set studio-dev
genlayer network info
genlayer deploy
```

For stable Studio use `studionet`; for a local stack use `localnet`. Studio-dev requires the matching release-candidate CLI and SDK. See [Network Configuration](./network-configuration).

## Related

- [CLI Deployment](./cli-deployment)
- [Network Configuration](./network-configuration)
- [Writing to Intelligent Contracts](/developers/decentralized-applications/writing-data)
- [Fee Outcomes and Debugging](/developers/decentralized-applications/fee-outcomes-and-debugging)
