Initialize Contract
The 1st step is to initialize your new contract. xSuite CLI 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:
-
blank (opens in a new tab): An empty contract that comes fully set up with tests and blockchain interactions.
xsuite new --starter blank --dir <DIR> -
vested-transfers (opens in a new tab): A contract for vested transfers, with tests and blockchain interactions.
xsuite new --starter vested-transfers --dir <DIR>
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 -yAdd xsuite package and we also recommend adding TypeScript (typescript to type-check and tsx to run .ts files):
npm i -D xsuite typescript tsxBuilding and testing
Add vitest package to run tests:
npm i -D vitestAdd the following scripts in the package.json file:
"scripts": {
"build": "xsuite build",
"test": "vitest run",
"typecheck": "tsc --noEmit"
},Create the tests directory:
mkdir testsCreate the first test file under tests/contract.test.ts, with the following content:
import { test, beforeEach, afterEach } from "vitest";
import { assertAccount, SWorld, SWallet, SContract } from "xsuite";
let world: SWorld;
let deployer: SWallet;
let contract: SContract;
beforeEach(async () => {
world = await SWorld.start();
deployer = await world.createWallet();
({ contract } = await deployer.deployContract({
code: "file:output/contract.wasm",
codeMetadata: [],
gasLimit: 10_000_000,
}));
});
afterEach(async () => {
await world.terminate();
});
test("Test", async () => {
assertAccount(await contract.getAccountWithKvs(), {
balance: 0n,
allKvs: [],
});
});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 commanderAdd 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({
proxyUrl: envChain.publicProxyUrl(),
chainId: envChain.id(),
gasPrice: 1000000000,
});
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.