diff --git a/cli/docs/commands/README.md b/cli/docs/commands/README.md index fdda11626..31aafbce8 100644 --- a/cli/docs/commands/README.md +++ b/cli/docs/commands/README.md @@ -1673,12 +1673,14 @@ Remove offers ``` USAGE - $ fluence provider offer-remove [--no-input] [--offers ] [--env ] [--priv-key ] + $ fluence provider offer-remove [--no-input] [--offers | --offer-ids ] [--env ] [--priv-key ] FLAGS --env= Fluence Environment to use when running the command --no-input Don't interactively ask for any input from the user + --offer-ids= Comma-separated list of offer ids. Can't be used together with + --offers flag --offers= Comma-separated list of offer names. To use all of your offers: --offers all --priv-key= !WARNING! for debug purposes only. Passing private keys through diff --git a/cli/src/commands/provider/offer-remove.ts b/cli/src/commands/provider/offer-remove.ts index b8445075d..1e22bc897 100644 --- a/cli/src/commands/provider/offer-remove.ts +++ b/cli/src/commands/provider/offer-remove.ts @@ -17,7 +17,7 @@ import { BaseCommand, baseFlags } from "../../baseCommand.js"; import { removeOffers } from "../../lib/chain/offer/updateOffers.js"; -import { CHAIN_FLAGS, OFFER_FLAG } from "../../lib/const.js"; +import { CHAIN_FLAGS, OFFER_FLAGS } from "../../lib/const.js"; import { initCli } from "../../lib/lifeCycle.js"; export default class OfferRemove extends BaseCommand { @@ -25,7 +25,7 @@ export default class OfferRemove extends BaseCommand { static override description = "Remove offers"; static override flags = { ...baseFlags, - ...OFFER_FLAG, + ...OFFER_FLAGS, ...CHAIN_FLAGS, }; diff --git a/cli/src/lib/chain/chainValidators.ts b/cli/src/lib/chain/chainValidators.ts index de9ff8728..0bba41093 100644 --- a/cli/src/lib/chain/chainValidators.ts +++ b/cli/src/lib/chain/chainValidators.ts @@ -71,32 +71,38 @@ export async function validateAddress( return `Must be a valid address. Got: ${color.yellow(stringifyUnknown(input))}`; } -async function getProtocolVersions() { - let minProtocolVersion = BigInt(versions.protocolVersion); - let maxProtocolVersion = minProtocolVersion; - - if ((await ensureChainEnv()) !== "local") { - const { readonlyDealClient } = await getReadonlyDealClient(); - const core = readonlyDealClient.getCore(); - - [minProtocolVersion, maxProtocolVersion] = await Promise.all([ - core.minProtocolVersion(), - core.maxProtocolVersion(), - ]); +let protocolVersions: + | undefined + | Promise<{ minProtocolVersion: bigint; maxProtocolVersion: bigint }>; + +export async function getProtocolVersions() { + if (protocolVersions === undefined) { + protocolVersions = (async () => { + let minProtocolVersion = BigInt(versions.protocolVersion); + let maxProtocolVersion = minProtocolVersion; + + if ((await ensureChainEnv()) !== "local") { + const { readonlyDealClient } = await getReadonlyDealClient(); + const core = readonlyDealClient.getCore(); + + [minProtocolVersion, maxProtocolVersion] = await Promise.all([ + core.minProtocolVersion(), + core.maxProtocolVersion(), + ]); + } + + return { minProtocolVersion, maxProtocolVersion }; + })(); } - return { minProtocolVersion, maxProtocolVersion }; + return protocolVersions; } -let protocolVersions: undefined | ReturnType; - export async function validateProtocolVersion( protocolVersion: number, ): Promise { - protocolVersions = - protocolVersions === undefined ? getProtocolVersions() : protocolVersions; - - const { minProtocolVersion, maxProtocolVersion } = await protocolVersions; + const { minProtocolVersion, maxProtocolVersion } = + await getProtocolVersions(); if ( protocolVersion < minProtocolVersion || diff --git a/cli/src/lib/chain/commitment.ts b/cli/src/lib/chain/commitment.ts index 6d46accbc..edafaf307 100644 --- a/cli/src/lib/chain/commitment.ts +++ b/cli/src/lib/chain/commitment.ts @@ -63,7 +63,7 @@ import { import { peerIdHexStringToBase58String, - peerIdToUint8Array, + peerIdBase58ToUint8Array, } from "./conversions.js"; import { fltFormatWithSymbol, fltParse } from "./currencies.js"; @@ -98,7 +98,9 @@ export async function getComputePeersWithCC( const computePeersWithChainInfo = ( await Promise.all( computePeers.map(async (computePeer) => { - const peerIdUint8Array = await peerIdToUint8Array(computePeer.peerId); + const peerIdUint8Array = await peerIdBase58ToUint8Array( + computePeer.peerId, + ); const commitmentCreatedEvent = commitmentCreatedEvents[computePeer.peerId]; @@ -225,7 +227,7 @@ export async function createCommitments(flags: { let peerIdUint8Arr; try { - peerIdUint8Arr = await peerIdToUint8Array(peerId); + peerIdUint8Arr = await peerIdBase58ToUint8Array(peerId); } catch (e) { return { error: `Invalid peerId: ${peerId}. Error: ${stringifyUnknown(e)}`, diff --git a/cli/src/lib/chain/conversions.ts b/cli/src/lib/chain/conversions.ts index 4f693cd20..caf9b7867 100644 --- a/cli/src/lib/chain/conversions.ts +++ b/cli/src/lib/chain/conversions.ts @@ -20,7 +20,7 @@ import type { CIDV1Struct } from "@fluencelabs/deal-ts-clients/dist/typechain-ty const PREFIX = new Uint8Array([0, 36, 8, 1, 18, 32]); const BASE_58_PREFIX = "z"; -export async function peerIdToUint8Array(peerId: string) { +export async function peerIdBase58ToUint8Array(peerIdBase58: string) { const [{ digest }, { base58btc }] = await Promise.all([ import("multiformats"), @@ -28,7 +28,7 @@ export async function peerIdToUint8Array(peerId: string) { ]); return digest - .decode(base58btc.decode(BASE_58_PREFIX + peerId)) + .decode(base58btc.decode(BASE_58_PREFIX + peerIdBase58)) .bytes.subarray(PREFIX.length); } diff --git a/cli/src/lib/chain/offer/offer.ts b/cli/src/lib/chain/offer/offer.ts index 5b28a6095..c62088575 100644 --- a/cli/src/lib/chain/offer/offer.ts +++ b/cli/src/lib/chain/offer/offer.ts @@ -61,10 +61,11 @@ import { } from "../../helpers/utils.js"; import { checkboxes } from "../../prompt.js"; import { ensureFluenceEnv } from "../../resolveFluenceEnv.js"; +import { getProtocolVersions } from "../chainValidators.js"; import { cidStringToCIDV1Struct, peerIdHexStringToBase58String, - peerIdToUint8Array, + peerIdBase58ToUint8Array, } from "../conversions.js"; import { ptParse } from "../currencies.js"; import { assertProviderIsRegistered } from "../providerInfo.js"; @@ -74,6 +75,7 @@ const OFFER_ID_PROPERTY = "offerId"; export type OffersArgs = { [OFFER_FLAG_NAME]?: string | undefined; + [OFFER_IDS_FLAG_NAME]?: string | undefined; force?: boolean | undefined; }; @@ -530,8 +532,110 @@ async function formatOfferInfo( export async function resolveOffersFromProviderConfig( flags: OffersArgs, ): Promise { + if ( + flags[OFFER_FLAG_NAME] !== undefined && + flags[OFFER_IDS_FLAG_NAME] !== undefined + ) { + commandObj.error( + `You can't use both ${color.yellow( + `--${OFFER_FLAG_NAME}`, + )} and ${color.yellow( + `--${OFFER_IDS_FLAG_NAME}`, + )} flags at the same time. Please pick one of them`, + ); + } + const allOffers = await ensureOfferConfigs(); + if (flags[OFFER_IDS_FLAG_NAME] !== undefined) { + const offerIdsFromFlags = commaSepStrToArr(flags[OFFER_IDS_FLAG_NAME]); + const offerIdsFromFlagsSet = new Set(offerIdsFromFlags); + + const offersDefinedLocally = allOffers.filter(({ offerId }) => { + return offerId !== undefined && offerIdsFromFlagsSet.has(offerId); + }); + + const offersDefinedLocallySet = new Set( + offersDefinedLocally.map(({ offerId }) => { + return offerId; + }), + ); + + const offerIdsNotDefinedLocally = offerIdsFromFlags.filter((offerId) => { + return !offersDefinedLocallySet.has(offerId); + }); + + const [offerInfosErrors, offerInfos] = await getOffersInfo( + offerIdsNotDefinedLocally.map((offerId) => { + return { offerId }; + }), + ); + + if (offerInfosErrors.length > 0) { + commandObj.warn( + `Wasn't able to get info about the following offers from indexer:\n\n${offerInfosErrors + .map(({ offerId }) => { + return offerId; + }) + .join("\n")}`, + ); + } + + const protocolVersionsFromChain = await getProtocolVersions(); + + const offersNotDefinedLocally = await Promise.all( + offerInfos.map(async ({ offerId, offerIndexerInfo }) => { + return { + offerName: `Offer ${offerId}`, + minPricePerCuPerEpochBigInt: await ptParse( + offerIndexerInfo.pricePerEpoch, + ), + effectorPrefixesAndHash: await Promise.all( + offerIndexerInfo.effectors.map(({ cid }) => { + return cidStringToCIDV1Struct(cid); + }), + ), + effectors: offerIndexerInfo.effectors.map(({ cid }) => { + return cid; + }), + computePeersFromProviderConfig: await Promise.all( + offerIndexerInfo.peers.map(async ({ computeUnits, id }, i) => { + const peerIdBase58 = await peerIdHexStringToBase58String(id); + return { + name: `Peer #${numToStr(i)}`, + peerIdBase58, + peerId: await peerIdBase58ToUint8Array(peerIdBase58), + unitIds: computeUnits.map(({ id }) => { + return new Uint8Array(Buffer.from(id.slice(2), "hex")); + }), + owner: offerIndexerInfo.providerId, + }; + }), + ), + offerId, + minProtocolVersion: Number( + protocolVersionsFromChain.minProtocolVersion, + ), + maxProtocolVersion: Number( + protocolVersionsFromChain.maxProtocolVersion, + ), + }; + }), + ); + + return offerIdsFromFlags.flatMap((offerId) => { + const offer = + offersDefinedLocally.find((o) => { + return o.offerId === offerId; + }) ?? + offersNotDefinedLocally.find((o) => { + return o.offerId === offerId; + }); + + return offer === undefined ? [] : [offer]; + }); + } + if (flags[OFFER_FLAG_NAME] === ALL_FLAG_VALUE) { return allOffers; } @@ -630,7 +734,7 @@ async function ensureOfferConfigs() { return { name, peerIdBase58: peerId, - peerId: await peerIdToUint8Array(peerId), + peerId: await peerIdBase58ToUint8Array(peerId), unitIds: times(computeUnits).map(() => { return ethers.randomBytes(32); }), diff --git a/cli/src/lib/configs/project/provider.ts b/cli/src/lib/configs/project/provider.ts index 2d3c89a17..00a74338c 100644 --- a/cli/src/lib/configs/project/provider.ts +++ b/cli/src/lib/configs/project/provider.ts @@ -57,7 +57,7 @@ import { IPFS_PORT, defaultNumberProperties, DEFAULT_CC_DURATION, - DEFAULT_CC_REWARD_DELEGATION_RATE, + DEFAULT_CC_STAKER_REWARD, DURATION_EXAMPLE, DEFAULT_NUMBER_OF_COMPUTE_UNITS_ON_NOX, WS_CHAIN_URLS, @@ -128,7 +128,7 @@ const capacityCommitmentSchemaV0 = { minimum: 0, maximum: 100, description: "Reward delegation rate in percent", - default: DEFAULT_CC_REWARD_DELEGATION_RATE, + default: DEFAULT_CC_STAKER_REWARD, }, }, } as const satisfies JSONSchemaType; @@ -161,7 +161,7 @@ const capacityCommitmentSchemaV1 = { minimum: 0, maximum: 100, description: "Staker reward in percent", - default: DEFAULT_CC_REWARD_DELEGATION_RATE, + default: DEFAULT_CC_STAKER_REWARD, }, }, } as const satisfies JSONSchemaType; @@ -1407,7 +1407,7 @@ function getDefault(args: ProviderConfigArgs) { noxName, { duration: DEFAULT_CC_DURATION, - stakerReward: DEFAULT_CC_REWARD_DELEGATION_RATE, + stakerReward: DEFAULT_CC_STAKER_REWARD, }, ] as const; }), diff --git a/cli/src/lib/const.ts b/cli/src/lib/const.ts index bd0551e84..5f5501d17 100644 --- a/cli/src/lib/const.ts +++ b/cli/src/lib/const.ts @@ -863,7 +863,7 @@ export const READMEs: Record = { export const DEFAULT_OFFER_NAME = "defaultOffer"; -export const DEFAULT_CC_REWARD_DELEGATION_RATE = 7; +export const DEFAULT_CC_STAKER_REWARD = 20; export const DEFAULT_CC_DURATION = "100 days"; export const DURATION_EXAMPLE = "in human-readable format. Example: 1 months 1 days"; diff --git a/cli/src/lib/deal.ts b/cli/src/lib/deal.ts index ce1b636ba..b6d504be4 100644 --- a/cli/src/lib/deal.ts +++ b/cli/src/lib/deal.ts @@ -23,7 +23,7 @@ import { versions } from "../versions.js"; import { cidStringToCIDV1Struct, - peerIdToUint8Array, + peerIdBase58ToUint8Array, } from "./chain/conversions.js"; import { ptFormatWithSymbol, ptParse } from "./chain/currencies.js"; import { commandObj } from "./commandObj.js"; @@ -178,7 +178,7 @@ export async function createAndMatchDealsForPeerIds({ const offersWithCUs = await Promise.all( peerIds.map(async (peerId) => { - const peerIdUint8Array = await peerIdToUint8Array(peerId); + const peerIdUint8Array = await peerIdBase58ToUint8Array(peerId); const computeUnits = ( await Promise.all( diff --git a/cli/src/lib/generateUserProviderConfig.ts b/cli/src/lib/generateUserProviderConfig.ts index 8573d834c..4be21efb2 100644 --- a/cli/src/lib/generateUserProviderConfig.ts +++ b/cli/src/lib/generateUserProviderConfig.ts @@ -31,7 +31,7 @@ import { defaultNumberProperties, type CurrencyProperty, currencyProperties, - DEFAULT_CC_REWARD_DELEGATION_RATE, + DEFAULT_CC_STAKER_REWARD, DURATION_EXAMPLE, DEFAULT_NUMBER_OF_COMPUTE_UNITS_ON_NOX, } from "./const.js"; @@ -108,7 +108,7 @@ export async function addComputePeers( const capacityCommitmentStakerReward = await input({ message: `Enter capacity commitment staker reward (in %)`, - default: numToStr(DEFAULT_CC_REWARD_DELEGATION_RATE), + default: numToStr(DEFAULT_CC_STAKER_REWARD), validate: validatePercent, });