Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
{
"name": "swanky-env",
"image": "ghcr.io/swankyhub/swanky-cli/swanky-base:swanky3.1.0-beta.0_v2.1.0",

"image": "ghcr.io/inkdevhub/swanky-cli/swanky-base:swanky3.1.0-beta.0_v2.1.1",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2.8.0": {}
},
// Mount the workspace volume
"mounts": ["source=${localWorkspaceFolder},target=/workspaces,type=bind,consistency=cached"],
"workspaceFolder": "/workspaces",
Expand Down
35 changes: 35 additions & 0 deletions .gitpod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# This configuration file was automatically generated by Gitpod.
# Please adjust to your needs (see https://www.gitpod.io/docs/introduction/learn-gitpod/gitpod-yaml)
# and commit this file to your remote git repository to share the goodness with others.

# Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart

ports:
- name: Swanky Node
port: 9944

vscode:
extensions:
- rust-lang.rust-analyzer

tasks:
- init: |
# Add wasm target
rustup target add wasm32-unknown-unknown

# Add necessary components
rustup component add rust-src

# Install or update cargo packages
cargo install --force --locked cargo-contract
cargo install cargo-dylint dylint-link

yarn install
yarn build
command: |
echo "Swanky Dev Environment ready!"
echo "Use Swanky directly by running \"./bin/run.js COMMAND\""
echo "For example:"
echo "./bin/run.js init temp_project"
echo "cd temp_project"
echo "../bin/run.js contract compile flipper"
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ A newly generated project will have a `swanky.config.json` file that will get po
"node": {
"localPath": "/Users/sasapul/Work/astar/swanky-cli/temp_proj/bin/swanky-node",
"polkadotPalletVersions": "polkadot-v0.9.39",
"supportedInk": "v4.2.0"
"supportedInk": "v4.3.0"
},
"accounts": [
{
Expand Down
12 changes: 6 additions & 6 deletions base-image/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ RUN curl -L https://github.com/swankyhub/swanky-cli/releases/download/v3.1.0-bet
# Install Rustup and Rust, additional components, packages, and verify the installations
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && \
/bin/bash -c "source $HOME/.cargo/env && \
rustup toolchain install nightly-2023-03-05 && \
rustup default nightly-2023-03-05 && \
rustup component add rust-src --toolchain nightly-2023-03-05 && \
rustup target add wasm32-unknown-unknown --toolchain nightly-2023-03-05 && \
cargo +stable install cargo-dylint dylint-link && \
cargo +stable install cargo-contract --force --version 4.0.0-alpha && \
rustup install 1.72 && \
rustup default 1.72 && \
rustup component add rust-src && \
rustup target add wasm32-unknown-unknown && \
cargo install cargo-dylint dylint-link && \
cargo install cargo-contract --version 4.0.0-rc.1 && \
rustc --version"

# Install Yarn 1.x
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"ora": "6.3.1",
"semver": "7.5.4",
"shelljs": "0.8.5",
"toml": "^3.0.0",
"ts-mocha": "^10.0.0",
"winston": "^3.10.0"
},
Expand Down
63 changes: 63 additions & 0 deletions src/commands/account/balance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Args } from "@oclif/core";
import { ApiPromise } from "@polkadot/api";
import type { AccountInfo, Balance as BalanceType } from "@polkadot/types/interfaces";
import { ChainApi, resolveNetworkUrl } from "../../lib/index.js";
import { SwankyCommand } from "../../lib/swankyCommand.js";
import { InputError } from "../../lib/errors.js";
import { formatBalance } from "@polkadot/util";

