A package for deploying AO contracts with support for both Node.js and web environments.
- 🚀 Build and deploy contracts with ease
- 🌐 Cross-platform support
- 🔧 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-devpnpm add ao-deploy --save-devyarn add ao-deploy --devbun add ao-deploy --devIf 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)
-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: 10)
--retry-delay [delay] Delay between retries in milliseconds. (default: 3000)
--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 tokenNote
Configuration files are only supported in Node.js environments. For web environments, use the API directly with individual contract configurations.
Here is an example using a deployment configuration:
// 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,
// 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.
To Build contracts and produce single bundle lua file, take a look at below provided commands
Build contract and save to default(process-dist) directory:
aod src/process.lua -n my-process --build-onlyBuild contract and save to specific directory:
aod 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'));"To deploy a contract, you need to import and call the deployContract function from your script. Here are examples for both Node.js and web environments:
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();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 to10times with a3000milliseconds 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 or JWK itself (Autogenerated if not passed).luaPath(optional): The path to the Lua modules seperated by semicolon.
Note
In web environments, you must provide contractSrc directly as a string. The contractPath, wallet, and luaPath parameters are not supported in web environments.
To deploy contracts, you need to import and call the deployContracts function from your script. Here is a basic example:
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();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();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();Note
In web environments, you must provide the contractSrc parameter directly as a string. The contractPath parameter is not supported in web environments.
- create-ao-contract: A CLI tool for scaffolding AO contracts.
👤 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.