Skip to content

pawanpaudel93/ao-deploy

Repository files navigation

ao-deploy

npm version npm downloads JSDocs License

A package for deploying AO contracts with support for both Node.js and web environments.

Features

  • 🚀 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

Installation

Basic Installation

Using npm

npm install ao-deploy --save-dev

Using pnpm

pnpm add ao-deploy --save-dev

Using yarn

yarn add ao-deploy --dev

Using bun

bun add ao-deploy --dev

Optional Dependencies

If 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           # bun

Usage

CLI

Note

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 command

Example: Deploy contract

ao-deploy process.lua -n tictactoe -w wallet.json --tags name1:value1 name2:value2

Example: Deploy contract with minify

Note

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 --minify

Example: Deploy contract with on-boot

ao-deploy process.lua -n tictactoe -w wallet.json --tags name1:value1 name2:value2 --on-boot

Example: Deploy blueprints

ao-deploy -n tictactoe -w wallet.json --blueprints arns token

Example: Deploy contracts with configuration

Note

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.ts

Deploy specific contracts:

ao-deploy aod.config.ts --deploy=contract_1,contract_3

Example: Build Contract

Note

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-only

Build 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 ./dist

Example: Build Contracts using Configuration

Note

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-only

Build specific contracts:

ao-deploy aod.config.ts --build=contract_1,contract_3 --build-only

Note

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'));"

API Usage

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:

Example: Node.js deployContract

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();
Parameters

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 format interval-(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 with count and delay properties. By default, it will retry up to 10 times with a 3000 milliseconds 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 when contractSrc is 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.

Example: Node.js deployContracts

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();

Web Usage Examples

For web/browser environments, you need to provide the contract source directly since file system access is not available:

Example: Web deployContract

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();

Example: Web deployContracts

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.

Related

Author

👤 Pawan Paudel

🤝 Contributing

Contributions, issues and feature requests are welcome! \ Feel free to check issues page.

Show your support

Give a ⭐️ if this project helped you!

Copyright © 2024 Pawan Paudel.

About

Deploy AO contracts with ease

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •