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.

Table of Contents

Features

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

Installation

Install Locally

npm install ao-deploy --save-dev
pnpm add ao-deploy --save-dev
yarn add ao-deploy --dev
bun add ao-deploy --dev

Use without installation

You can use ao-deploy without installing it locally by using package runners:

Using npx (npm):

npx ao-deploy process.lua -n tictactoe -w wallet.json

Using bunx (bun):

bunx ao-deploy process.lua -n tictactoe -w wallet.json

Using pnpm dlx (pnpm):

pnpm dlx ao-deploy process.lua -n tictactoe -w wallet.json

Using yarn dlx (yarn):

yarn dlx ao-deploy process.lua -n tictactoe -w wallet.json

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)
  --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 command

Basic Deployment

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

Advanced Options

Minify Contract

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
Deploy with On-Boot
ao-deploy process.lua -n tictactoe -w wallet.json --tags name1:value1 name2:value2 --on-boot
Deploy Blueprints
ao-deploy -n tictactoe -w wallet.json --blueprints arns token

Browser Wallet

Important

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
Advanced Browser Configuration
# 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 MyProcess
Using a Configuration File
export 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.ts

Configuration File

Note

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

Deploy specific contracts:

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

Build Contracts

Note

Contract building is only available in Node.js environments. For web environments, you need to bundle your contracts using your own build process.

Build to Default Directory
aod src/process.lua -n my-process --build-only
Build to Custom 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
Build Using Configuration File

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

deployContract

Deploy a single contract using the deployContract function.

Basic Deployment (Node.js)
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();
Browser Wallet (Node.js)
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();
Web Deployment

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

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 3 times with a 1000 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, 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.

deployContracts

Deploy multiple contracts concurrently using the deployContracts function.

Multiple Contracts (Node.js)
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();
Multiple Contracts (Web)

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

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

  •  
  •  
  •  
  •