Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add offer-remove command #1018

Merged
merged 4 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
29 changes: 29 additions & 0 deletions cli/docs/commands/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
* [`fluence provider init`](#fluence-provider-init)
* [`fluence provider offer-create`](#fluence-provider-offer-create)
* [`fluence provider offer-info`](#fluence-provider-offer-info)
* [`fluence provider offer-remove`](#fluence-provider-offer-remove)
* [`fluence provider offer-update`](#fluence-provider-offer-update)
* [`fluence provider register`](#fluence-provider-register)
* [`fluence provider tokens-distribute`](#fluence-provider-tokens-distribute)
Expand Down Expand Up @@ -1651,6 +1652,34 @@ ALIASES

_See code: [src/commands/provider/offer-info.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.19.2/src/commands/provider/offer-info.ts)_

## `fluence provider offer-remove`

Remove offers

```
USAGE
$ fluence provider offer-remove [--no-input] [--offers <offer-1,offer-2>] [--env <dar | kras | stage | local | custom>]
[--priv-key <private-key>]

FLAGS
--env=<dar | kras | stage | local | custom> Fluence Environment to use when running the command
--no-input Don't interactively ask for any input from the user
--offers=<offer-1,offer-2> Comma-separated list of offer names. To use all of your offers: --offers
all
--priv-key=<private-key> !WARNING! for debug purposes only. Passing private keys through flags is
unsecure. On local env
0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 is
used by default when CLI is used in non-interactive mode

DESCRIPTION
Remove offers

ALIASES
$ fluence provider or
```

_See code: [src/commands/provider/offer-remove.ts](https://github.com/fluencelabs/cli/blob/fluence-cli-v0.19.2/src/commands/provider/offer-remove.ts)_

## `fluence provider offer-update`

Update offers
Expand Down
36 changes: 36 additions & 0 deletions cli/src/commands/provider/offer-remove.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Fluence CLI
* Copyright (C) 2024 Fluence DAO
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { BaseCommand, baseFlags } from "../../baseCommand.js";
import { removeOffers } from "../../lib/chain/offer/updateOffers.js";
import { CHAIN_FLAGS, OFFER_FLAG } from "../../lib/const.js";
import { initCli } from "../../lib/lifeCycle.js";

export default class OfferRemove extends BaseCommand<typeof OfferRemove> {
static override aliases = ["provider:or"];
static override description = "Remove offers";
static override flags = {
...baseFlags,
...OFFER_FLAG,
...CHAIN_FLAGS,
};

async run(): Promise<void> {
const { flags } = await initCli(this, await this.parse(OfferRemove));
await removeOffers(flags);
}
}
9 changes: 9 additions & 0 deletions cli/src/lib/chain/offer/offer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,11 @@ export async function createOffers(flags: OffersArgs) {
);
}

if (offerIds.length === 0) {
commandObj.logToStderr("No offers created");
return;
}

type GetOffersInfoReturnType = Awaited<
ReturnType<typeof getOffersInfo<(typeof offerIds)[number]>>
>;
Expand Down Expand Up @@ -633,6 +638,10 @@ export async function resolveCreatedOffers(flags: OfferArtifactsArgs) {
export async function getOffersInfo<T extends OfferNameAndId>(
offers: T[],
): Promise<[T[], (T & { offerIndexerInfo: OfferDetail })[]]> {
if (offers.length === 0) {
return [[], []];
}

const dealCliClient = await getDealCliClient();

const getOffersArg: Parameters<typeof dealCliClient.getOffers>[0] = {
Expand Down
151 changes: 151 additions & 0 deletions cli/src/lib/chain/offer/updateOffers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
import type { ComputeUnit } from "@fluencelabs/deal-ts-clients/dist/dealExplorerClient/types/schemes.js";
import { color } from "@oclif/color";
import chunk from "lodash-es/chunk.js";
import omit from "lodash-es/omit.js";

import { commandObj } from "../../commandObj.js";
import { initNewProviderArtifactsConfig } from "../../configs/project/providerArtifacts.js";
import {
CLI_NAME,
PROVIDER_ARTIFACTS_CONFIG_FULL_FILE_NAME,
Expand All @@ -35,6 +37,7 @@ import {
import { numToStr, uint8ArrayToHex } from "../../helpers/typesafeStringify.js";
import { splitErrorsAndResults } from "../../helpers/utils.js";
import { confirm } from "../../prompt.js";
import { ensureFluenceEnv } from "../../resolveFluenceEnv.js";
import {
cidStringToCIDV1Struct,
peerIdHexStringToBase58String,
Expand Down Expand Up @@ -103,6 +106,66 @@ export async function updateOffers(flags: OffersArgs) {
);
}

export async function removeOffers(flags: OffersArgs) {
const offers = await resolveOffersFromProviderConfig(flags);
const offersFoundOnChain = await filterOffersFoundOnChain(offers);
const populatedTxs = await populateRemoveOffersTxs(offersFoundOnChain);

const removeOffersTxs = [
populatedTxs.flatMap(({ cuToRemoveTxs: txs }) => {
return txs.map(({ tx }) => {
return tx;
});
}),
populatedTxs.flatMap(({ removePeersFromOffersTxs }) => {
return removePeersFromOffersTxs.map(({ tx }) => {
return tx;
});
}),
populatedTxs.flatMap(({ removeOfferTx }) => {
return [removeOfferTx.tx];
}),
].flat();

if (removeOffersTxs.length === 0) {
commandObj.logToStderr("Nothing to remove for selected offers");
return;
}

printOffersToRemoveInfo(populatedTxs);

if (
!(await confirm({
message: "Would you like to continue",
default: true,
}))
) {
commandObj.logToStderr("Offers remove canceled");
return;
}

await signBatch(
`Removing offers:\n\n${populatedTxs
.map(({ offerName, offerId }) => {
return `${offerName} (${offerId})`;
})
.join("\n")}`,
removeOffersTxs,
assertProviderIsRegistered,
);

const providerArtifactsConfig = await initNewProviderArtifactsConfig();

providerArtifactsConfig.offers[await ensureFluenceEnv()] = omit(
providerArtifactsConfig.offers[await ensureFluenceEnv()],
shamsartem marked this conversation as resolved.
Show resolved Hide resolved
populatedTxs.map(({ offerName }) => {
return offerName;
}),
);

await providerArtifactsConfig.$commit();
}

type OnChainOffer = Awaited<
ReturnType<typeof filterOffersFoundOnChain>
>[number];
Expand Down Expand Up @@ -190,6 +253,44 @@ function populateUpdateOffersTxs(offersFoundOnChain: OnChainOffer[]) {
);
}

function populateRemoveOffersTxs(offersFoundOnChain: OnChainOffer[]) {
return Promise.all(
offersFoundOnChain.map(async (offer) => {
const { offerName, offerId, offerIndexerInfo } = offer;
offer.computePeersFromProviderConfig = [];

const peersOnChain = (await Promise.all(
offerIndexerInfo.peers.map(async ({ id, ...rest }) => {
return {
peerIdBase58: await peerIdHexStringToBase58String(id),
hexPeerId: id,
...rest,
};
}),
)) satisfies PeersOnChain;

const removePeersFromOffersTxs = (await populatePeersToRemoveTxs(
offer,
peersOnChain,
)) satisfies Txs;

const cuToRemoveTxs = (
await populateCUToRemoveTxs(offer, peersOnChain)
).flat() satisfies Txs;

const removeOfferTx = await populateOfferRemoveTx(offer);

return {
offerName,
offerId,
removePeersFromOffersTxs,
cuToRemoveTxs,
removeOfferTx,
};
}),
);
}

async function populatePeersToRemoveTxs(
{ computePeersFromProviderConfig }: OnChainOffer,
peersOnChain: PeersOnChain,
Expand Down Expand Up @@ -374,6 +475,15 @@ async function populateCUToRemoveTxs(
});
}

async function populateOfferRemoveTx({ offerId }: OnChainOffer) {
const { dealClient } = await getDealClient();
const market = dealClient.getMarket();
return {
description: `\nRemoving offer: ${offerId}`,
tx: populateTx(market.removeOffer, offerId),
};
}

async function populateCUToAddTxs(
{ computePeersFromProviderConfig }: OnChainOffer,
peersOnChain: PeersOnChain,
Expand Down Expand Up @@ -484,3 +594,44 @@ function printOffersToUpdateInfo(
.join("\n\n")}`,
);
}

function printOffersToRemoveInfo(
populatedTxs: Awaited<ReturnType<typeof populateRemoveOffersTxs>>,
) {
commandObj.logToStderr(
`Offers to remove:\n\n${populatedTxs
.flatMap(
({
offerId,
offerName,
removePeersFromOffersTxs,
cuToRemoveTxs,
removeOfferTx,
}) => {
const allTxs = [
...removePeersFromOffersTxs,
...cuToRemoveTxs,
removeOfferTx,
];

if (allTxs.length === 0) {
return [];
}

return [
`Offer ${color.green(offerName)} with id ${color.yellow(
offerId,
)}:\n${allTxs
.filter((tx): tx is typeof tx & { description: string } => {
return "description" in tx;
})
.map(({ description }) => {
return description;
})
.join("\n")}\n`,
];
},
)
.join("\n\n")}`,
);
}
Loading