Skip to content
Merged
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
10 changes: 4 additions & 6 deletions .commitlintrc
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
{
"env": {
"browser": true,
"es2021": true
},

"env": {
"browser": true,
"es2021": true
}
}
Empty file added .npmignore
Empty file.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## [1.1.0](https://github.com/versumstudios/cli/compare/v1.0.0...v1.1.0) (2022-07-23)


### Features

* **export:** add export token ([#3](https://github.com/versumstudios/cli/issues/3)) ([#4](https://github.com/versumstudios/cli/issues/4)) ([864f0f8](https://github.com/versumstudios/cli/commit/864f0f8a423938715e9331e6f458c422ab27a165))

## 1.0.0 (2022-07-23)


Expand Down
14 changes: 14 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,17 @@ When squashing-and-merging:
function that's only expected to be used by driver implementations).
- Delete the automatically added commit lines; these are generally not
interesting and make commit history harder to read.

## Develop

Follow the steps below to run the CLI locally:

1. Make sure you do not have any instance of @versumstudios/cli already installed. You can also verify if the CLI is installed by running `npm list -g --depth 0`. If you have a previous version installed you should uninstall it via `yarn local:uninstall`.

2. Install all dependencies by running `yarn`

3. Run `yarn local:link`. It should create a symlink pointing to `./bin/src/index.js`.

4. Run `yarn start` to transpile the typescript into javascript.

5. Every time you need to test a new command, just type `versum <command>`.
43 changes: 34 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,56 @@
[![Join the community on GitHub Discussions](https://badgen.net/badge/join%20the%20discussion/on%20github/black?icon=github)](https://github.com/versumstudios/cli/discussions)

# @versumstudios/cli

The command-line interface for versum.

## Install
- [versum-cli](#versum-cli)
- [Usage](#usage)
- [Contributing](#contributing)
- [How to use](#how-to-use)
- [Export](#export)

## Usage

To install the latest version of Versum CLI, run this command:

```bash
npm i -g @versumstudios/cli
```

## Get started
To get started run:

```bash
versum
```

## Develop
## Contributing

- [Code of Conduct](https://github.com/versumstudios/cli/blob/main/CODE_OF_CONDUCT.md)
- [Contributing Guidelines](https://github.com/versumstudios/cli/blob/main/CONTRIBUTING.md)
- [Apache-2.0 License](https://github.com/versumstudios/cli/blob/main/LICENSE)

Follow the steps below to run the CLI locally:
## How to use

1. Make sure you do not have any instance of @versumstudios/cli already installed. You can also verify if the CLI is installed by running `npm list -g --depth 0`. If you have a previous version installed you should uninstall it via `yarn local:uninstall`.
```bash
versum -h
```

2. Install all dependencies by running `yarn`
### Export

3. Run `yarn local:link`. It should create a symlink pointing to `./bin/src/index.js`.
The versum CLI allows you to export several chunks of data into `.csv` files.

4. Run `yarn start` to transpile the typescript into javascript.
### Export `token-collectors`

5. Every time you need to test a new command, just type `versum <command>`.
```bash
versum export token-collectors
versum export token-collectors --contract KT1LjmAdYQCLBjwv4S2oFkEzyHVkomAf5MrW --token 0
```

### Export `wallet-collectors`

```bash
versum export wallet-collectors
versum export wallet-collectors --wallet tz1eht4WAjkqU7kaupJd8qCDmec9HuKfGf68
versum export wallet-collectors --wallet tz1eht4WAjkqU7kaupJd8qCDmec9HuKfGf68 --platform versum
```
21 changes: 12 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@versumstudios/cli",
"version": "1.0.2",
"version": "1.1.0",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for versum",
Expand All @@ -11,19 +11,22 @@
"url": "https://github.com/versumstudios/cli.git"
},
"scripts": {
"start": "ttsc -w -p .",
"build": "ttsc",
"start": "rm -rf ./bin && concurrently --raw \"tsc -w -p .\" \"tsc-alias -w\"",
"build": "rm -rf ./bin && tsc && tsc-alias",
"test": "echo \"Error: no test specified\" && exit 1",
"local:install": "npm install -g .",
"local:uninstall": "npm uninstall -g @versumstudios/cli",
"local:link": "yarn local:uninstall && yarn local:install",
"prepare": "husky install"
},
"files": [
"bin"
],
"bin": {
"versum": "./bin/src/index.js"
},
"engines": {
"node": ">= 16"
"node": ">=16"
},
"commitlint": {
"extends": [
Expand All @@ -33,14 +36,14 @@
"devDependencies": {
"@commitlint/cli": "^17.0.3",
"@commitlint/config-conventional": "^17.0.3",
"@taquito/utils": "^13.0.1",
"@types/inquirer": "^8.2.1",
"@types/node": "^18.0.6",
"@types/node-fetch": "^2.6.2",
"@types/objects-to-csv": "^1.3.1",
"@types/update-notifier": "^6.0.1",
"@typescript-eslint/eslint-plugin": "^5.30.7",
"@typescript-eslint/parser": "^5.30.7",
"concurrently": "^7.3.0",
"eslint": "^8.20.0",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^3.3.0",
Expand All @@ -50,17 +53,17 @@
"husky": "^8.0.1",
"prettier": "^2.7.1",
"ts-node": "^10.9.1",
"ttypescript": "^1.5.13",
"typescript": "^4.7.4",
"typescript-transform-paths": "^3.3.1"
"tsc-alias": "^1.7.0",
"typescript": "^4.7.4"
},
"dependencies": {
"@taquito/utils": "^13.0.1",
"chalk": "4.1.2",
"commander": "^9.4.0",
"inquirer": "8.0.0",
"node-fetch": "2.6.2",
"objects-to-csv": "^1.3.6",
"ora-classic": "^5.4.2",
"ora": "5.4.1",
"update-notifier": "5.1.0"
}
}
92 changes: 53 additions & 39 deletions src/actions/export-token-collectors.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,70 @@
import inquirer, { Answers } from 'inquirer';
import inquirer, { Answers, Separator } from 'inquirer';
import fetch from 'node-fetch';
import ora from 'ora-classic';
import ora from 'ora';

import { CONTRACT_VERSUM, getContractFromPlatform, PLATFORMS, TEZTOK_API } from '@constants';
import { CONTRACT_VERSUM, ERRORS, getContractFromPlatform, MESSAGES, PLATFORMS, TEZTOK_API } from '@constants';
import { CollectorsType } from '@custom-types/collectors';
import { validateContractAddress } from '@taquito/utils';
import { SaveToFile } from '@utils/csv';
import { error } from '@utils/logger';
import { error, info } from '@utils/logger';

type CollectorsType = {
holder_address: string;
amount: number;
}[];
const handleAction = (address: string, token: string) => {
const query = `
query GetTokenCollectors($address: String!, $token: String!) {
tokens_by_pk(fa2_address: $address, token_id: $token) {
holdings(where: { amount: { _gt: "0" } }) {
holder_address
amount
}
}
}`;

return fetch(TEZTOK_API, { method: 'POST', body: JSON.stringify({ query, variables: { address, token } }) })
.then((e) => e.json())
.then((e) => e.data.tokens_by_pk.holdings)
.then(async (collectors: CollectorsType) => {
// parse data
const data = collectors.map(({ holder_address, amount }) => ({
address: holder_address,
amount,
}));
const filename = await SaveToFile(`token-collectors-${address}-${token}.csv`, data);
return `File saved ${filename}`;
});
};

export const action = (options: Record<string, string>) => {
// if options are present, bypass the user promp
if (options.contract && options.token) {
handleAction(options.contract, options.token)
.then((message) => info(message))
.catch(() => {
error(ERRORS.ERROR_EXPORT_COLLECTOR);
});
return;
}

export const action = () => {
// otherwise show user promp
const questions = [
{
type: 'list',
name: 'platform',
message: 'Select platform',
choices: [PLATFORMS.VERSUM, PLATFORMS.HICETNUNC, PLATFORMS.FXHASH, PLATFORMS.OTHER],
message: MESSAGES.SELECT_PLATFORM,
choices: [PLATFORMS.VERSUM, PLATFORMS.HICETNUNC, PLATFORMS.FXHASH, new Separator(), PLATFORMS.OTHER],
default() {
return PLATFORMS.VERSUM;
},
},
{
type: 'input',
name: 'contract',
message: 'Enter contract address',
message: MESSAGES.ENTER_CONTRACT_ADDRESS,
when: (answers: Answers) => answers.platform === PLATFORMS.OTHER,
validate: async (input: string) => {
if ((await validateContractAddress(input)) === 3) {
return true;
}
error('\nInvalid contract address');
return false;
return ERRORS.ERROR_INVALID_ADDRESS;
},
default() {
return CONTRACT_VERSUM;
Expand All @@ -42,43 +73,26 @@ export const action = () => {
{
type: 'input',
name: 'token',
message: 'Enter token id',
message: MESSAGES.ENTER_TOKEN_ID,
default() {
return '0';
},
},
];
const query = `
query GetTokenCollectors($address: String!, $token: String!) {
tokens_by_pk(fa2_address: $address, token_id: $token) {
holdings(where: { amount: { _gt: "0" } }) {
holder_address
amount
}
}
}`;

inquirer.prompt(questions).then(({ platform, contract, token }: Record<string, string>) => {
// select contract address from platform
// select contract address from platform alias
const address: string = getContractFromPlatform(platform as PLATFORMS, token as string) || contract;
const spinner = ora('Fetching data...').start();
const spinner = ora(MESSAGES.FETCHING_DATA).start();

fetch(TEZTOK_API, { method: 'POST', body: JSON.stringify({ query, variables: { address, token } }) })
.then((e) => e.json())
.then((e) => e.data.tokens_by_pk.holdings)
.then(async (collectors: CollectorsType) => {
// parse data
const data = collectors.map(({ holder_address, amount }) => ({
address: holder_address,
amount,
}));
handleAction(address, token)
.then((message: string) => {
spinner.succeed();
await SaveToFile(`collectors-${platform}-${address}-${token}.csv`, data);
info(message);
})
.catch(() => {
const errorMsg = 'Error exporting collectors';
error(errorMsg);
spinner.fail(errorMsg);
spinner.fail();
error(ERRORS.ERROR_EXPORT_COLLECTOR);
});
});
};
Loading