Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion apps/playground/src/components/cardano/mesh-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { BlockfrostProvider, MeshWallet } from "@meshsdk/core";

export function getProvider(network = "preprod") {
const provider = new BlockfrostProvider(
`/api/blockfrost/${network}/`,
`https://cardano-${network}.blockfrost.io/api/v0/`,
);
provider.setSubmitTxToBytes(false);
return provider;
Expand Down
3 changes: 2 additions & 1 deletion apps/playground/src/pages/providers/blockfrost.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ const ReactPage: NextPage = () => {

const blockfrostKey = useProviders((state) => state.blockfrostKey);

const provider = new BlockfrostProvider(blockfrostKey ?? "");
// replace with your Blockfrost API key
const provider = new BlockfrostProvider(blockfrostKey ?? "preprod12345");

return (
<>
Expand Down
11 changes: 5 additions & 6 deletions packages/mesh-common/src/data/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ export const stringToHex = (str: string) =>
* @param hex The string to be checked
* @returns True if the string is a hex string, false otherwise
*/
export const isHexString = (hex: string) => /^[0-9A-F]*$/i.test(hex);
export const isHexString = (hex: string) =>
hex.length % 2 === 0 && /^[0-9A-F]*$/i.test(hex);

/**
* Converting hex string to utf8 string
Expand All @@ -43,9 +44,8 @@ export const hexToString = (hex: string) =>
* @param hex The hex or utf8 string to be converted
* @returns The bytes
*/
export const toBytes = (hex: string): Uint8Array => {
if (hex.length % 2 === 0 && /^[0-9A-F]*$/i.test(hex))
return Buffer.from(hex, "hex");
export const toBytes = (hex: string): Buffer => {
if (isHexString(hex)) return Buffer.from(hex, "hex");

return Buffer.from(hex, "utf-8");
};
Expand All @@ -56,8 +56,7 @@ export const toBytes = (hex: string): Uint8Array => {
* @returns The hex string
*/
export const fromUTF8 = (utf8: string) => {
if (utf8.length % 2 === 0 && /^[0-9A-F]*$/i.test(utf8)) return utf8;
return bytesToHex(Buffer.from(utf8, "utf-8"));
return Buffer.from(utf8, "utf-8").toString("hex");
};

/**
Expand Down
60 changes: 60 additions & 0 deletions packages/mesh-common/test/data/parser.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import {
bytesToHex,
fromUTF8,
hexToBytes,
hexToString,
isHexString,
parseAssetUnit,
stringToHex,
toBytes,
toUTF8,
} from "@meshsdk/core";

describe("Data parser utils", () => {
const hexStr = "626f6f6f";
const str = "booo";
const buf = Buffer.from(str);
const asset =
"d65287fa32b1c9880150b548ce32d503000152fe1cc3e3947eb151901370db9a";
const assetUnit = {
policyId: "d65287fa32b1c9880150b548ce32d503000152fe1cc3e3947eb15190",
assetName: "1370db9a",
};

it("converts bytes array to hex string", () => {
expect(bytesToHex(buf)).toStrictEqual(hexStr);
});

it("converts hex string to bytes array", () => {
expect(hexToBytes(hexStr)).toStrictEqual(buf);
});

it("converts utf-8 string to hex string", () => {
expect(stringToHex(str)).toStrictEqual(hexStr);
});

it("verifies hex string correctness", () => {
expect(isHexString(hexStr)).toBeTruthy();
});

it("converts hex string to utf-8 string", () => {
expect(hexToString(hexStr)).toStrictEqual(str);
});

it("converts hex or utf-8 string to bytes", () => {
expect(toBytes(hexStr)).toStrictEqual(buf);
expect(toBytes(str)).toStrictEqual(buf);
});

it("converts utf-8 string to hex string", () => {
expect(fromUTF8(str)).toStrictEqual(hexStr);
});

it("converts hex string to utf-8 string", () => {
expect(toUTF8(hexStr)).toStrictEqual(str);
});

it("parse asset unit into an object with policyId and assetName", () => {
expect(parseAssetUnit(asset)).toStrictEqual(assetUnit);
});
});
38 changes: 29 additions & 9 deletions packages/mesh-provider/src/blockfrost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { OfflineFetcher } from "./offline/offline-fetcher";
import { BlockfrostAsset, BlockfrostUTxO } from "./types";
import { parseHttpError } from "./utils";
import { parseAssetUnit } from "./utils/parse-asset-unit";
import { inferNetworkFromURL, isURL } from "./utils/url";

export type BlockfrostCachingOptions = {
enableCaching?: boolean;
Expand Down Expand Up @@ -78,21 +79,40 @@ export class BlockfrostProvider
* @param version The version of the API. Default is 0.
* @param cachingOptions Optional caching configuration
*/
constructor(projectId: string, version?: number, cachingOptions?: BlockfrostCachingOptions);
constructor(
projectId: string,
version?: number,
cachingOptions?: BlockfrostCachingOptions,
);

constructor(...args: unknown[]) {
let cachingOptions: BlockfrostCachingOptions | undefined;

if (
typeof args[0] === "string" &&
(args[0].startsWith("http") || args[0].startsWith("/"))
) {
this._axiosInstance = axios.create({ baseURL: args[0] });
this._network = "mainnet";

const first = args[0];
if (typeof first !== "string") {
throw new Error("First argument must of type string");
} else if (first.length === 0) {
throw new Error("First argument cannot be an empty string");
}

if (isURL(first)) {
this._axiosInstance = axios.create({ baseURL: first });
const n = inferNetworkFromURL(new URL(first));
if (n === undefined)
throw new Error("Provided URL have an unrecognized network");
this._network = n;
cachingOptions = args[1] as BlockfrostCachingOptions | undefined;
} else {
const projectId = args[0] as string;
const projectId = first as string;
const network = projectId.slice(0, 7);

const supported = ["mainnet", "preprod", "preview"];
if (!supported.includes(network)) {
throw new Error(
`Unsupported type of network: ${network}. Please provide one of the following: ${supported}`,
);
}

this._axiosInstance = axios.create({
baseURL: `https://cardano-${network}.blockfrost.io/api/v${
args[1] ?? 0
Expand Down
6 changes: 5 additions & 1 deletion packages/mesh-provider/src/utils/parse-http-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ export const parseHttpError = (error: unknown): string => {
headers: error.response.headers,
status: error.response.status,
});
} else if (error.request && !(error.request instanceof XMLHttpRequest)) {
} else if (
typeof XMLHttpRequest !== "undefined" &&
error.request &&
!(error.request instanceof XMLHttpRequest)
) {
return JSON.stringify(error.request);
} else {
return JSON.stringify({ code: error.code, message: error.message });
Expand Down
22 changes: 22 additions & 0 deletions packages/mesh-provider/src/utils/url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { BlockfrostSupportedNetworks } from "../blockfrost";

export function isURL(str: string) {
try {
new URL(str);
return true;
} catch (e) {
return false;
}
}

export function inferNetworkFromURL(
u: URL,
): BlockfrostSupportedNetworks | undefined {
let h = u.hostname.toLowerCase();

if (h.includes("cardano-mainnet")) return "mainnet";
if (h.includes("cardano-preprod")) return "preprod";
if (h.includes("cardano-preview")) return "preview";

return undefined;
}
13 changes: 13 additions & 0 deletions packages/mesh-provider/test/blockfrost/constructor.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { BlockfrostProvider } from "@meshsdk/provider";

describe("Blockfrost constructor", () => {
it("fails to initiate a new instance with a wrong first argument", () => {
expect(() => new BlockfrostProvider({})).toThrow();
expect(() => new BlockfrostProvider("")).toThrow();
expect(() => new BlockfrostProvider("http://google.com")).toThrow();
expect(
() =>
new BlockfrostProvider("`https://cardano-testnet.blockfrost.io/api/v1"),
).toThrow();
});
});
5 changes: 4 additions & 1 deletion packages/mesh-provider/test/blockfrost/evaluator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { BlockfrostProvider } from "@meshsdk/provider";

dotenv.config();
const apiKey = process.env.BLOCKFROST_API_KEY_PREPROD;
const provider = new BlockfrostProvider(apiKey ?? "", 0);
const provider = new BlockfrostProvider(
apiKey ?? "https://cardano-preprod.blockfrost.io/api/v1",
0,
);

const successTx =
"84a70081825820859d3b4fd3a4c012b43ee1bbbc99240aec1827c3b8a74b867d10a7f4759149bc00018382583900e4cfbbc317c718f78d137b6535d8940618cc3d2ac04f1f35acf78e53a1521c2cea3cc79762d575581e47ea60b8eaa03430716cfd6140c796821a0011b0dea1581c67dd133868f14107b25772f3c5abaa1e0549f4b400b5e0e3a1136152a149000643b0546573743101a300581d7067dd133868f14107b25772f3c5abaa1e0549f4b400b5e0e3a113615201821a001ad510a1581c67dd133868f14107b25772f3c5abaa1e0549f4b400b5e0e3a1136152a149000de140546573743101028201d8185882d8799fa4446e616d6545546573743145696d6167655835697066733a2f2f516d527a6963705265757477436b4d36616f74754b6a4572464355443231334470775071364279757a4d4a617561496d656469615479706549696d6167652f6a70674b6465736372697074696f6e5348656c6c6f20776f726c64202d20434950363802ff825839003659ed2a30abb32e97589f2a01c8500ce8fc4897b868ebe42fbf4a8aa1521c2cea3cc79762d575581e47ea60b8eaa03430716cfd6140c7961a00134249021a000c830909a1581c67dd133868f14107b25772f3c5abaa1e0549f4b400b5e0e3a1136152a249000643b054657374310149000de1405465737431010b58207ae25a8a9286347cc1e0444a0de75e07432a6ed243591ef673fd837bb5235a670d82825820859d3b4fd3a4c012b43ee1bbbc99240aec1827c3b8a74b867d10a7f4759149bc00825820859d3b4fd3a4c012b43ee1bbbc99240aec1827c3b8a74b867d10a7f4759149bc050e81581ce4cfbbc317c718f78d137b6535d8940618cc3d2ac04f1f35acf78e53a206815883588101000032323232323232322232533300632323232533300a3370e9000000899b8f375c601c601000e911046d6573680014a0601000260180026018002600800429309b2b19299980319b87480000044c8c94ccc02cc03400852616375c601600260080062c60080044600a6ea80048c00cdd5000ab9a5573aaae7955cfaba157450581840100d8799f446d657368ff821a006acfc01ab2d05e00f5f6";
Expand Down