export class Balance extends SwankyCommand<typeof Balance> {
static description = "Balance of an account";

static args = {
alias: Args.string({
name: "alias",
description: "Alias of account to be used",
}),
};
async run(): Promise<void> {
const { args } = await this.parse(Balance);

if (!args.alias) {
throw new InputError(
"Missing argument! Please provide an alias account to get the balance from. Example usage: `swanky account balance <YourAliasAccount>`"
);
}

const accountData = this.findAccountByAlias(args.alias);
const networkUrl = resolveNetworkUrl(this.swankyConfig, "");

const api = (await this.spinner.runCommand(async () => {
const api = await ChainApi.create(networkUrl);
await api.start();
return api.apiInst;
}, "Connecting to node")) as ApiPromise;

const decimals = api.registry.chainDecimals[0];
formatBalance.setDefaults({ unit: "UNIT", decimals });

const { nonce, data: balance } = await api.query.system.account<AccountInfo>(
accountData.address
);
const { free, reserved, miscFrozen, feeFrozen } = balance;

let frozen: BalanceType;
if (feeFrozen.gt(miscFrozen)) {
frozen = feeFrozen;
} else {
frozen = miscFrozen;
}

const transferrableBalance = free.sub(frozen);
const totalBalance = free.add(reserved);

console.log("Transferrable Balance:", formatBalance(transferrableBalance));
if (!transferrableBalance.eq(totalBalance)) {
console.log("Total Balance:", formatBalance(totalBalance));
console.log("Raw Balances:", balance.toHuman());
}
console.log("Account Nonce:", nonce.toHuman());

await api.disconnect();
}
}
43 changes: 37 additions & 6 deletions src/commands/account/create.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,37 @@
import { Flags } from "@oclif/core";
import chalk from "chalk";
import { ChainAccount, encrypt } from "../../lib/index.js";
import { ChainAccount, encrypt, getSwankyConfig, isLocalConfigCheck } from "../../lib/index.js";
import { AccountData } from "../../types/index.js";
import inquirer from "inquirer";
import { SwankyCommand } from "../../lib/swankyCommand.js";
export class CreateAccount extends SwankyCommand<typeof CreateAccount> {
import { FileError } from "../../lib/errors.js";
import { ConfigBuilder } from "../../lib/config-builder.js";
import { SwankyAccountCommand } from "./swankyAccountCommands.js";

export class CreateAccount extends SwankyAccountCommand<typeof CreateAccount> {
static description = "Create a new dev account in config";

static flags = {
generate: Flags.boolean({
global: Flags.boolean({
char: "g",
description: "Create account globally stored in Swanky system config.",

}),
new: Flags.boolean({
char: "n",
description: "Generate a brand new account.",
}),
dev: Flags.boolean({
char: "d",
description: "Make this account a dev account for local network usage.",
}),
};

constructor(argv: string[], baseConfig: any) {
super(argv, baseConfig);
(this.constructor as typeof SwankyCommand).ENSURE_SWANKY_CONFIG = false;
}

async run(): Promise<void> {
const { flags } = await this.parse(CreateAccount);

Expand All @@ -36,7 +52,7 @@ export class CreateAccount extends SwankyCommand<typeof CreateAccount> {
}

let tmpMnemonic = "";
if (flags.generate) {
if (flags.new) {
tmpMnemonic = ChainAccount.generate();
console.log(
`${
Expand Down Expand Up @@ -75,14 +91,29 @@ export class CreateAccount extends SwankyCommand<typeof CreateAccount> {
accountData.mnemonic = tmpMnemonic;
}

this.swankyConfig.accounts.push(accountData);
const configType = flags.global ? "global" : isLocalConfigCheck() ? "local" : "global";
const config = configType === "global" ? getSwankyConfig("global") : getSwankyConfig("local");

await this.storeConfig();
const configBuilder = new ConfigBuilder(config).addAccount(accountData);

if (config.defaultAccount === null) {
configBuilder.setDefaultAccount(accountData.alias);
}

try {
await this.storeConfig(configBuilder.build(), configType);
} catch (cause) {
throw new FileError(`Error storing created account in ${configType} config`, {
cause,
});
}

this.log(
`${chalk.greenBright("✔")} Account with alias ${chalk.yellowBright(
accountData.alias
)} stored to config`
);

await this.performFaucetTransfer(accountData, true);
}
}
82 changes: 82 additions & 0 deletions src/commands/account/default.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { Args, Flags } from "@oclif/core";
import chalk from "chalk";
import { SwankySystemConfig } from "../../types/index.js";
import inquirer from "inquirer";
import { SwankyCommand } from "../../lib/swankyCommand.js";
import { ConfigError, FileError } from "../../lib/errors.js";
import { getSwankyConfig, isLocalConfigCheck } from "../../lib/index.js";
import { ConfigBuilder } from "../../lib/config-builder.js";

export class DefaultAccount extends SwankyCommand<typeof DefaultAccount> {
static description = "Set default account to use";

static flags = {
global: Flags.boolean({
char: "g",
description: "Set default account globally in Swanky system config.",
}),
};

static args = {
accountAlias: Args.string({
name: "accountAlias",
required: false,
description: "Alias of account to be used as default",
}),
};

constructor(argv: string[], baseConfig: any) {
super(argv, baseConfig);
(this.constructor as typeof SwankyCommand).ENSURE_SWANKY_CONFIG = false;
}

async run(): Promise<void> {
const { args, flags } = await this.parse(DefaultAccount);

const configType = flags.global ? "global" : isLocalConfigCheck() ? "local" : "global";
const config = configType === "global" ? getSwankyConfig("global") : getSwankyConfig("local");

const accountAlias = args.accountAlias ?? (await this.promptForAccountAlias(config));
this.ensureAccountExists(config, accountAlias);

const newConfig = new ConfigBuilder(config).setDefaultAccount(accountAlias).build();

try {
await this.storeConfig(newConfig, configType);
} catch (cause) {
throw new FileError(`Error storing default account in ${configType} config`, {
cause,
});
}

this.log(
`${chalk.greenBright("✔")} Account with alias ${chalk.yellowBright(
accountAlias
)} set as default in ${configType} config`
);
}

private async promptForAccountAlias(config: SwankySystemConfig): Promise<string> {
const choices = config.accounts.map((account) => ({
name: `${account.alias} (${account.address})`,
value: account.alias,
}));

const answer = await inquirer.prompt([
{
type: "list",
name: "defaultAccount",
message: "Select default account",
choices: choices,
},
]);

return answer.defaultAccount;
}

private ensureAccountExists(config: SwankySystemConfig, alias: string) {
const isSomeAccount = config.accounts.some((account) => account.alias === alias);
if (!isSomeAccount)
throw new ConfigError(`Provided account alias ${chalk.yellowBright(alias)} not found`);
}
}
23 changes: 23 additions & 0 deletions src/commands/account/faucet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Args } from "@oclif/core";
import { SwankyAccountCommand } from "./swankyAccountCommands.js";

export class Faucet extends SwankyAccountCommand<typeof Faucet> {
static description = "Transfer some tokens from faucet to an account";

static aliases = [`account:faucet`];

static args = {
alias: Args.string({
name: "alias",
required: true,
description: "Alias of account to be used",
}),
};

async run(): Promise<void> {
const { args } = await this.parse(Faucet);

const accountData = this.findAccountByAlias(args.alias);
await this.performFaucetTransfer(accountData);
}
}
31 changes: 28 additions & 3 deletions src/commands/account/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,36 @@ export class ListAccounts extends SwankyCommand<typeof ListAccounts> {
static description = "List dev accounts stored in config";
static aliases = [`account:ls`];

constructor(argv: string[], baseConfig: any) {
super(argv, baseConfig);
(this.constructor as typeof SwankyCommand).ENSURE_SWANKY_CONFIG = false;
}

async run(): Promise<void> {
this.log(`${chalk.greenBright("✔")} Stored dev accounts:`);
const countOfDevAccounts = this.swankyConfig.accounts.filter((account) => account.isDev).length;

if(countOfDevAccounts !== 0) {
this.log(`${chalk.greenBright("✔")} Stored dev accounts:`);

for (const account of this.swankyConfig.accounts) {
if(account.isDev){
this.log(`\t${chalk.yellowBright("Alias: ")} ${account.alias} \
${chalk.yellowBright("Address: ")} ${account.address} ${this.swankyConfig.defaultAccount === account.alias ? chalk.greenBright("<- Default") : ""}`);
}
}
}

const countOfProdAccounts = this.swankyConfig.accounts.length - countOfDevAccounts;

if(countOfProdAccounts !== 0) {
this.log(`${chalk.greenBright("✔")} Stored prod accounts:`);

for (const account of this.swankyConfig.accounts) {
this.log(`\t${chalk.yellowBright("Alias: ")} ${account.alias}`);
for (const account of this.swankyConfig.accounts) {
if(!account.isDev){
this.log(`\t${chalk.yellowBright("Alias: ")} ${account.alias} \
${chalk.yellowBright("Address: ")} ${account.address} ${this.swankyConfig.defaultAccount === account.alias ? chalk.greenBright("<- Default") : ""}`);
}
}
}
}
}
Loading