Skip to content

Commit

Permalink
refactor: implement custom error class handle for minter
Browse files Browse the repository at this point in the history
Refs: #25
  • Loading branch information
bucurdavid committed Sep 11, 2023
1 parent 4a61fa4 commit 5606d14
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 69 deletions.
18 changes: 16 additions & 2 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ export class ErrInvalidArgument extends Error {
}

export class ErrBadType extends Error {
public constructor(name: string, type: any, value?: any) {
super(`Bad type of "${name}": ${value}. Expected type: ${type}`);
public constructor(name: string, type: any, value?: any, context?: string) {
super(
`Bad type of "${name}": ${value}. Expected type: ${type}. Context: ${context}`
);
}
}

Expand Down Expand Up @@ -48,3 +50,15 @@ export class ErrContractQuery extends Error {
super(`Failed to query contract: Method: ${method} : ${message}`);
}
}

export class ErrParamValidation extends Error {
public constructor(message: string) {
super(`Params have validation issues : ${message}`);
}
}

export class ErrFailedOperation extends Error {
public constructor(method: string, message?: string) {
super(`Failed to perform operation: ${method} : ${message}`);
}
}
115 changes: 52 additions & 63 deletions src/minter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,18 @@ import { MinterRequirements } from './interfaces';
import { NFTStorage } from 'nft.storage';
import { File } from '@web-std/file';
import {
checkStatus,
checkTraitsUrl,
checkUrlIsUp,
validateSpecificParamsMint
} from './utils';
// import {
// ErrArgumentNotSet,
// ErrContractQuery,
// ErrFailedOperation
// } from './errors';
import {
ErrBadType,
ErrContractQuery,
ErrFailedOperation,
ErrNetworkConfig,
ErrParamValidation
} from './errors';

export class DataNftMinter {
readonly contract: SmartContract;
Expand All @@ -51,6 +54,11 @@ export class DataNftMinter {
* @param timeout Timeout for the network provider (DEFAULT = 10000ms)
*/
constructor(env: string, timeout: number = 10000) {
if (!(env in EnvironmentsEnum)) {
throw new ErrNetworkConfig(
`Invalid environment: ${env}, Expected: 'devnet' | 'mainnet' | 'testnet'`
);
}
this.env = env;
const networkConfig = networkConfiguration[env as EnvironmentsEnum];
this.imageServiceUrl = imageService[env as EnvironmentsEnum];
Expand Down Expand Up @@ -114,8 +122,10 @@ export class DataNftMinter {
};
return requirements;
} else {
throw new Error('Could not retrieve minter contract requirements');
// throw new ErrContractQuery('Could not retrieve requirements');
throw new ErrContractQuery(
'viewMinterRequirements',
returnCode.toString()
);
}
}

Expand All @@ -135,10 +145,10 @@ export class DataNftMinter {
const returnValue = firstValue?.valueOf();
return new BooleanValue(returnValue).valueOf();
} else {
throw new Error('Error while retrieving the contract pause state');
// throw new ErrContractQuery(
// 'Error while retrieving the contract pause state'
// );
throw new ErrContractQuery(
'viewContractPauseState',
returnCode.toString()
);
}
}

Expand Down Expand Up @@ -247,27 +257,15 @@ export class DataNftMinter {
});

if (!allPassed) {
throw new Error(`Params have validation issues = ${validationMessages}`);
// throw new ErrFailedOperation(
// this.mint.name,
// new Error(`params have validation issues = ${validationMessages}`)
// );
throw new ErrParamValidation(validationMessages);
}
// E: run any format specific validation...

// deep validate all mandatory URLs
try {
await checkUrlIsUp(dataStreamUrl, [200, 403]);
await checkUrlIsUp(dataPreviewUrl, [200]);
await checkUrlIsUp(dataMarshalUrl + '/health-check', [200]);
} catch (error) {
throw error;
// if (error instanceof Error) {
// throw new ErrFailedOperation(this.mint.name, error);
// } else {
// throw new ErrFailedOperation(this.mint.name);
// }
}

