Skip to content

Commit

Permalink
add investigate command
Browse files Browse the repository at this point in the history
  • Loading branch information
krzysu committed Apr 11, 2024
1 parent 9190b9c commit e39e824
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 67 deletions.
106 changes: 55 additions & 51 deletions packages/cli/src/commands/createTestProfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,67 +7,71 @@ import {
ensureParentCommand,
getHandlePrefix,
initLensClient,
} from '../utils/commandToEnvironment.js';
} from '../lib/commandToEnvironment.js';
import { output } from '../lib/output.js';

const createTestProfile = new Command('create-profile')
.description('Create a new test profile, possible only in the development environment')
.requiredOption('-h, --handle <handle>', 'Test profile handle')
.requiredOption('-a, --address <address>', 'Wallet address')
.action(async (options) => {
const validation = createSpinner(`Validating input data`).start();
export function createTestProfile() {
const cmd = new Command('create-profile')

if (!isValidHandle(options.handle)) {
validation.error();
console.error(`Invalid handle: ${options.handle}`);
process.exit(1);
}
.description('Create a new test profile, possible only in the development environment')
.requiredOption('-h, --handle <handle>', 'Test profile handle')
.requiredOption('-a, --address <address>', 'Wallet address')
.action(async (options) => {
const validation = createSpinner(`Validating input data`).start();

if (!isAddress(options.address)) {
validation.error();
console.error(`Invalid address: ${options.address}`);
process.exit(1);
}

const parentCommandName = ensureParentCommand(createTestProfile);
const client = initLensClient(parentCommandName);

// check if the requested handle is available
const handleOwnerAddress = await client.handle.resolveAddress({
handle: `${getHandlePrefix(parentCommandName)}/${options.handle}`,
});
if (!isValidHandle(options.handle)) {
validation.error();
output.error(`Invalid handle: ${options.handle}`);
process.exit(1);
}

if (handleOwnerAddress) {
validation.error();
console.error(`The requested handle "${options.handle}" is not available.`);
process.exit(1);
}
validation.success();
if (!isAddress(options.address)) {
validation.error();
output.error(`Invalid address: ${options.address}`);
process.exit(1);
}

const creation = createSpinner(
`Creating new test profile with handle "${options.handle}" for address "${options.address}"`,
).start();
const parentCommandName = ensureParentCommand(cmd);
const client = initLensClient(parentCommandName);

try {
const profileCreateResult = await client.wallet.createProfileWithHandle({
handle: options.handle,
to: options.address,
// check if the requested handle is available
const handleOwnerAddress = await client.handle.resolveAddress({
handle: `${getHandlePrefix(parentCommandName)}/${options.handle}`,
});

if (!isRelaySuccess(profileCreateResult)) {
creation.error();
console.error(`Something went wrong`, profileCreateResult);
if (handleOwnerAddress) {
validation.error();
output.error(`The requested handle "${options.handle}" is not available.`);
process.exit(1);
}
validation.success();

await client.transaction.waitUntilComplete({ forTxId: profileCreateResult.txId });
const creation = createSpinner(
`Creating new test profile with handle "${options.handle}" for address "${options.address}"`,
).start();

creation.success();
console.log(`Profile created successfully`);
} catch (error) {
creation.error();
console.error(error);
process.exit(1);
}
});
try {
const profileCreateResult = await client.wallet.createProfileWithHandle({
handle: options.handle,
to: options.address,
});

if (!isRelaySuccess(profileCreateResult)) {
creation.error();
output.error(`Something went wrong:`, profileCreateResult);
process.exit(1);
}

await client.transaction.waitUntilComplete({ forTxId: profileCreateResult.txId });

creation.success();
output.success(`Profile created successfully`);
} catch (error) {
creation.error();
output.error(error);
process.exit(1);
}
});

export { createTestProfile };
return cmd;
}
115 changes: 115 additions & 0 deletions packages/cli/src/commands/investigate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { Command } from '@commander-js/extra-typings';
import { BigDecimal } from '@lens-protocol/shared-kernel';
import chalk from 'chalk';
import { createSpinner } from 'nanospinner';

import { ensureParentCommand, initLensClient } from '../lib/commandToEnvironment.js';
import { LENS_HANDLES_CONTRACT, LENS_PROFILES_CONTRACT } from '../lib/consts.js';
import { output } from '../lib/output.js';
import { safeRequest } from '../lib/safeRequest.js';

const hexToDecimal = (hex: string) => BigDecimal.from(hex).toFixed();

export function investigate() {
const cmd = new Command('investigate')
.description('Investigate a Profile ID, Handle or Wallet Address')
.option('-h, --handle <handle>', 'Handle with prefix (lens/handle or test/handle)')
.option('-a, --address <address>', 'Wallet address')
.option('-p, --profile <address>', 'Profile ID')
.action(async (options) => {
if (!options.handle && !options.address && !options.profile) {
output.error('At least one of the options is required. See --help for more information.');
process.exit(1);
}

const parentCommandName = ensureParentCommand(cmd);
const client = initLensClient(parentCommandName);

if (options.handle) {
const fullHandle = options.handle;

const spinner = createSpinner(
`Investigating handle: ${chalk.green(options.handle)}`,
).start();

const address = await safeRequest(
async () => client.handle.resolveAddress({ handle: fullHandle }),
() => spinner.error(),
);

const profile = await safeRequest(
async () => client.profile.fetch({ forHandle: fullHandle }),
() => spinner.error(),
);

spinner.success();

output.value(`Resolved address:`, address);
output.info(
`Handle details:`,
profile &&
profile.handle && {
linkedTo: {
profileId: profile.handle.linkedTo?.nftTokenId,
},
ownedBy: profile.handle.ownedBy,
},
);
output.info(
`Linked profile:`,
profile && {
id: profile.id,
ownedBy: profile.ownedBy.address,
createdAt: profile.createdAt,
sponsor: profile.sponsor,
signless: profile.signless,
// guardian: profile.guardian, // can only be read by owner
metadata: profile.metadata && {
displayName: profile.metadata.displayName,
bio: profile.metadata.bio,
},
stats: profile.stats,
},
);

if (parentCommandName === 'production') {
output.value(`URL:`, `https://share.lens.xyz/u/${fullHandle}`);
profile &&
profile.handle &&
output.value(
`Lens Handles OpenSea:`,
`https://opensea.io/assets/matic/${LENS_HANDLES_CONTRACT}/${hexToDecimal(
profile.handle.id,
)}`,
);
profile &&
output.value(
`Lens Profiles OpenSea:`,
`https://opensea.io/assets/matic/${LENS_PROFILES_CONTRACT}/${hexToDecimal(
profile.id,
)}`,
);
}
}

if (options.address) {
output.value(`Investigating address:`, options.address);

// validate
// owned/managed profiles
// owned handles
// rate limits
}

if (options.profile) {
output.value(`Investigating profile:`, options.profile);

// owner
// managers
// linked handle
// lens share link
}
});

return cmd;
}
8 changes: 5 additions & 3 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@
import { program } from '@commander-js/extra-typings';

import { createTestProfile } from './commands/createTestProfile.js';
import './utils/logger.js';
import { investigate } from './commands/investigate.js';

program.name('lens').description('Lens CLI');

program
.command('development')
.alias('dev')
.description('Command will run in the development environment')
.addCommand(createTestProfile);
.addCommand(createTestProfile())
.addCommand(investigate());

program
.command('production')
.alias('prod')
.description('Command will run in the production environment');
.description('Command will run in the production environment')
.addCommand(investigate());

program.parse();
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Command } from '@commander-js/extra-typings';
import type { Command } from '@commander-js/extra-typings';
import { LensClient, production, development } from '@lens-protocol/client';

const commandToEnvironmentMap = {
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/lib/consts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const LENS_HANDLES_CONTRACT = '0xe7e7ead361f3aacd73a61a9bd6c10ca17f38e945';
export const LENS_PROFILES_CONTRACT = '0xdb46d1dc155634fbc732f92e853b10b288ad5a1d';
16 changes: 16 additions & 0 deletions packages/cli/src/lib/output.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import chalk from 'chalk';

export const output = {
success: function (...args: Parameters<typeof console.log>) {
console.log(chalk.green(...args));
},
error: function (...args: Parameters<typeof console.log>) {
console.log(chalk.red(...args));
},
info: function (...args: Parameters<typeof console.log>) {
console.log(...args);
},
value: function (key: string, ...args: Parameters<typeof console.log>) {
console.log(key, chalk.green(...args));
},
};
22 changes: 22 additions & 0 deletions packages/cli/src/lib/safeRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { assertError } from '@lens-protocol/shared-kernel';

import { output } from './output.js';

/*
* Safely execute a request and handle errors
*/
export async function safeRequest<T>(
callback: () => Promise<T>,
onError?: (error: Error) => void,
): Promise<T> {
try {
return await callback();
} catch (error) {
assertError(error);
if (onError) {
onError(error);
}
output.error(`Error: ${error.message}`);
process.exit(1);
}
}
12 changes: 0 additions & 12 deletions packages/cli/src/utils/logger.ts

This file was deleted.

0 comments on commit e39e824

Please sign in to comment.