mirror of
https://github.com/LBRYFoundation/curate.git
synced 2025-08-23 17:37:25 +00:00
Add admin commands
This commit is contained in:
parent
d09c8fa311
commit
2c156c6853
11 changed files with 526 additions and 0 deletions
67
src/commands/admin/abandonall.ts
Normal file
67
src/commands/admin/abandonall.ts
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import { oneLine } from 'common-tags';
|
||||||
|
import { CommandContext, DexareClient } from 'dexare';
|
||||||
|
import { confirm, resolveUser } from '../../util';
|
||||||
|
import { GeneralCommand } from '../../util/abstracts';
|
||||||
|
|
||||||
|
export default class AbandonAllCommand extends GeneralCommand {
|
||||||
|
constructor(client: DexareClient<any>) {
|
||||||
|
super(client, {
|
||||||
|
name: 'abandonall',
|
||||||
|
description: 'Abandons all supports of all accounts or of a given account.',
|
||||||
|
category: 'Admin',
|
||||||
|
aliases: ['abanall', 'dropall'],
|
||||||
|
userPermissions: ['lbry.admin'],
|
||||||
|
metadata: {
|
||||||
|
examples: ['abandonall', 'abandonall @user'],
|
||||||
|
usage: '[user]'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.filePath = __filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(ctx: CommandContext) {
|
||||||
|
// Single user abandon
|
||||||
|
if (ctx.args[0]) {
|
||||||
|
const discordID = resolveUser(ctx.args[0]);
|
||||||
|
if (!discordID) return "That Discord user isn't valid.";
|
||||||
|
|
||||||
|
const account = await this.lbryx.ensureAccount(discordID, false);
|
||||||
|
if (!account.id) return 'That user does not have an account.';
|
||||||
|
|
||||||
|
const supportsCount = await this.lbryx.getSupportsCount(account.id);
|
||||||
|
if (supportsCount <= 0) return 'That user does not have any supports.';
|
||||||
|
|
||||||
|
if (
|
||||||
|
!(await confirm(
|
||||||
|
ctx,
|
||||||
|
oneLine`
|
||||||
|
Are you sure you want to abandon **all supports** from that account?
|
||||||
|
*(${supportsCount.toLocaleString()} support[s])*
|
||||||
|
`
|
||||||
|
))
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
await this.lbryx.abandonAllClaims(account.id);
|
||||||
|
return `Abandoned ${supportsCount.toLocaleString()} support(s).`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abandon ALL supports
|
||||||
|
|
||||||
|
await this.lbryx.sync();
|
||||||
|
const pairs = this.lbryx.getIDs();
|
||||||
|
if (pairs.length <= 0) return 'No pairs in the database.';
|
||||||
|
|
||||||
|
if (!(await confirm(ctx, 'Are you sure you want to abandon **all supports** from **all accounts**?')))
|
||||||
|
return;
|
||||||
|
|
||||||
|
await this.client.startTyping(ctx.channel.id);
|
||||||
|
let count = 0;
|
||||||
|
for (const [, lbryID] of pairs) {
|
||||||
|
const result = await this.lbryx.abandonAllClaims(lbryID);
|
||||||
|
if (result) count += result.count;
|
||||||
|
}
|
||||||
|
this.client.stopTyping(ctx.channel.id);
|
||||||
|
return `Abandoned ${count.toLocaleString()} supports(s).`;
|
||||||
|
}
|
||||||
|
}
|
24
src/commands/admin/adminbalance.ts
Normal file
24
src/commands/admin/adminbalance.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import { DexareClient } from 'dexare';
|
||||||
|
import { GeneralCommand } from '../../util/abstracts';
|
||||||
|
|
||||||
|
export default class AdminBalanceCommand extends GeneralCommand {
|
||||||
|
constructor(client: DexareClient<any>) {
|
||||||
|
super(client, {
|
||||||
|
name: 'adminbalance',
|
||||||
|
description: 'Shows the master wallet balance.',
|
||||||
|
category: 'Admin',
|
||||||
|
aliases: ['abal', 'adminbal'],
|
||||||
|
userPermissions: ['lbry.admin'],
|
||||||
|
metadata: {
|
||||||
|
examples: ['adminbalance']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.filePath = __filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
async run() {
|
||||||
|
const wallet = await this.lbry.walletBalance();
|
||||||
|
return this.displayWallet(wallet, 'Master Wallet Balance');
|
||||||
|
}
|
||||||
|
}
|
71
src/commands/admin/allsupports.ts
Normal file
71
src/commands/admin/allsupports.ts
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
import { CommandContext, DexareClient } from 'dexare';
|
||||||
|
import { Support } from '../../modules/lbry/types';
|
||||||
|
import { GeneralCommand } from '../../util/abstracts';
|
||||||
|
import { paginate } from '../../util/pager';
|
||||||
|
|
||||||
|
export default class AllSupportsommand extends GeneralCommand {
|
||||||
|
constructor(client: DexareClient<any>) {
|
||||||
|
super(client, {
|
||||||
|
name: 'allsupports',
|
||||||
|
description: 'List all supports from all users.',
|
||||||
|
category: 'Admin',
|
||||||
|
aliases: ['asups', 'allsups'],
|
||||||
|
userPermissions: ['lbry.admin'],
|
||||||
|
metadata: {
|
||||||
|
examples: ['allsupports', 'allsupports @channel#a/video#b'],
|
||||||
|
usage: '[claim]'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.filePath = __filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(ctx: CommandContext) {
|
||||||
|
let claim: string | null = null;
|
||||||
|
if (ctx.args[0]) {
|
||||||
|
claim = await this.lbryx.resolveClaim(ctx.args[0]);
|
||||||
|
if (!claim) return "That claim isn't valid.";
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.lbryx.sync();
|
||||||
|
const pairs = this.lbryx.getIDs();
|
||||||
|
if (pairs.length <= 0) return 'No users found in the database.';
|
||||||
|
|
||||||
|
const allSupports: (Support & {
|
||||||
|
discordID: string;
|
||||||
|
accountID: string;
|
||||||
|
})[] = [];
|
||||||
|
|
||||||
|
for (const [discordID, accountID] of pairs) {
|
||||||
|
const supportsCount = await this.lbryx.getSupportsCount(accountID);
|
||||||
|
if (supportsCount <= 0) continue;
|
||||||
|
const supports = await this.lbry.supportList({
|
||||||
|
account_id: accountID,
|
||||||
|
page_size: supportsCount,
|
||||||
|
claim_id: claim || undefined
|
||||||
|
});
|
||||||
|
for (const support of supports.items)
|
||||||
|
allSupports.push({
|
||||||
|
...support,
|
||||||
|
discordID,
|
||||||
|
accountID
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allSupports.length <= 0) return 'No supports found.';
|
||||||
|
|
||||||
|
await paginate(
|
||||||
|
ctx,
|
||||||
|
{
|
||||||
|
title: 'Supports',
|
||||||
|
items: allSupports.map(
|
||||||
|
(item) => `> ${item.name} \`${item.claim_id}\`\n> <@${item.discordID}> ${item.amount} LBC`
|
||||||
|
),
|
||||||
|
itemSeparator: '\n\n'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
author: { name: `All supports ${claim ? ` on claim \`${claim}\`` : ''}` }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
48
src/commands/admin/deleteaccount.ts
Normal file
48
src/commands/admin/deleteaccount.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import { stripIndents } from 'common-tags';
|
||||||
|
import { CommandContext, DexareClient } from 'dexare';
|
||||||
|
import { confirm, resolveUser } from '../../util';
|
||||||
|
import { GeneralCommand } from '../../util/abstracts';
|
||||||
|
|
||||||
|
export default class DeleteAccountommand extends GeneralCommand {
|
||||||
|
constructor(client: DexareClient<any>) {
|
||||||
|
super(client, {
|
||||||
|
name: 'deleteaccount',
|
||||||
|
description: "Delete a user's Curation account.",
|
||||||
|
category: 'Admin',
|
||||||
|
aliases: ['del', 'delacc'],
|
||||||
|
userPermissions: ['lbry.admin'],
|
||||||
|
metadata: {
|
||||||
|
examples: ['deleteaccount @user'],
|
||||||
|
usage: '<user>'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.filePath = __filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(ctx: CommandContext) {
|
||||||
|
const discordID = resolveUser(ctx.args[0]);
|
||||||
|
if (!discordID) return "That Discord user isn't valid.";
|
||||||
|
const account = await this.lbryx.ensureAccount(discordID, false);
|
||||||
|
if (!account.id) return 'That user does not have an account.';
|
||||||
|
|
||||||
|
const supportsCount = await this.lbryx.getSupportsCount(account.id);
|
||||||
|
if (
|
||||||
|
!(await confirm(
|
||||||
|
ctx,
|
||||||
|
`Are you sure you want to delete that account? *(${supportsCount.toLocaleString()} support[s])*`
|
||||||
|
))
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.lbryx.deleteAccount(discordID, account.id);
|
||||||
|
return 'Deleted account.';
|
||||||
|
} catch (e) {
|
||||||
|
return stripIndents`
|
||||||
|
Failed to delete the account. An error most likely occured while backing up the wallet.
|
||||||
|
\`\`\`\n${e.toString()}\`\`\`
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
src/commands/admin/deleteall.ts
Normal file
47
src/commands/admin/deleteall.ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import { stripIndents } from 'common-tags';
|
||||||
|
import { CommandContext, DexareClient } from 'dexare';
|
||||||
|
import { confirm } from '../../util';
|
||||||
|
import { GeneralCommand } from '../../util/abstracts';
|
||||||
|
|
||||||
|
export default class DeleteAllCommand extends GeneralCommand {
|
||||||
|
constructor(client: DexareClient<any>) {
|
||||||
|
super(client, {
|
||||||
|
name: 'deleteall',
|
||||||
|
description: 'Deletes all accounts in the database.',
|
||||||
|
category: 'Admin',
|
||||||
|
aliases: ['delall'],
|
||||||
|
userPermissions: ['lbry.admin'],
|
||||||
|
metadata: {
|
||||||
|
examples: ['delall']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.filePath = __filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(ctx: CommandContext) {
|
||||||
|
await this.lbryx.sync();
|
||||||
|
const pairs = this.lbryx.getIDs();
|
||||||
|
|
||||||
|
if (pairs.length <= 0) return 'No pairs in the database.';
|
||||||
|
if (
|
||||||
|
!(await confirm(
|
||||||
|
ctx,
|
||||||
|
`Are you sure you want to delete **all** ${pairs.length.toLocaleString()} accounts?`
|
||||||
|
))
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const [discordID, lbryID] of pairs) {
|
||||||
|
try {
|
||||||
|
await this.lbryx.deleteAccount(discordID, lbryID);
|
||||||
|
} catch (e) {
|
||||||
|
return stripIndents`
|
||||||
|
Failed to delete an account. An error most likely occured while backing up the wallet.
|
||||||
|
\`\`\`\n${e.toString()}\`\`\`
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 'Deleted all accounts.';
|
||||||
|
}
|
||||||
|
}
|
25
src/commands/admin/deposit.ts
Normal file
25
src/commands/admin/deposit.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { DexareClient } from 'dexare';
|
||||||
|
import { GeneralCommand } from '../../util/abstracts';
|
||||||
|
|
||||||
|
export default class DepositCommand extends GeneralCommand {
|
||||||
|
constructor(client: DexareClient<any>) {
|
||||||
|
super(client, {
|
||||||
|
name: 'deposit',
|
||||||
|
description: 'Gets the address of the master wallet.',
|
||||||
|
category: 'Admin',
|
||||||
|
aliases: ['dp'],
|
||||||
|
userPermissions: ['lbry.admin'],
|
||||||
|
metadata: {
|
||||||
|
examples: ['deposit']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.filePath = __filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
async run() {
|
||||||
|
const accountID = await this.lbryx.getDefaultAccount();
|
||||||
|
const addresses = await this.lbry.addressList({ account_id: accountID, page_size: 1 });
|
||||||
|
return `Address: ${addresses.items[0].address}`;
|
||||||
|
}
|
||||||
|
}
|
40
src/commands/admin/fund.ts
Normal file
40
src/commands/admin/fund.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { stripIndents } from 'common-tags';
|
||||||
|
import { CommandContext, DexareClient } from 'dexare';
|
||||||
|
import { confirm, ensureDecimal, resolveUser } from '../../util';
|
||||||
|
import { GeneralCommand } from '../../util/abstracts';
|
||||||
|
|
||||||
|
export default class FundCommand extends GeneralCommand {
|
||||||
|
constructor(client: DexareClient<any>) {
|
||||||
|
super(client, {
|
||||||
|
name: 'fund',
|
||||||
|
description: "Fund a user's account with some LBC.",
|
||||||
|
category: 'Admin',
|
||||||
|
aliases: ['fundacc', 'fundaccount'],
|
||||||
|
userPermissions: ['lbry.admin'],
|
||||||
|
metadata: {
|
||||||
|
examples: ['fund @user 2.0'],
|
||||||
|
usage: '<user> <amount>'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.filePath = __filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(ctx: CommandContext) {
|
||||||
|
const discordID = resolveUser(ctx.args[0]);
|
||||||
|
if (!discordID) return "That Discord user isn't valid.";
|
||||||
|
const account = await this.lbryx.ensureAccount(discordID, false);
|
||||||
|
if (!account.id) return 'That user does not have an account.';
|
||||||
|
const amount = ensureDecimal(ctx.args[1]);
|
||||||
|
if (!amount) return 'You must give a numeric amount of LBC to send!';
|
||||||
|
|
||||||
|
if (!(await confirm(ctx, `Are you sure you want to fund this account ${amount} LBC?`))) return;
|
||||||
|
|
||||||
|
const transaction = await this.lbry.accountFund({ amount, to_account: account.id, broadcast: true });
|
||||||
|
this.log('info', `Funded account ${account.id} ${amount}`, transaction);
|
||||||
|
return stripIndents`
|
||||||
|
Successfully funded account!
|
||||||
|
🔗 https://explorer.lbry.com/tx/${transaction.txid}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
77
src/commands/admin/fundall.ts
Normal file
77
src/commands/admin/fundall.ts
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import { CommandContext, DexareClient } from 'dexare';
|
||||||
|
import { confirm, ensureDecimal, wait } from '../../util';
|
||||||
|
import { GeneralCommand } from '../../util/abstracts';
|
||||||
|
|
||||||
|
export default class FundAllCommand extends GeneralCommand {
|
||||||
|
constructor(client: DexareClient<any>) {
|
||||||
|
super(client, {
|
||||||
|
name: 'fundall',
|
||||||
|
description: 'Fund all users in the database with some LBC.',
|
||||||
|
category: 'Admin',
|
||||||
|
userPermissions: ['lbry.admin'],
|
||||||
|
metadata: {
|
||||||
|
examples: ['fundall 2.0'],
|
||||||
|
usage: '<amount>'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.filePath = __filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(ctx: CommandContext) {
|
||||||
|
const amount = ensureDecimal(ctx.args[0]);
|
||||||
|
if (!amount) return 'You must give a numeric amount of LBC to send!';
|
||||||
|
|
||||||
|
await this.lbryx.sync();
|
||||||
|
const pairs = this.lbryx.getIDs();
|
||||||
|
|
||||||
|
// empty DB population
|
||||||
|
if (pairs.length <= 0) {
|
||||||
|
const procMsg = await ctx.reply('No users in the database, creating accounts...');
|
||||||
|
await this.client.startTyping(ctx.channel.id);
|
||||||
|
const rolesConfig: string | string[] = this.client.config.curatorRoles;
|
||||||
|
const curatorRoles = Array.isArray(rolesConfig) ? rolesConfig : [rolesConfig];
|
||||||
|
const members = await this.client.bot.guilds.get(this.client.config.guildID)!.fetchMembers();
|
||||||
|
for (const member of members) {
|
||||||
|
if (curatorRoles.map((r) => member.roles.includes(r)).includes(true)) {
|
||||||
|
const account = await this.lbryx.ensureAccount(member.id);
|
||||||
|
pairs.push([member.id, account.id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await wait(5000);
|
||||||
|
this.client.stopTyping(ctx.channel.id);
|
||||||
|
await procMsg.delete().catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await confirm(ctx, `Are you sure you want to fund **all** accounts ${amount} LBC?`))) return;
|
||||||
|
|
||||||
|
await this.client.startTyping(ctx.channel.id);
|
||||||
|
const resultLines = [];
|
||||||
|
let funded = 0,
|
||||||
|
errored = 0;
|
||||||
|
for (const [discordID, accountID] of pairs) {
|
||||||
|
try {
|
||||||
|
const transaction = await this.lbry.accountFund({ to_account: accountID, amount, broadcast: true });
|
||||||
|
console.info('Funded account', accountID, transaction.txid);
|
||||||
|
resultLines.push(`${discordID} - https://explorer.lbry.com/tx/${transaction.txid}`);
|
||||||
|
funded++;
|
||||||
|
} catch (e) {
|
||||||
|
this.log('info', 'Failed to fund account', accountID, e);
|
||||||
|
resultLines.push(`${discordID} ! ${e.toString()}`);
|
||||||
|
errored++;
|
||||||
|
}
|
||||||
|
await wait(3000);
|
||||||
|
}
|
||||||
|
this.client.stopTyping(ctx.channel.id);
|
||||||
|
|
||||||
|
await ctx.reply(
|
||||||
|
errored
|
||||||
|
? `Failed to fund ${errored} accounts! (${funded} funded)`
|
||||||
|
: `Successfully funded ${funded} account(s)!`,
|
||||||
|
{
|
||||||
|
name: 'result.txt',
|
||||||
|
file: Buffer.from(resultLines.join('\n'), 'utf8')
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
51
src/commands/admin/listall.ts
Normal file
51
src/commands/admin/listall.ts
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import { stripIndents } from 'common-tags';
|
||||||
|
import { CommandContext, DexareClient } from 'dexare';
|
||||||
|
import { Balance } from '../../modules/lbry/types';
|
||||||
|
import { GeneralCommand } from '../../util/abstracts';
|
||||||
|
import { paginate } from '../../util/pager';
|
||||||
|
|
||||||
|
export default class ListAllCommand extends GeneralCommand {
|
||||||
|
constructor(client: DexareClient<any>) {
|
||||||
|
super(client, {
|
||||||
|
name: 'listall',
|
||||||
|
description: 'List all users in the database.',
|
||||||
|
category: 'Admin',
|
||||||
|
userPermissions: ['lbry.admin'],
|
||||||
|
metadata: {
|
||||||
|
examples: ['listall', 'listall 2'],
|
||||||
|
usage: '[page]'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.filePath = __filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(ctx: CommandContext) {
|
||||||
|
const pairs = this.lbryx.getIDs();
|
||||||
|
const walletMap = new Map<string, Balance>();
|
||||||
|
|
||||||
|
for (const [, accountID] of pairs) {
|
||||||
|
try {
|
||||||
|
const wallet = await this.lbry.accountBalance({ account_id: accountID });
|
||||||
|
walletMap.set(accountID, wallet);
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
await paginate(ctx, {
|
||||||
|
title: 'Users',
|
||||||
|
items: pairs.map(([discordID, accountID]) => {
|
||||||
|
const bal = walletMap.get(accountID);
|
||||||
|
return stripIndents`
|
||||||
|
> <@${discordID}> - \`${accountID}\`
|
||||||
|
> ${
|
||||||
|
bal
|
||||||
|
? `${bal.available} available, ${bal.reserved_subtotals.supports} staked.`
|
||||||
|
: 'Wallet Unavailable'
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}),
|
||||||
|
itemSeparator: '\n\n',
|
||||||
|
startPage: parseInt(ctx.args[0])
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
23
src/commands/admin/sync.ts
Normal file
23
src/commands/admin/sync.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { DexareClient } from 'dexare';
|
||||||
|
import { GeneralCommand } from '../../util/abstracts';
|
||||||
|
|
||||||
|
export default class SyncCommand extends GeneralCommand {
|
||||||
|
constructor(client: DexareClient<any>) {
|
||||||
|
super(client, {
|
||||||
|
name: 'sync',
|
||||||
|
description: 'Syncs ID pairs with the SDK.',
|
||||||
|
category: 'Admin',
|
||||||
|
userPermissions: ['lbry.admin'],
|
||||||
|
metadata: {
|
||||||
|
examples: ['sync']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.filePath = __filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
async run() {
|
||||||
|
const synced = await this.lbryx.sync();
|
||||||
|
return `Synced ${synced.toLocaleString()} new pairs.`;
|
||||||
|
}
|
||||||
|
}
|
53
src/commands/admin/withdraw.ts
Normal file
53
src/commands/admin/withdraw.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import { oneLine, stripIndents } from 'common-tags';
|
||||||
|
import { CommandContext, DexareClient } from 'dexare';
|
||||||
|
import { confirm, ensureDecimal } from '../../util';
|
||||||
|
import { GeneralCommand } from '../../util/abstracts';
|
||||||
|
|
||||||
|
export default class WithdrawCommand extends GeneralCommand {
|
||||||
|
constructor(client: DexareClient<any>) {
|
||||||
|
super(client, {
|
||||||
|
name: 'withdraw',
|
||||||
|
description: 'Sends funds to an address from the master wallet.',
|
||||||
|
category: 'Admin',
|
||||||
|
aliases: ['wd'],
|
||||||
|
userPermissions: ['lbry.admin'],
|
||||||
|
metadata: {
|
||||||
|
examples: ['wd abcd1234 2.0']
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.filePath = __filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
async run(ctx: CommandContext) {
|
||||||
|
const addr = ctx.args[0];
|
||||||
|
if (!addr || !/^[\w]{34}$/.test(addr)) return 'The address is invalid!';
|
||||||
|
const amount = ensureDecimal(ctx.args[1]);
|
||||||
|
if (!amount) return 'You must give a numeric amount of LBC to send!';
|
||||||
|
|
||||||
|
// Check if the balance is more than requested
|
||||||
|
const balance = await this.lbry.walletBalance();
|
||||||
|
const availableBalance = parseFloat(balance.available);
|
||||||
|
if (parseFloat(amount) > availableBalance)
|
||||||
|
return 'There is not enough available LBC in the wallet to send that amount!';
|
||||||
|
|
||||||
|
// Send to wallet
|
||||||
|
if (
|
||||||
|
!(await confirm(
|
||||||
|
ctx,
|
||||||
|
oneLine`
|
||||||
|
Are you sure you want to send ${amount} to \`${addr}\`?
|
||||||
|
*(remaining: ${availableBalance - parseFloat(amount)})*
|
||||||
|
`
|
||||||
|
))
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const transaction = await this.lbry.walletSend({ amount, addresses: addr });
|
||||||
|
this.log('info', `Withdrew ${amount} from master wallet to ${addr}`, transaction);
|
||||||
|
return stripIndents`
|
||||||
|
Sent ${amount} LBC to \`${addr}\`.
|
||||||
|
🔗 https://explorer.lbry.com/tx/${transaction.txid}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue