Initialize Contract

Initialize Contract

The 1st step is to initialize your new contract. xSuite makes initialization super simple.

To create a new blank contract:

xsuite new --dir <DIR>

To create a new contract from a starter contract (audited by Arda):

xsuite new --starter <STARTER> --dir <DIR>

Starter contracts are a great starting point for your new smart contract. They will save you significant time setting up the codebase and writing the initial logic. They are audited by Arda. Available starter contracts:

Manual setup

You can also setup your new contract without using the CLI.

Create a new directory and init a package there:

mkdir my-contract
cd my-contract
npm init -y

Add xsuite package and we also recommend adding TypeScript (typescript to type-check and tsx to run .ts files):

npm i -D xsuite typescript tsx

Building and testing

Add vitest package to run tests:

npm i -D vitest

Add the following scripts in the package.json file:

  "scripts": {
    "build": "xsuite build",
    "test": "vitest run",
    "typecheck": "tsc --noEmit"
  },

Create the tests directory:

mkdir tests

Create the first test file under tests/contract.test.ts, with the following content:

import { test, beforeEach, afterEach } from "vitest";
import { assertAccount, LSWorld, LSWallet, LSContract } from "xsuite";
 
let world: LSWorld;
let deployer: LSWallet;
let contract: LSContract;
 
beforeEach(async () => {
  world = await LSWorld.start();
  deployer = await world.createWallet();
  ({ contract } = await deployer.deployContract({
    code: "file:output/contract.wasm",
    codeMetadata: [],
    gasLimit: 10_000_000,
  }));
});
 
afterEach(async () => {
  world.terminate();
});
 
test("Test", async () => {
  assertAccount(await contract.getAccountWithKvs(), {
    balance: 0n,
    kvs: [],
  });
});

At this point, you can build the contract using npm run build and run tests with npm run test.

Interacting

Interactions use commander package to easily declare CLI commands:

npm i -D commander

Add the following scripts in the scripts of the package.json file:

"interact:devnet": "CHAIN=devnet tsx interact/index.ts",
"interact:testnet": "CHAIN=testnet tsx interact/index.ts",
"interact:mainnet": "CHAIN=mainnet tsx interact/index.ts",

Create the interact/data.json file with the following content:

{
  "code": "file:output/contract.wasm",
  "address": {
    "devnet": "",
    "testnet": "",
    "mainnet": ""
  }
}

Create the interact/index.ts file with the following content:

import { Command } from "commander";
import { envChain, World } from "xsuite";
import data from "./data.json";
 
const world = World.new({
  chainId: envChain.id(),
});
 
const loadWallet = () => world.newWalletFromFile("wallet.json");
 
const program = new Command();
 
program.command("deploy").action(async () => {
  const wallet = await loadWallet();
  const result = await wallet.deployContract({
    code: data.code,
    codeMetadata: ["upgradeable"],
    gasLimit: 20_000_000,
  });
  console.log("Result:", result);
});
 
program.command("upgrade").action(async () => {
  const wallet = await loadWallet();
  const result = await wallet.upgradeContract({
    callee: envChain.select(data.address),
    code: data.code,
    codeMetadata: ["upgradeable"],
    gasLimit: 20_000_000,
  });
  console.log("Result:", result);
});
 
program.command("ClaimDeveloperRewards").action(async () => {
  const wallet = await loadWallet();
  const result = await wallet.callContract({
    callee: envChain.select(data.address),
    funcName: "ClaimDeveloperRewards",
    gasLimit: 10_000_000,
  });
  console.log("Result:", result);
});
 
program.parse(process.argv);

At this point, you should be able to run interactions. For example, if you want to deploy the contract on devnet: npm run interact:devnet deploy.

Note: The interactions use a wallet.json file which can be generated using xsuite new-wallet --wallet wallet.json.