await checkUrlIsUp(dataStreamUrl, [200, 403]);
await checkUrlIsUp(dataPreviewUrl, [200]);
await checkUrlIsUp(dataMarshalUrl + '/health-check', [200]);

let imageOnIpfsUrl: string;
let metadataOnIpfsUrl: string;
Expand All @@ -277,13 +275,12 @@ export class DataNftMinter {

if (!imageUrl) {
if (!nftStorageToken) {
throw new Error(
throw new ErrBadType(
'nftStorageToken',
'string',
nftStorageToken,
'NFT Storage token is required when not using custom image and traits'
);
// throw new ErrArgumentNotSet(
// 'nftStorageToken',
// 'NFT Storage token is required when not using custom image and traits'
// );
}
const { image, traits } = await this.createFileFromUrl(
`${this.imageServiceUrl}/v1/generateNFTArt?hash=${dataNftHash}`,
Expand All @@ -302,11 +299,12 @@ export class DataNftMinter {
metadataOnIpfsUrl = metadataIpfsUrl;
} else {
if (!traitsUrl) {
throw new Error('Traits URL is required when using custom image');
// throw new ErrArgumentNotSet(
// 'traitsUrl',
// 'Traits URL is required when using custom image'
// );
throw new ErrBadType(
'traitsUrl',
'string',
traitsUrl,
'Traits URL is required when using custom image'
);
}

await checkTraitsUrl(traitsUrl);
Expand Down Expand Up @@ -374,29 +372,21 @@ export class DataNftMinter {
body: JSON.stringify({ dataNFTStreamUrl })
};

try {
const res = await fetch(`${dataMarshalUrl}/generate`, requestOptions);
const data = await res.json();
const res = await fetch(`${dataMarshalUrl}/generate`, requestOptions);
const data = await res.json();

if (data && data.encryptedMessage && data.messageHash) {
return {
dataNftHash: data.messageHash,
dataNftStreamUrlEncrypted: data.encryptedMessage
};
} else {
throw new Error('Issue with data marshal generate payload');
// throw new ErrFailedOperation(this.dataNFTDataStreamAdvertise.name);
}
} catch (error) {
throw error;
// if (error instanceof Error) {
// throw new ErrFailedOperation(
// this.dataNFTDataStreamAdvertise.name,
// error
// );
// } else {
// throw new ErrFailedOperation(this.dataNFTDataStreamAdvertise.name);
// }
checkStatus(res);

if (data && data.encryptedMessage && data.messageHash) {
return {
dataNftHash: data.messageHash,
dataNftStreamUrlEncrypted: data.encryptedMessage
};
} else {
throw new ErrFailedOperation(
'dataNFTDataStreamAdvertise',
'Invalid response from Data Marshal'
);
}
}

Expand All @@ -412,9 +402,8 @@ export class DataNftMinter {
});
const dir = [image, traits];
res = await nftstorage.storeDirectory(dir);
} catch (error) {
throw error;
// throw new ErrFailedOperation(this.storeToIpfs.name);
} catch (error: any) {
throw new ErrFailedOperation('storeToIpfs', error.message);
}
return {
imageOnIpfsUrl: `https://ipfs.io/ipfs/${res}/image.png`,
Expand Down
6 changes: 2 additions & 4 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -528,14 +528,12 @@ export async function checkUrlIsUp(url: string, expectedHttpCodes: number[]) {
const response = await fetch(url);

if (!expectedHttpCodes.includes(response.status)) {
throw new Error(
`URL needs to return a 200 OK response code (or a 403 Forbidden error code is also allowed for protected Data Streams). url : ${url}, actual HTTP status: ${response.status}`
);
throw new ErrFetch(response.status, response.statusText);
}
}

export function checkStatus(response: Response) {
if (response.status != 200) {
if (response.status >= 200 && response.status <= 299) {
throw new ErrFetch(response.status, response.statusText);
}
}

0 comments on commit 5606d14

Please sign in to comment.