Deploy Scripts
For more complex deployment workflows, use deploy scripts.
Script Structure
Create TypeScript or JavaScript files in the deploy/
directory:
your-project/
├── deploy/
│ ├── 001_deploy_main_contract.ts
│ ├── 002_setup_configuration.ts
│ └── 003_initialize_data.ts
└── contracts/
└── my_contract.py
⚠️
Deploy scripts are executed in alphabetical order. Use numeric prefixes (001_, 002_) to control execution order.
Basic Deploy Script
Here's a template for a deploy script (deploy/deployScript.ts
):
import { readFileSync } from "fs";
import path from "path";
import {
TransactionHash,
TransactionStatus,
GenLayerClient,
DecodedDeployData,
GenLayerChain
} from "genlayer-js/types";
import { testnetAsimov } from "genlayer-js/chains";
export default async function main(client: GenLayerClient<any>) {
// Read the contract file
const filePath = path.resolve(process.cwd(), "contracts/my_contract.py");
const contractCode = new Uint8Array(readFileSync(filePath));
// Initialize consensus
await client.initializeConsensusSmartContract();
// Deploy the contract
const deployTransaction = await client.deployContract({
code: contractCode,
args: [], // Constructor arguments
});
// Wait for deployment confirmation
const receipt = await client.waitForTransactionReceipt({
hash: deployTransaction as TransactionHash,
retries: 200,
});
// Check deployment success
if (
receipt.statusName !== TransactionStatus.ACCEPTED &&
receipt.statusName !== TransactionStatus.FINALIZED
) {
throw new Error(`Deployment failed. Receipt: ${JSON.stringify(receipt)}`);
}
// Receipt structure differs between TestnetAsimov and localnet/studionet
const deployedContractAddress =
(client.chain as GenLayerChain).id !== testnetAsimov.id
? receipt.data.contract_address
: (receipt.txDataDecoded as DecodedDeployData)?.contractAddress;
console.log("Contract deployed successfully!", {
"Transaction Hash": deployTransaction,
"Contract Address": deployedContractAddress,
});
return deployedContractAddress;
}
Advanced Deploy Script with Configuration
import { readFileSync } from "fs";
import path from "path";
import {
TransactionHash,
TransactionStatus,
GenLayerClient,
DecodedDeployData,
GenLayerChain
} from "genlayer-js/types";
import { testnetAsimov } from "genlayer-js/chains";
export default async function main(client: GenLayerClient<any>) {
console.log("🚀 Starting deployment process...");
// Deploy main contract
const mainContractAddress = await deployContract(
client,
"contracts/main_contract.py",
["Initial Config", 1000]
);
// Deploy helper contract
const helperContractAddress = await deployContract(
client,
"contracts/helper_contract.py",
[mainContractAddress]
);
// Configure the main contract
await configureContract(client, mainContractAddress, helperContractAddress);
console.log("✅ Deployment completed successfully!");
console.log({
mainContract: mainContractAddress,
helperContract: helperContractAddress,
});
}
async function deployContract(
client: GenLayerClient<any>,
contractPath: string,
args: any[] = []
): Promise<string> {
const filePath = path.resolve(process.cwd(), contractPath);
const contractCode = new Uint8Array(readFileSync(filePath));
await client.initializeConsensusSmartContract();
const deployTransaction = await client.deployContract({
code: contractCode,
args,
});
const receipt = await client.waitForTransactionReceipt({
hash: deployTransaction as TransactionHash,
retries: 200,
});
// Check deployment success
if (
receipt.statusName !== TransactionStatus.ACCEPTED &&
receipt.statusName !== TransactionStatus.FINALIZED
) {
throw new Error(`Deployment failed for ${contractPath}. Receipt: ${JSON.stringify(receipt)}`);
}
// Receipt structure differs between TestnetAsimov and localnet/studionet
const deployedContractAddress =
(client.chain as GenLayerChain).id !== testnetAsimov.id
? receipt.data.contract_address
: (receipt.txDataDecoded as DecodedDeployData)?.contractAddress;
return deployedContractAddress;
}
async function configureContract(
client: GenLayerClient<any>,
mainAddress: string,
helperAddress: string
) {
// Example configuration call
const hash = await client.writeContract({
address: mainAddress as any,
functionName: "setHelperContract",
args: [helperAddress],
value: 0n,
});
await client.waitForTransactionReceipt({
hash,
retries: 100,
interval: 5000,
});
}
Running Deploy Scripts
Execute all deploy scripts in order:
genlayer deploy
The CLI will automatically:
- Find all
.ts
and.js
files in thedeploy/
directory - Sort them numerically by filename prefix (001_, 002_, etc.)
- Execute them in order
- Pass a configured GenLayer client to each script
Script Organization
Recommended File Naming
deploy/
├── 001_core_contracts.ts # Core infrastructure
├── 002_token_contracts.ts # Token-related contracts
├── 003_governance.ts # Governance setup
├── 004_configure_system.ts # System configuration
└── 999_verify_deployment.ts # Post-deployment verification
Error Handling
Always include proper error handling in deploy scripts:
export default async function main(client: GenLayerClient<any>) {
try {
await client.initializeConsensusSmartContract();
const deployTransaction = await client.deployContract({
code: contractCode,
args: [],
});
const receipt = await client.waitForTransactionReceipt({
hash: deployTransaction as TransactionHash,
retries: 200,
});
// Check deployment success
if (
receipt.statusName !== TransactionStatus.ACCEPTED &&
receipt.statusName !== TransactionStatus.FINALIZED
) {
throw new Error(`Deployment failed: ${JSON.stringify(receipt)}`);
}
// Receipt structure differs between TestnetAsimov and localnet/studionet
const deployedContractAddress =
(client.chain as GenLayerChain).id !== testnetAsimov.id
? receipt.data.contract_address
: (receipt.txDataDecoded as DecodedDeployData)?.contractAddress;
return deployedContractAddress;
} catch (error) {
console.error("Deployment failed:", error);
throw error;
}
}
Next Steps
- Learn about different Network Configuration
- Configure CLI deployments with CLI Deployment