diff --git a/packages/core/scripts/contracts-check.ts b/packages/core/scripts/contracts-check.ts index 64b5a9b0b..7db676296 100644 --- a/packages/core/scripts/contracts-check.ts +++ b/packages/core/scripts/contracts-check.ts @@ -3,6 +3,8 @@ import path from "path"; import { fileURLToPath } from "url"; import { promisify } from "util"; +import { ContractsCheckError } from "../src/errors/config.js"; + const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -10,12 +12,14 @@ const execAsync = promisify(exec); const outputFilePath = path.resolve(__dirname, "..", "src", "contracts.ts"); +const docsPath = "/nft-contracts"; +const docsSlug = "list-all-nft-contracts"; async function run() { try { const { stderr } = await execAsync(`tsc --noEmit ${outputFilePath}`); if (stderr) { - throw new Error(stderr); + throw new ContractsCheckError(stderr, { docsPath, docsSlug }); } console.log("Contracts file is valid TypeScript."); diff --git a/packages/core/src/actions/account/account.ts b/packages/core/src/actions/account/account.ts index b0e6889f3..895fd544f 100644 --- a/packages/core/src/actions/account/account.ts +++ b/packages/core/src/actions/account/account.ts @@ -8,7 +8,9 @@ import { } from "starknet"; import { SOLIS_ACCOUNT_CLASS_HASH } from "../../constants.js"; +import { AccountDeployFailedError } from "../../errors/actions.js"; +const docsPath = "sdk-core/create-account"; /** * Creates a new account on the StarkNet testnet. * This function generates a private key, derives the corresponding public key, @@ -53,11 +55,11 @@ export const createAccount = async (provider: ProviderInterface) => { addressSalt: publicKey }); } catch (e) { - throw new Error(`Account deploy failed for ${address}`); + throw new AccountDeployFailedError(address, { docsPath }); } if (!response) { - throw new Error(`Account deploy failed for ${address}`); + throw new AccountDeployFailedError(address, { docsPath }); } const { transaction_hash, contract_address } = response; diff --git a/packages/core/src/actions/fees/setArkFees.ts b/packages/core/src/actions/fees/setArkFees.ts index 529c05968..4ff10b105 100644 --- a/packages/core/src/actions/fees/setArkFees.ts +++ b/packages/core/src/actions/fees/setArkFees.ts @@ -1,6 +1,7 @@ import { Account, cairo, CallData } from "starknet"; import { Config } from "../../createConfig.js"; +import { InvalidFeesRatioError } from "../../errors/actions.js"; import { validateFeesRatio } from "../../utils/index.js"; interface Params { @@ -11,7 +12,7 @@ interface Params { export const setArkFees = async (config: Config, params: Params) => { if (!validateFeesRatio(params.numerator, params.denominator)) { - throw new Error("Invalid fees ratio"); + throw new InvalidFeesRatioError(); } const result = await params.account.execute({ diff --git a/packages/core/src/actions/fees/setBrokerFees.ts b/packages/core/src/actions/fees/setBrokerFees.ts index 2e564735e..2d98a4520 100644 --- a/packages/core/src/actions/fees/setBrokerFees.ts +++ b/packages/core/src/actions/fees/setBrokerFees.ts @@ -1,6 +1,7 @@ import { Account, cairo, CallData } from "starknet"; import { Config } from "../../createConfig.js"; +import { InvalidFeesRatioError } from "../../errors/actions.js"; import { validateFeesRatio } from "../../utils/index.js"; interface Params { @@ -11,7 +12,7 @@ interface Params { export const setBrokerFees = async (config: Config, params: Params) => { if (!validateFeesRatio(params.numerator, params.denominator)) { - throw new Error("Invalid fees ratio"); + throw new InvalidFeesRatioError(); } const result = await params.brokerAccount.execute({ diff --git a/packages/core/src/actions/fees/setCollectionCreatorFees.ts b/packages/core/src/actions/fees/setCollectionCreatorFees.ts index f02286a2c..26bd795d1 100644 --- a/packages/core/src/actions/fees/setCollectionCreatorFees.ts +++ b/packages/core/src/actions/fees/setCollectionCreatorFees.ts @@ -1,6 +1,7 @@ import { Account, cairo, CallData } from "starknet"; import { Config } from "../../createConfig.js"; +import { InvalidFeesRatioError } from "../../errors/actions.js"; import { validateFeesRatio } from "../../utils/index.js"; interface Params { @@ -16,7 +17,7 @@ export const setCollectionCreatorFees = async ( params: Params ) => { if (!validateFeesRatio(params.numerator, params.denominator)) { - throw new Error("Invalid fees ratio"); + throw new InvalidFeesRatioError(); } const result = await params.account.execute({ diff --git a/packages/core/src/actions/fees/setDefaultCreatorFees.ts b/packages/core/src/actions/fees/setDefaultCreatorFees.ts index dd30ec4a0..22b5c1f31 100644 --- a/packages/core/src/actions/fees/setDefaultCreatorFees.ts +++ b/packages/core/src/actions/fees/setDefaultCreatorFees.ts @@ -1,6 +1,7 @@ import { Account, cairo, CallData } from "starknet"; import { Config } from "../../createConfig.js"; +import { InvalidFeesRatioError } from "../../errors/actions.js"; import { validateFeesRatio } from "../../utils/index.js"; interface Params { @@ -12,7 +13,7 @@ interface Params { export const setDefaultCreatorFees = async (config: Config, params: Params) => { if (!validateFeesRatio(params.numerator, params.denominator)) { - throw new Error("Invalid fees ratio"); + throw new InvalidFeesRatioError(); } const result = await params.account.execute({ diff --git a/packages/core/src/actions/order/createAuction.ts b/packages/core/src/actions/order/createAuction.ts index d09647835..e55a521c8 100644 --- a/packages/core/src/actions/order/createAuction.ts +++ b/packages/core/src/actions/order/createAuction.ts @@ -8,6 +8,13 @@ import { } from "starknet"; import { Config } from "../../createConfig.js"; +import { + EndDateTooFarError, + InvalidEndAmountError, + InvalidEndDateError, + InvalidStartAmountError, + InvalidStartDateError +} from "../../errors/actions.js"; import { OrderV1, RouteType } from "../../types/index.js"; import { getOrderHashFromOrderV1 } from "../../utils/index.js"; @@ -29,6 +36,7 @@ export interface CreateAuctionResult { transactionHash: string; } +const docsPath = "/sdk-core/create-auction"; /** * Creates an Auction on the ArkProject. * @@ -65,33 +73,23 @@ export async function createAuction( const maxEndedAt = now + 60 * 60 * 24 * 30; if (startedAt < now) { - throw new Error( - `Invalid start date. Start date (${startDate}) cannot be in the past.` - ); + throw new InvalidStartDateError(startDate, { docsPath }); } if (endedAt < startedAt) { - throw new Error( - `Invalid end date. End date (${endDate}) must be after the start date (${startDate}).` - ); + throw new InvalidEndDateError({ endDate, startDate }, { docsPath }); } if (endedAt > maxEndedAt) { - throw new Error( - `End date too far in the future. End date (${endDate}) exceeds the maximum allowed (${maxEndedAt}).` - ); + throw new EndDateTooFarError({ endDate, maxEndedAt }, { docsPath }); } if (startAmount === BigInt(0)) { - throw new Error( - "Invalid start amount. The start amount must be greater than zero." - ); + throw new InvalidStartAmountError({ docsPath }); } if (endAmount && endAmount < startAmount) { - throw new Error( - "Invalid end amount. The end amount must be greater than the start amount." - ); + throw new InvalidEndAmountError({ docsPath }); } const chainId = await config.starknetProvider.getChainId(); diff --git a/packages/core/src/actions/order/createCollectionOffer.ts b/packages/core/src/actions/order/createCollectionOffer.ts index bfb004197..579ff4072 100644 --- a/packages/core/src/actions/order/createCollectionOffer.ts +++ b/packages/core/src/actions/order/createCollectionOffer.ts @@ -8,6 +8,12 @@ import { } from "starknet"; import { Config } from "../../createConfig.js"; +import { + EndDateTooFarError, + InvalidEndDateError, + InvalidStartAmountError, + InvalidStartDateError +} from "../../errors/actions.js"; import { OrderV1, RouteType } from "../../types/index.js"; import { getOrderHashFromOrderV1 } from "../../utils/index.js"; import { getAllowance } from "../read/getAllowance.js"; @@ -28,6 +34,7 @@ export interface CreateCollectionOfferResult { transactionHash: string; } +const docsPath = "/sdk-core/create-collection-offer"; /** * Creates a collection offer on the ArkProject. * @@ -62,27 +69,19 @@ async function createCollectionOffer( const maxEndedAt = now + 60 * 60 * 24 * 30; if (startedAt < now) { - throw new Error( - `Invalid start date. Start date (${startDate}) cannot be in the past.` - ); + throw new InvalidStartDateError(startDate, { docsPath }); } if (endedAt < startedAt) { - throw new Error( - `Invalid end date. End date (${endDate}) must be after the start date (${startDate}).` - ); + throw new InvalidEndDateError({ endDate, startDate }, { docsPath }); } if (endedAt > maxEndedAt) { - throw new Error( - `End date too far in the future. End date (${endDate}) exceeds the maximum allowed (${maxEndedAt}).` - ); + throw new EndDateTooFarError({ endDate, maxEndedAt }, { docsPath }); } if (amount === BigInt(0)) { - throw new Error( - "Invalid start amount. The start amount must be greater than zero." - ); + throw new InvalidStartAmountError({ docsPath }); } const chainId = await config.starknetProvider.getChainId(); diff --git a/packages/core/src/actions/order/createListing.ts b/packages/core/src/actions/order/createListing.ts index a8fa195ed..8bb727d14 100644 --- a/packages/core/src/actions/order/createListing.ts +++ b/packages/core/src/actions/order/createListing.ts @@ -8,6 +8,12 @@ import { } from "starknet"; import { Config } from "../../createConfig.js"; +import { + EndDateTooFarError, + InvalidEndDateError, + InvalidStartAmountError, + InvalidStartDateError +} from "../../errors/actions.js"; import { OrderV1, RouteType } from "../../types/index.js"; import { getOrderHashFromOrderV1 } from "../../utils/index.js"; @@ -28,6 +34,7 @@ export interface CreateListingResult { transactionHash: string; } +const docsPath = "/sdk-core/create-listing"; /** * Creates a listing on the ArkProject. * @@ -63,27 +70,19 @@ export async function createListing( const maxEndedAt = now + 60 * 60 * 24 * 30; if (startedAt < now) { - throw new Error( - `Invalid start date. Start date (${startDate}) cannot be in the past.` - ); + throw new InvalidStartDateError(startDate, { docsPath }); } if (endedAt < startedAt) { - throw new Error( - `Invalid end date. End date (${endDate}) must be after the start date (${startDate}).` - ); + throw new InvalidEndDateError({ endDate, startDate }, { docsPath }); } if (endedAt > maxEndedAt) { - throw new Error( - `End date too far in the future. End date (${endDate}) exceeds the maximum allowed (${maxEndedAt}).` - ); + throw new EndDateTooFarError({ endDate, maxEndedAt }, { docsPath }); } if (amount === BigInt(0)) { - throw new Error( - "Invalid start amount. The start amount must be greater than zero." - ); + throw new InvalidStartAmountError({ docsPath }); } const chainId = await config.starknetProvider.getChainId(); diff --git a/packages/core/src/actions/order/createOffer.ts b/packages/core/src/actions/order/createOffer.ts index 4dfbe7b21..7681c6447 100644 --- a/packages/core/src/actions/order/createOffer.ts +++ b/packages/core/src/actions/order/createOffer.ts @@ -8,6 +8,12 @@ import { } from "starknet"; import { Config } from "../../createConfig.js"; +import { + EndDateTooFarError, + InvalidEndDateError, + InvalidStartAmountError, + InvalidStartDateError +} from "../../errors/actions.js"; import { OrderV1, RouteType } from "../../types/index.js"; import { getOrderHashFromOrderV1 } from "../../utils/index.js"; import { getAllowance } from "../read/getAllowance.js"; @@ -29,6 +35,7 @@ export interface CreateOfferResult { transactionHash: string; } +const docsPath = "/sdk-core/create-offer"; /** * Creates a listing on the ArkProject. * @@ -64,27 +71,19 @@ export async function createOffer( const maxEndedAt = now + 60 * 60 * 24 * 30; if (startedAt < Math.floor(Date.now() / 1000)) { - throw new Error( - `Invalid start date. Start date (${startDate}) cannot be in the past.` - ); + throw new InvalidStartDateError(startDate, { docsPath }); } if (endedAt < startedAt) { - throw new Error( - `Invalid end date. End date (${endDate}) must be after the start date (${startDate}).` - ); + throw new InvalidEndDateError({ endDate, startDate }, { docsPath }); } if (endedAt > maxEndedAt) { - throw new Error( - `End date too far in the future. End date (${endDate}) exceeds the maximum allowed (${maxEndedAt}).` - ); + throw new EndDateTooFarError({ endDate, maxEndedAt }, { docsPath }); } if (amount === BigInt(0)) { - throw new Error( - "Invalid start amount. The start amount must be greater than zero." - ); + throw new InvalidStartAmountError({ docsPath }); } const chainId = await config.starknetProvider.getChainId(); diff --git a/packages/core/src/actions/read/getAllowance.ts b/packages/core/src/actions/read/getAllowance.ts index 7ff5ba034..d01880e1b 100644 --- a/packages/core/src/actions/read/getAllowance.ts +++ b/packages/core/src/actions/read/getAllowance.ts @@ -1,6 +1,7 @@ import { Contract } from "starknet"; import { Config } from "../../createConfig.js"; +import { NoABIError } from "../../errors/actions.js"; export const getAllowance = async ( config: Config, @@ -10,7 +11,7 @@ export const getAllowance = async ( const { abi } = await config.starknetProvider.getClassAt(ERC20ContractAddress); if (abi === undefined) { - throw new Error("no abi."); + throw new NoABIError({ docsPath: "/sdk-core/fulfill-listing" }); } const ERC20Contract = new Contract( diff --git a/packages/core/src/actions/read/getNFTOwner.ts b/packages/core/src/actions/read/getNFTOwner.ts index 331c79b50..c63a2d17f 100644 --- a/packages/core/src/actions/read/getNFTOwner.ts +++ b/packages/core/src/actions/read/getNFTOwner.ts @@ -1,6 +1,7 @@ import { cairo, CallData, Contract } from "starknet"; import { Config } from "../../createConfig.js"; +import { NoABIError } from "../../errors/actions.js"; export const getNftOwner = async ( config: Config, @@ -9,7 +10,7 @@ export const getNftOwner = async ( ) => { const { abi } = await config.starknetProvider.getClassAt(nftContractAddress); if (abi === undefined) { - throw new Error("no abi."); + throw new NoABIError({ docsPath: "/sdk-core/get-nft-owner" }); } const nftContract = new Contract( diff --git a/packages/core/src/actions/read/getOrder.ts b/packages/core/src/actions/read/getOrder.ts index 1f67179d0..8820991b1 100644 --- a/packages/core/src/actions/read/getOrder.ts +++ b/packages/core/src/actions/read/getOrder.ts @@ -1,6 +1,7 @@ import { CallData, Contract } from "starknet"; import { Config } from "../../createConfig.js"; +import { NoABIError } from "../../errors/actions.js"; interface GetOrderParameters { orderHash: bigint; @@ -12,7 +13,7 @@ const getOrder = async (config: Config, parameters: GetOrderParameters) => { config.starknetExecutorContract ); if (orderbookAbi === undefined) { - throw new Error("no abi."); + throw new NoABIError({ docsPath: "/sdk-core/get-order" }); } const orderbookContract = new Contract( diff --git a/packages/core/src/actions/read/getOrderHash.ts b/packages/core/src/actions/read/getOrderHash.ts index e0fe8045b..98d164c26 100644 --- a/packages/core/src/actions/read/getOrderHash.ts +++ b/packages/core/src/actions/read/getOrderHash.ts @@ -2,6 +2,7 @@ import * as starknet from "@scure/starknet"; import { cairo, CallData, Contract, shortString } from "starknet"; import { Config } from "../../createConfig.js"; +import { NoABIError } from "../../errors/actions.js"; interface GetOrderHashParameters { tokenId: bigint; @@ -33,7 +34,7 @@ const getOrderHash = async ( config.starknetExecutorContract ); if (executorAbi === undefined) { - throw new Error("no abi."); + throw new NoABIError({ docsPath: "/sdk-core/get-order-hash" }); } const orderbookContract = new Contract( diff --git a/packages/core/src/actions/read/getOrderSigner.ts b/packages/core/src/actions/read/getOrderSigner.ts index 2491ac92e..dfcccc714 100644 --- a/packages/core/src/actions/read/getOrderSigner.ts +++ b/packages/core/src/actions/read/getOrderSigner.ts @@ -1,6 +1,7 @@ import { CallData, Contract } from "starknet"; import { Config } from "../../createConfig.js"; +import { NoABIError } from "../../errors/actions.js"; interface GetOrderSignerParameters { orderHash: bigint; @@ -15,7 +16,7 @@ const getOrderSigner = async ( config.starknetExecutorContract ); if (executorAbi === undefined) { - throw new Error("no abi."); + throw new NoABIError({ docsPath: "/sdk-core/get-order-signer" }); } const orderbookContract = new Contract( diff --git a/packages/core/src/actions/read/getOrderStatus.ts b/packages/core/src/actions/read/getOrderStatus.ts index 47c31224e..0a61eb6e3 100644 --- a/packages/core/src/actions/read/getOrderStatus.ts +++ b/packages/core/src/actions/read/getOrderStatus.ts @@ -1,6 +1,7 @@ import { CairoCustomEnum, CallData, Contract } from "starknet"; import { Config } from "../../createConfig.js"; +import { NoABIError } from "../../errors/actions.js"; interface GetOrderStatusParameters { orderHash: bigint; @@ -15,7 +16,7 @@ const getOrderStatus = async ( config.starknetExecutorContract ); if (executorAbi === undefined) { - throw new Error("no abi."); + throw new NoABIError({ docsPath: "/sdk-core/get-order-status" }); } const orderbookContract = new Contract( diff --git a/packages/core/src/actions/read/getOrderType.ts b/packages/core/src/actions/read/getOrderType.ts index c7995f22e..48ecf4c8b 100644 --- a/packages/core/src/actions/read/getOrderType.ts +++ b/packages/core/src/actions/read/getOrderType.ts @@ -1,6 +1,7 @@ import { CairoCustomEnum, CallData, Contract } from "starknet"; import { Config } from "../../createConfig.js"; +import { NoABIError } from "../../errors/actions.js"; interface GetOrderTypeParameters { orderHash: bigint; @@ -15,7 +16,7 @@ const getOrderType = async ( config.starknetExecutorContract ); if (executorAbi === undefined) { - throw new Error("no abi."); + throw new NoABIError({ docsPath: "/sdk-core/get-order-type" }); } const orderbookContract = new Contract( diff --git a/packages/core/src/createConfig.ts b/packages/core/src/createConfig.ts index 0ac92416d..316c117f8 100644 --- a/packages/core/src/createConfig.ts +++ b/packages/core/src/createConfig.ts @@ -6,6 +6,7 @@ import { starknetExecutorContracts, starknetRpcUrls } from "./constants.js"; +import { MissingExecutorContractError } from "./errors/config.js"; export type Network = "mainnet" | "sepolia" | "dev"; @@ -25,6 +26,8 @@ export type CreateConfigParameters = { starknetCurrencyContract?: string; }; +const docsPath = "/sdk-core/configuration"; +const docsSlug = "starknetExecutorContract"; export function createConfig({ starknetNetwork, starknetRpcUrl, @@ -33,7 +36,7 @@ export function createConfig({ starknetCurrencyContract = starknetEthContract }: CreateConfigParameters): Config { if (starknetNetwork === networks.dev && !starknetExecutorContract) { - throw new Error("Executor contract address is required for dev network"); + throw new MissingExecutorContractError({ docsPath, docsSlug }); } return { diff --git a/packages/core/src/errors/account.ts b/packages/core/src/errors/account.ts new file mode 100644 index 000000000..48043ac4c --- /dev/null +++ b/packages/core/src/errors/account.ts @@ -0,0 +1,18 @@ +import { BaseError, BaseErrorOptions } from "./base.js"; + +export type NoAccountFoundErrorType = NoAccountFoundError & { + name: "NoAccountFoundError"; +}; +export class NoAccountFoundError extends BaseError { + override name = "NoAccountFoundError"; + constructor({ docsPath, docsSlug }: BaseErrorOptions) { + super("No account found", { docsPath, docsSlug }); + } +} + +export class AccountNotConnectedError extends BaseError { + override name = "AccountNotConnectedError"; + constructor({ docsPath, docsSlug }: BaseErrorOptions) { + super("Account not connected", { docsPath, docsSlug }); + } +} diff --git a/packages/core/src/errors/actions.ts b/packages/core/src/errors/actions.ts new file mode 100644 index 000000000..e037678b8 --- /dev/null +++ b/packages/core/src/errors/actions.ts @@ -0,0 +1,121 @@ +import { BaseError, BaseErrorOptions } from "./base.js"; + +export type UndefinedNFTContractAddressErrorType = + UndefinedNFTContractAddressError & { + name: "UndefinedNFTContractAddressErrorType"; + }; +export class UndefinedNFTContractAddressError extends BaseError { + override name = "UndefinedNFTContractAddressError"; + constructor({ docsPath, docsSlug }: BaseErrorOptions) { + super("NFT contract address is not defined", { docsPath, docsSlug }); + } +} + +export type NoABIErrorType = NoABIError & { + name: "NoABIError"; +}; +export class NoABIError extends BaseError { + override name = "NoABIError"; + constructor({ docsPath, docsSlug }: BaseErrorOptions) { + super("No ABI", { docsPath, docsSlug }); + } +} + +export type AccountDeployFailedErrorType = AccountDeployFailedError & { + name: "AccountDeployFailedError"; +}; +export class AccountDeployFailedError extends BaseError { + override name = "AccountDeployFailedError"; + constructor(address: string, { docsPath }: BaseErrorOptions) { + super(`Account deploy failed for ${address}`, { docsPath }); + } +} + +export type InvalidFeesRatioErrorType = InvalidFeesRatioError & { + name: "InvalidFeesRatioError"; +}; +export class InvalidFeesRatioError extends BaseError { + override name = "InvalidFeesRatioError"; + constructor() { + super("Invalid fees ratio", { + docsPath: "/errors", + docsSlug: "error-types" + }); + } +} + +export type InvalidStartDateErrorType = InvalidFeesRatioError & { + name: "InvalidStartDateErrorType"; +}; +export class InvalidStartDateError extends BaseError { + override name = "InvalidStartDateError"; + constructor(startDate: number | undefined, { docsPath }: BaseErrorOptions) { + super( + `Invalid start date. Start date (${startDate}) cannot be in the past.`, + { docsPath } + ); + } +} + +export type InvalidEndDateErrorType = InvalidEndDateError & { + name: "InvalidDateError"; +}; +export class InvalidEndDateError extends BaseError { + override name = "InvalidEndDateError"; + constructor( + { + endDate, + startDate + }: { endDate: number | undefined; startDate: number | undefined }, + { docsPath }: BaseErrorOptions + ) { + super( + `Invalid end date. End date (${endDate}) must be after the start date (${startDate}).`, + { docsPath } + ); + } +} + +export type EndDateTooFarErrorType = EndDateTooFarError & { + name: "EndDateTooFarError"; +}; +export class EndDateTooFarError extends BaseError { + override name = "EndDateTooFarError"; + constructor( + { + endDate, + maxEndedAt + }: { endDate: number | undefined; maxEndedAt: number | undefined }, + { docsPath }: BaseErrorOptions + ) { + super( + `End date too far in the future. End date (${endDate}) exceeds the maximum allowed (${maxEndedAt}).`, + { docsPath } + ); + } +} + +export type InvalidStartAmountErrorType = InvalidStartAmountError & { + name: "InvalidStartAmountError"; +}; +export class InvalidStartAmountError extends BaseError { + override name = "InvalidStartAmountError"; + constructor({ docsPath }: BaseErrorOptions) { + super("Invalid start amount. The start amount must be greater than zero.", { + docsPath + }); + } +} + +export type InvalidEndAmountErrorType = InvalidEndAmountError & { + name: "InvalidEndAmountErrorType"; +}; +export class InvalidEndAmountError extends BaseError { + override name = "InvalidEndAmountError"; + constructor({ docsPath }: BaseErrorOptions) { + super( + "Invalid end amount. The end amount must be greater than the start amount.", + { docsPath } + ); + } +} diff --git a/packages/core/src/errors/base.ts b/packages/core/src/errors/base.ts new file mode 100644 index 000000000..62745b443 --- /dev/null +++ b/packages/core/src/errors/base.ts @@ -0,0 +1,95 @@ +import { Compute, OneOf } from "../types/utils.js"; +import { getVersion } from "../utils/utils.js"; + +export type ErrorType = Error & { name: name }; + +export type BaseErrorOptions = Compute< + OneOf<{ details?: string | undefined } | { cause: BaseError | Error }> & { + docsPath?: string | undefined; + docsSlug?: string | undefined; + metaMessages?: string[] | undefined; + } +>; + +export type BaseErrorType = BaseError & { name: "ArkProjectCoreError" }; +export class BaseError extends Error { + details: string; + docsPath?: string | undefined; + metaMessages?: string[] | undefined; + shortMessage: string; + + override name = "ArkProjectCoreError"; + get docsBaseUrl() { + return "https://docs.arkproject.dev/"; + } + get version() { + return getVersion(); + } + + constructor(shortMessage: string, options: BaseErrorOptions = {}) { + super(); + + const details = + options.cause instanceof BaseError + ? options.cause.details + : options.cause?.message + ? options.cause?.message + : options.details!; + const docsPath = + options.cause instanceof BaseError + ? options.cause.docsPath || options.docsPath + : options.docsPath; + + this.message = [ + shortMessage || "An error occured.", + "", + ...(options.metaMessages ? [...options.metaMessages, ""] : []), + ...(docsPath + ? [ + `Docs: ${this.docsBaseUrl}${docsPath}${options.docsSlug ? `#${options.docsSlug}` : ""}` + ] + : []), + ...(details ? [`Details: ${details}`] : []), + `Version: ${this.version}` + ].join("\n"); + + if (options.cause) this.cause = options.cause; + this.details = details; + this.docsPath = docsPath; + this.metaMessages = options.metaMessages; + this.shortMessage = shortMessage; + } + + walk(fn?: (err: unknown) => boolean) { + return this.#walk(this, fn); + } + + #walk(err: unknown, fn?: (err: unknown) => boolean): unknown { + if (fn?.(err)) return err; + if ((err as Error).cause) return this.#walk((err as Error).cause, fn); + return err; + } +} + +/** + * CONTRACT_ADDRESS_MUST_BE_NON_EMPTY_STRING -> config + * UNSUPPORTED_NETWORK -> Config + * NFT_CONTRACT_ADDRESS_IS_NOT_DEFINED -> Scripts/Config + * NO_ABI -> Config, Actions/Read + * STDERR -> Scripts + * EXECUTOR_CONTRACT_ADDRESS_IS_REQUIRED_FOR_DEVELOPER_NETWORK -> Config + * ACCOUNT_DEPLOY_FAILED_FOR_ADDRESS -> Account + * INVALID_FEES_RATIO -> Actions/Fees + * INVALID_START_DATE -> Actions/Orders + * INVALID_END_DATE -> Actions/Orders + * END_DATE_TOO_FAR -> Actions/Orders + * INVALID_START_AMOUNT -> Actions/Orders + * INVALID_END_AMOUNT -> Actions/Orders + * NO_VALID_VARIANT_FOUND_IN_CAIRO_CUSTOM_ENUM -> Utils + * UNSUPPORTED_STARKNET_NETWORK -> Providers + * NO_ACCOUNT_FOUND -> Account + * CONFIG_NOT_FOUND -> Config/Hooks + * CONFIG_NOT_LOADED -> Config/Hooks + * USECONFIG_WITHIN_ARKPROVIDER -> Config/Hooks + * ACCOUNT_NOT_CONNECTED -> Account + */ diff --git a/packages/core/src/errors/config.ts b/packages/core/src/errors/config.ts new file mode 100644 index 000000000..41213884f --- /dev/null +++ b/packages/core/src/errors/config.ts @@ -0,0 +1,105 @@ +import { BaseError, BaseErrorOptions } from "./base.js"; + +export type InvalidContractAddressErrorType = InvalidContractAddressError & { + name: "InvalidContractAddressError"; +}; +export class InvalidContractAddressError extends BaseError { + override name = "InvalidContractAdressError"; + constructor(name: string, { docsPath, docsSlug }: BaseErrorOptions) { + super(`${name} contract address must be a valid non-empty string`, { + docsPath, + docsSlug + }); + } +} + +export type UnsupportedNetworkErrorType = UnsupportedNetworkError & { + name: "UnsupportedNetworkError"; +}; +export class UnsupportedNetworkError extends BaseError { + override name = "UnsupportedNetworkError"; + constructor(network: string, { docsPath, docsSlug }: BaseErrorOptions) { + super(`Unsupported network: ${network}`, { docsPath, docsSlug }); + } +} + +export type ContractsCheckErrorType = ContractsCheckError & { + name: "ContractsCheckError"; +}; +export class ContractsCheckError extends BaseError { + override name = "ContractsCheckError"; + constructor(stderr: string, { docsPath }: BaseErrorOptions) { + super(stderr, { docsPath }); + } +} + +export type MissingExecutorContractErrorType = MissingExecutorContractError & { + name: "MissingExecutorContractError"; +}; +export class MissingExecutorContractError extends BaseError { + override name = "MissingExecutorContractError"; + constructor({ docsPath, docsSlug }: BaseErrorOptions) { + super("Executor contract address is required for dev network", { + docsPath, + docsSlug + }); + } +} + +export type InvalidVariantCairoCustomEnumErrorType = + InvalidContractAddressError & { + name: "InvalidVariantCairoCustomEnumError"; + }; +export class InvalidVariantCairoCustomEnumError extends BaseError { + override name = "InvalidVariantCairoCustomEnumError"; + constructor({ docsPath }: BaseErrorOptions) { + super("No valid variant found in CairoCustomEnum", { docsPath }); + } +} + +export class UnsupportedStarknetNetworkError extends BaseError { + override name = "UnsupportedStarknetNetworkError"; + constructor( + starknetNetwork: string, + { docsPath, docsSlug }: BaseErrorOptions + ) { + super(`Unsupported starknetNetwork: ${starknetNetwork}`, { + docsPath, + docsSlug + }); + } +} + +export type ConfigNotLoadedType = ConfigNotLoaded & { + name: "ConfigNotLoaded"; +}; +export class ConfigNotFoundError extends BaseError { + override name = "ConfigNotFoundError"; + constructor({ docsPath, docsSlug }: BaseErrorOptions) { + super("Config not found", { docsPath, docsSlug }); + } +} + +export type ConfigNotFoundErrorType = ConfigNotFoundError & { + name: "ConfigNotFoundError"; +}; +export class ConfigNotLoaded extends BaseError { + override name = "ConfigNotLoaded"; + constructor({ docsPath, docsSlug }: BaseErrorOptions) { + super("Config not loaded", { docsPath, docsSlug }); + } +} + +export type UseConfigWithinArkProviderErrorType = + UseConfigWithinArkProviderError & { + name: "UseConfigWithinArkProviderError"; + }; +export class UseConfigWithinArkProviderError extends BaseError { + override name = "UseConfigWithinArkProviderError"; + constructor({ docsPath, docsSlug }: BaseErrorOptions) { + super("useConfig must be used within a ArkProvider", { + docsPath, + docsSlug + }); + } +} diff --git a/packages/core/src/types/utils.ts b/packages/core/src/types/utils.ts new file mode 100644 index 000000000..eba2952bd --- /dev/null +++ b/packages/core/src/types/utils.ts @@ -0,0 +1,10 @@ +export type Compute = { [key in keyof type]: type[key] } & unknown; + +export type OneOf< + union extends object, + /// + keys extends KeyofUnion = KeyofUnion +> = union extends infer Item + ? Compute]?: undefined }> + : never; +type KeyofUnion = type extends type ? keyof type : never; diff --git a/packages/core/src/utils/utils.ts b/packages/core/src/utils/utils.ts new file mode 100644 index 000000000..9c4f70c4b --- /dev/null +++ b/packages/core/src/utils/utils.ts @@ -0,0 +1,3 @@ +import { version } from "../version.js"; + +export const getVersion = () => `@ark-project/core@${version}`; diff --git a/packages/core/tests/setBrokerFees.test.ts b/packages/core/tests/setBrokerFees.test.ts index a136b9118..2b8f9f167 100644 --- a/packages/core/tests/setBrokerFees.test.ts +++ b/packages/core/tests/setBrokerFees.test.ts @@ -3,6 +3,7 @@ import { describe, expect, it } from "vitest"; import { config, getAccounts, mintERC721 } from "@ark-project/test"; +import { NoABIError } from "../src/errors/actions.js"; import { getFeesAmount, setBrokerFees } from "../src/index.js"; describe("setBrokerFees", () => { @@ -18,7 +19,7 @@ describe("setBrokerFees", () => { ); if (abi === undefined) { - throw new Error("no abi."); + throw new NoABIError({ docsPath: "" }); } await setBrokerFees(config, { diff --git a/packages/core/tests/utils/index.ts b/packages/core/tests/utils/index.ts index db41699a4..19dd3f2c8 100644 --- a/packages/core/tests/utils/index.ts +++ b/packages/core/tests/utils/index.ts @@ -1,6 +1,7 @@ import { CairoCustomEnum } from "starknet"; import contracts from "../../../../contracts.dev.json"; +import { InvalidVariantCairoCustomEnumError } from "../../src/errors/config.js"; type VariantKey = "Listing" | "Auction" | "Offer" | "CollectionOffer"; @@ -25,5 +26,5 @@ export function getTypeFromCairoCustomEnum(cairoCustomEnum: CairoCustomEnum) { } } - throw new Error("No valid variant found in CairoCustomEnum"); + throw new InvalidVariantCairoCustomEnumError({ docsPath: "" }); }