A package for deploying AO contracts with support for both Node.js and web environments.
- 🚀 Build and deploy contracts with ease
- 🌐 Cross-platform support
- 🔐 Browser wallet support (Wander or other compatible wallet) for secure signing
- 🔧 Custom LUA_PATH support
- 📦 LuaRocks package support
- ⚙️ Flexible deployment configuration
- 🔄 Concurrent deployments with retry options
- 📝 Contract minification and transformation
- 🧩 Blueprint support
- 🛠️ CLI and API interfaces
npm install ao-deploy --save-dev
pnpm add ao-deploy --save-dev
yarn add ao-deploy --dev
bun add ao-deploy --devYou can use ao-deploy without installing it locally by using package runners:
Using npx (npm):
npx ao-deploy process.lua -n tictactoe -w wallet.jsonUsing bunx (bun):
bunx ao-deploy process.lua -n tictactoe -w wallet.jsonUsing pnpm dlx (pnpm):
pnpm dlx ao-deploy process.lua -n tictactoe -w wallet.jsonUsing yarn dlx (yarn):
yarn dlx ao-deploy process.lua -n tictactoe -w wallet.jsonIf you plan to use the --minify option, you'll need to install lua-format:
npm install lua-format --save-dev # npm
pnpm add lua-format --save-dev # pnpm
yarn add lua-format --dev # yarn
bun add lua-format --dev # bunNote
The CLI is only available in Node.js environments. For web environments, use the API directly.
Usage: ao-deploy [options] <contractOrConfigPath>
Deploy AO contracts using a CLI.
Arguments:
contractOrConfigPath Path to the main contract file or deployment configuration.
Options:
-V, --version output the version number
-n, --name [name] Specify the process name. (default: "default")
-w, --wallet [wallet] Path to the wallet JWK file. (Autogenerated if not passed)
--use-browser-wallet Use browser wallet (Wander or other compatible wallet) for signing transactions.
--browser [browser] Browser to use for signing transactions. (default: "system default")
--browser-profile [profile] Browser profile to use for signing transactions.
-l, --lua-path [luaPath] Specify the Lua modules path seperated by semicolon.
-d, --deploy [deploy] List of deployment configuration names, separated by commas.
-b, --build [build] List of deployment configuration names, separated by commas.
-s, --scheduler [scheduler] Scheduler to be used for the process. (default: "_GQ33BkPtZrqxA84vM8Zk-N2aO0toNNu_C-l-rawrBA")
-m, --module [module] Module source for spawning the process.
-c, --cron [interval] Cron interval for the process (e.g. 1-minute, 5-minutes).
-t, --tags [tags...] Additional tags for spawning the process.
-p, --process-id [processId] Specify process Id of existing process.
--build-only Bundle the contract into a single file and store it in the process-dist directory.
--out-dir [outDir] Used with --build-only to output the single bundle contract file to a specified directory.
--gateway-url [url] Custom Gateway URL to connect to. (default: "https://arweave.net")
--cu-url [url] Custom Compute Unit (CU) URL to connect to. (default: "https://cu.ao-testnet.xyz")
--mu-url [url] Custom Messenger Unit (MU) URL to connect to. (default: "https://mu.ao-testnet.xyz")
--concurrency [limit] Concurrency limit for deploying multiple processes. (default: 5)
--sqlite Use sqlite aos module when spawning new process.
--retry-count [count] Number of retries for deploying contract. (default: 3)
--retry-delay [delay] Delay between retries in milliseconds. (default: 1000)
--minify Reduce the size of the contract before deployment. (default: false)
--on-boot Load contract when process is spawned. (default: false)
--blueprints [blueprints...] Blueprints to use for the contract.
--force-spawn Force spawning a new process without checking for existing ones. (default: false)
-h, --help display help for commandao-deploy process.lua -n tictactoe -w wallet.json --tags name1:value1 name2:value2Note
Make sure to install lua-format as mentioned in Optional Dependencies section.
ao-deploy process.lua -n tictactoe -w wallet.json --tags name1:value1 name2:value2 --minifyao-deploy process.lua -n tictactoe -w wallet.json --tags name1:value1 name2:value2 --on-bootao-deploy -n tictactoe -w wallet.json --blueprints arns tokenImportant
When deploying multiple contracts with browser wallets, the first browser configuration found in the deployment configs will be used for all browser deployments. This ensures a single browser session is shared across all deployments.
Use your browser wallet for secure transaction signing:
ao-deploy process.lua --use-browser-wallet -n MyProcess# Use specific browser
ao-deploy process.lua --use-browser-wallet --browser firefox -n MyProcess
# Use specific browser profile
ao-deploy process.lua --use-browser-wallet --browser chrome --browser-profile "Profile 1" -n MyProcessexport default defineConfig({
main: {
name: "my-process",
contractPath: "./src/main.lua",
wallet: "browser", // Use browser wallet for signing
browserConfig: {
browser: "chrome", // Optional: specify browser (chrome, firefox, edge, brave, safari, opera, zen, vivaldi)
browserProfile: "Profile 1" // Optional: specify browser profile
}
},
});Then deploy with:
ao-deploy ao.config.tsNote
Configuration files are only supported in Node.js environments. For web environments, use the API directly with individual contract configurations.
Deploy multiple contracts using a configuration file:
// aod.config.ts
import { defineConfig } from "ao-deploy";
const wallet = "wallet.json";
const luaPath = "./?.lua;./src/?.lua";
const config = defineConfig({
contract_1: {
luaPath,
name: `contract-1`,
contractPath: "contract-1.lua",
wallet,
minify: true // Minify the contract before deployment
},
contract_2: {
luaPath,
name: `contract-2`,
contractPath: "contract-2.lua",
wallet: "browser", // Use browser wallet
browserConfig: {
browser: "brave", // Use Brave browser
browserProfile: "Work" // Use profile 1
},
// Custom source transformer function
contractTransformer: (source) => {
// Example: Remove all comments from the source code
return source.replace(/\s*--.*\n/g, "");
}
},
contract_3: {
luaPath,
name: `contract-3`,
contractPath: "contract-3.lua",
wallet
}
});
export default config;Deploy all specified contracts:
ao-deploy aod.config.tsDeploy specific contracts:
ao-deploy aod.config.ts --deploy=contract_1,contract_3Note
Contract building is only available in Node.js environments. For web environments, you need to bundle your contracts using your own build process.
aod src/process.lua -n my-process --build-onlyaod src/process.lua -n my-process --build-only --out-dir <PATH>
aod src/process.lua -n my-process --build-only --out-dir ./distNote
Configuration-based building is only available in Node.js environments.
To Build contracts using config, take a look at below provided example
Here is an example using a deployment configuration:
// aod.config.ts
import { defineConfig } from "ao-deploy";
const luaPath = "./?.lua;./src/?.lua";
const config = defineConfig({
contract_1: {
luaPath,
name: `contract-1`,
contractPath: "contract-1.lua",
outDir: "./dist"
},
contract_2: {
luaPath,
name: `contract-2`,
contractPath: "contract-2.lua",
outDir: "./dist"
},
contract_3: {
luaPath,
name: `contract-3`,
contractPath: "contract-3.lua",
outDir: "./dist"
}
});
export default config;Build all specified contracts:
ao-deploy aod.config.ts --build-onlyBuild specific contracts:
ao-deploy aod.config.ts --build=contract_1,contract_3 --build-onlyNote
A wallet is generated and saved if not passed.
Retrieve the generated wallet path:
node -e "const path = require('path'); const os = require('os'); console.log(path.resolve(os.homedir(), '.aos.json'));"Deploy a single contract using the deployContract function.
import { deployContract } from "ao-deploy";
async function main() {
try {
const { messageId, processId } = await deployContract({
name: "demo",
wallet: "wallet.json",
contractPath: "process.lua",
tags: [{ name: "Custom", value: "Tag" }],
retry: {
count: 10,
delay: 3000
}
});
const processUrl = `https://www.ao.link/#/entity/${processId}`;
console.log(`Deployed Process: ${processUrl}`);
if (messageId) {
const messageUrl = `https://www.ao.link/#/message/${messageId}`;
console.log(`Deployment Message: ${messageUrl}`);
}
} catch (error: any) {
console.log(
`Deployment failed!: ${error?.message ?? "Failed to deploy contract!"}\n`
);
}
}
main();import { deployContract } from "ao-deploy";
async function main() {
try {
const { messageId, processId } = await deployContract({
name: "demo",
wallet: "browser", // Use browser wallet
contractPath: "process.lua",
browserConfig: {
browser: "chrome", // Optional: specify browser
browserProfile: "Profile 1" // Optional: specify browser profile
},
tags: [{ name: "Custom", value: "Tag" }],
retry: {
count: 10,
delay: 3000
}
});
const processUrl = `https://www.ao.link/#/entity/${processId}`;
console.log(`Deployed Process: ${processUrl}`);
if (messageId) {
const messageUrl = `https://www.ao.link/#/message/${messageId}`;
console.log(`Deployment Message: ${messageUrl}`);
}
} catch (error: any) {
console.log(
`Deployment failed!: ${error?.message ?? "Failed to deploy contract!"}\n`
);
}
}
main();Note
For web/browser environments, you need to provide the contract source directly since file system access is not available.
import { deployContract } from "ao-deploy/web";
async function main() {
try {
// Contract source as a string (loaded from your build process, CDN, etc.)
// Simple AO process that responds to ping messages with "pong"
const contractSrc = `
Handlers.add("ping", function(msg)
return ao.send({
Action = "Pong",
Target = msg.From,
Data = "pong"
})
end)
`;
const { messageId, processId } = await deployContract({
name: "web-demo",
contractSrc: contractSrc,
tags: [{ name: "Environment", value: "Web" }],
retry: {
count: 5,
delay: 2000
}
});
const processUrl = `https://www.ao.link/#/entity/${processId}`;
console.log(`Deployed Process: ${processUrl}`);
if (messageId) {
const messageUrl = `https://www.ao.link/#/message/${messageId}`;
console.log(`Deployment Message: ${messageUrl}`);
}
} catch (error: any) {
console.log(
`Deployment failed!: ${error?.message ?? "Failed to deploy contract!"}\n`
);
}
}
main();The deployContract function accepts the following parameters within the DeployArgs object:
Common Parameters (Node.js & Web):
name(optional): The process name to spawn. Defaults to "default".contractSrc(optional): The contract source code as a string. Required for web environments.module(optional): The module source to use. Defaults to fetching from the AOS's GitHub repository.scheduler(optional): The scheduler to use for the process. Defaults to_GQ33BkPtZrqxA84vM8Zk-N2aO0toNNu_C-l-rawrBA.tags(optional): Additional tags to use for spawning the process.cron(optional): The cron interval for the process, e.g., "1-minute", "5-minutes". Use formatinterval-(second, seconds, minute, minutes, hour, hours, day, days, month, months, year, years, block, blocks, Second, Seconds, Minute, Minutes, Hour, Hours, Day, Days, Month, Months, Year, Years, Block, Blocks)retry(optional): Retry options withcountanddelayproperties. By default, it will retry up to3times with a1000milliseconds delay between attempts.processId(optional): The process id of existing process.minify(optional): Reduce the size of the contract before deployment.contractTransformer(optional): Custom function to transform source code before deployment.onBoot(optional): Load contract when process is spawned. (default: false)silent(optional): Disable logging to console. (default: false)blueprints(optional): Blueprints to use for the contract.forceSpawn(optional): Force spawning a new process without checking for existing ones. (default: false)
Node.js Only Parameters:
contractPath: The path to the contract's main file. Required for Node.js whencontractSrcis not provided.wallet(optional): The wallet path, JWK itself, or "browser" to use browser wallet (Autogenerated if not passed).luaPath(optional): The path to the Lua modules seperated by semicolon.browserConfig(optional): Browser configuration for browser wallet usage.browser(optional): Browser to use ("chrome", "firefox", "edge", "brave", "safari", "opera", "zen", "vivaldi", or custom string).browserProfile(optional): Browser profile to use for signing transactions.
Note
In web environments, you must provide contractSrc directly as a string. The contractPath, wallet, and luaPath parameters are not supported in web environments.
Deploy multiple contracts concurrently using the deployContracts function.
import { deployContracts } from "ao-deploy";
async function main() {
try {
const results = await deployContracts(
[
{
name: "demo1",
wallet: "wallet.json",
contractPath: "process1.lua",
tags: [{ name: "Custom", value: "Tag" }],
retry: {
count: 10,
delay: 3000
}
},
{
name: "demo2",
wallet: "wallet.json",
contractPath: "process2.lua",
tags: [{ name: "Custom", value: "Tag" }],
retry: {
count: 10,
delay: 3000
}
}
],
2
);
results.forEach((result, idx) => {
if (result.status === "fulfilled") {
const { processId, messageId } = result.value;
const processUrl = `https://www.ao.link/#/entity/${processId}`;
console.log(`Deployed Process: ${processUrl}`);
if (messageId) {
const messageUrl = `https://www.ao.link/#/message/${messageId}`;
console.log(`Deployment Message: ${messageUrl}`);
}
} else {
console.log(`Failed to deploy contract!: ${result.reason}\n`);
}
});
} catch (error: any) {
console.log(
`Deployment failed!: ${error?.message ?? "Failed to deploy contract!"}\n`
);
}
}
main();Note
For web/browser environments, you need to provide the contract source directly since file system access is not available.
import { deployContracts } from "ao-deploy/web";
async function main() {
try {
const contract1Src = `
-- Simple counter process
local count = 0
Handlers.add("increment", function(msg)
count = count + 1
return ao.send({
Action = "Count",
Target = msg.From,
Data = tostring(count)
})
end)
`;
const contract2Src = `
-- Simple echo process
Handlers.add("echo", function(msg)
return ao.send({
Action = "Echo",
Target = msg.From,
Data = msg.Data or "No data provided"
})
end)
`;
const results = await deployContracts(
[
{
name: "web-demo1",
contractSrc: contract1Src,
tags: [{ name: "Environment", value: "Web" }],
retry: {
count: 5,
delay: 2000
}
},
{
name: "web-demo2",
contractSrc: contract2Src,
tags: [{ name: "Environment", value: "Web" }],
retry: {
count: 5,
delay: 2000
}
}
],
2
);
results.forEach((result, idx) => {
if (result.status === "fulfilled") {
const { processId, messageId } = result.value;
const processUrl = `https://www.ao.link/#/entity/${processId}`;
console.log(`Deployed Process ${idx + 1}: ${processUrl}`);
if (messageId) {
const messageUrl = `https://www.ao.link/#/message/${messageId}`;
console.log(`Deployment Message: ${messageUrl}`);
}
} else {
console.log(`Failed to deploy contract ${idx + 1}!: ${result.reason}\n`);
}
});
} catch (error: any) {
console.log(
`Deployment failed!: ${error?.message ?? "Failed to deploy contract!"}\n`
);
}
}
main();- create-ao-contract: A CLI tool for scaffolding AO contracts.
- node-arweave-wallet: A library for interacting with Arweave browser wallets.
👤 Pawan Paudel
- Github: @pawanpaudel93
Contributions, issues and feature requests are welcome! \ Feel free to check issues page.
Give a ⭐️ if this project helped you!
Copyright © 2024 Pawan Paudel.