diff --git a/graph/tests/.bin/hypercert-minter-allowlist.wasm b/graph/tests/.bin/hypercert-minter-allowlist.wasm new file mode 100644 index 00000000..d23ece46 Binary files /dev/null and b/graph/tests/.bin/hypercert-minter-allowlist.wasm differ diff --git a/graph/tests/.bin/hypercert-minter-burn.wasm b/graph/tests/.bin/hypercert-minter-burn.wasm new file mode 100644 index 00000000..2306c194 Binary files /dev/null and b/graph/tests/.bin/hypercert-minter-burn.wasm differ diff --git a/graph/tests/.bin/hypercert-minter-claim.wasm b/graph/tests/.bin/hypercert-minter-claim.wasm new file mode 100644 index 00000000..bc52619b Binary files /dev/null and b/graph/tests/.bin/hypercert-minter-claim.wasm differ diff --git a/graph/tests/.bin/hypercert-minter-fraction.wasm b/graph/tests/.bin/hypercert-minter-fraction.wasm new file mode 100644 index 00000000..5a752fd6 Binary files /dev/null and b/graph/tests/.bin/hypercert-minter-fraction.wasm differ diff --git a/sdk/lib/hypercerts-api b/sdk/lib/hypercerts-api index 3fa43414..b706b492 160000 --- a/sdk/lib/hypercerts-api +++ b/sdk/lib/hypercerts-api @@ -1 +1 @@ -Subproject commit 3fa434148d425d8f7a993c5173672d1c55b48f5c +Subproject commit b706b49242d2e98d3cec9e3bb703c471af3d115e diff --git a/sdk/package.json b/sdk/package.json index a72517aa..6b5cf1b2 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@hypercerts-org/sdk", - "version": "2.0.0-alpha.28", + "version": "2.0.0-alpha.29", "description": "SDK for hypercerts protocol", "repository": "git@github.com:hypercerts-org/hypercerts.git", "author": "Hypercerts team", diff --git a/sdk/src/__generated__/api.ts b/sdk/src/__generated__/api.ts index b49c4b05..3c7adc88 100644 --- a/sdk/src/__generated__/api.ts +++ b/sdk/src/__generated__/api.ts @@ -237,7 +237,7 @@ export interface HypercertMetadata { description: string; /** An url pointing to the external website of the project */ external_url?: string; - hypercert?: HypercertClaimdata; + hypercert?: HypercertClaimdata361; /** A URI pointing to a resource with mime type image/* representing the asset to which this token represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive. */ image: string; /** Identifies the asset to which this token represents */ @@ -252,7 +252,7 @@ export interface HypercertMetadata { /** * Work time period. The value is UNIX time in seconds from epoch. */ -export type HypercertClaimdataWorkTimeframe = { +export type HypercertClaimdata361WorkTimeframe = { display_value?: string; name?: string; value?: number[]; @@ -262,7 +262,7 @@ export type HypercertClaimdataWorkTimeframe = { /** * Scopes of work */ -export type HypercertClaimdataWorkScope = { +export type HypercertClaimdata361WorkScope = { display_value?: string; excludes?: string[]; name?: string; @@ -273,7 +273,7 @@ export type HypercertClaimdataWorkScope = { /** * Rights */ -export type HypercertClaimdataRights = { +export type HypercertClaimdata361Rights = { display_value?: string; excludes?: string[]; name?: string; @@ -284,7 +284,7 @@ export type HypercertClaimdataRights = { /** * Impact time period. The value is UNIX time in seconds from epoch. */ -export type HypercertClaimdataImpactTimeframe = { +export type HypercertClaimdata361ImpactTimeframe = { display_value?: string; name?: string; value?: number[]; @@ -294,7 +294,7 @@ export type HypercertClaimdataImpactTimeframe = { /** * Scopes of impact */ -export type HypercertClaimdataImpactScope = { +export type HypercertClaimdata361ImpactScope = { display_value?: string; excludes?: string[]; name?: string; @@ -305,7 +305,7 @@ export type HypercertClaimdataImpactScope = { /** * Contributors */ -export type HypercertClaimdataContributors = { +export type HypercertClaimdata361Contributors = { display_value?: string; name?: string; value?: string[]; @@ -315,19 +315,19 @@ export type HypercertClaimdataContributors = { /** * Properties of an impact claim */ -export interface HypercertClaimdata { +export interface HypercertClaimdata361 { /** Contributors */ - contributors: HypercertClaimdataContributors; + contributors: HypercertClaimdata361Contributors; /** Scopes of impact */ - impact_scope: HypercertClaimdataImpactScope; + impact_scope: HypercertClaimdata361ImpactScope; /** Impact time period. The value is UNIX time in seconds from epoch. */ - impact_timeframe: HypercertClaimdataImpactTimeframe; + impact_timeframe: HypercertClaimdata361ImpactTimeframe; /** Rights */ - rights?: HypercertClaimdataRights; + rights?: HypercertClaimdata361Rights; /** Scopes of work */ - work_scope: HypercertClaimdataWorkScope; + work_scope: HypercertClaimdata361WorkScope; /** Work time period. The value is UNIX time in seconds from epoch. */ - work_timeframe: HypercertClaimdataWorkTimeframe; + work_timeframe: HypercertClaimdata361WorkTimeframe; [key: string]: unknown; } diff --git a/sdk/src/client.ts b/sdk/src/client.ts index 83efe6c3..5bc958b6 100644 --- a/sdk/src/client.ts +++ b/sdk/src/client.ts @@ -30,6 +30,7 @@ import { ParserReturnType } from "./utils/txParser"; import { isClaimOnChain } from "./utils/chains"; import { StoreAllowList201AnyOfTwoData, StoreMetadata201AnyOf } from "./__generated__/api"; import { HypercertStorage } from "./types/storage"; +import { fetchFromHttpsOrIpfs } from "./utils/fetchers"; /** * The `HypercertClient` is a core class in the hypercerts SDK, providing a high-level interface to interact with the hypercerts system. @@ -128,7 +129,38 @@ export class HypercertClient implements HypercertClientInterface { let root; if (allowList) { - const tree = parseAllowListEntriesToMerkleTree(allowList); + let allowListEntries: AllowlistEntry[] = []; + if (typeof allowList === "string") { + // fetch the csv contents + const csvContents = await fetchFromHttpsOrIpfs(allowList); + + if (!csvContents) { + throw new ClientError("No contents found in the csv", { allowList }); + } + + if (typeof csvContents !== "string") { + throw new ClientError("Invalid contents found in the csv", { allowList }); + } + // parse the csv contents into an array of AllowlistEntry + // get first row as headers + const headers = (csvContents as string).split("\n")[0].split(","); + // map headers onto other rows + const rows = (csvContents as string) + .split("\n") + .slice(1) + .map((row) => { + const values = row.split(","); + return Object.fromEntries(headers.map((header, i) => [header, values[i]])); + }); + allowListEntries = rows.map((entry) => { + const { address, units } = entry; + return { address, units: BigInt(units) }; + }); + } else { + allowListEntries = allowList; + } + + const tree = parseAllowListEntriesToMerkleTree(allowListEntries); // store allowlist on IPFS const allowlistStoreRes = await this.storage.storeAllowlist( diff --git a/sdk/src/types/client.ts b/sdk/src/types/client.ts index 1f3cd02a..cc981104 100644 --- a/sdk/src/types/client.ts +++ b/sdk/src/types/client.ts @@ -100,7 +100,7 @@ export interface MintParams extends TransactionParams { metaData: HypercertMetadata; totalUnits: bigint; transferRestriction: TransferRestrictions; - allowList?: AllowlistEntry[]; + allowList?: AllowlistEntry[] | string; } export interface TransferParams extends TransactionParams { diff --git a/sdk/src/utils/fetchers.ts b/sdk/src/utils/fetchers.ts index 9f57717a..34c643b8 100644 --- a/sdk/src/utils/fetchers.ts +++ b/sdk/src/utils/fetchers.ts @@ -55,3 +55,46 @@ const getWeb3UpGatewayUri = (cidOrIpfsUri: string) => { }; export { getFromIPFS }; + +export const fetchFromHTTPS = async ({ uri }: { uri: string }) => { + // URL validation + const url = new URL(uri); + try { + const res = await axios.get(url.toString()); + + if (!res || !res.data) { + return; + } + + return res.data; + } catch (error) { + console.error(`Failed to get metadata from URI ${uri} `, error); + return; + } +}; + +export const fetchFromHttpsOrIpfs = async (uri?: string): Promise => { + if (!uri || uri === "ipfs://null" || uri === "ipfs://") { + console.error("[fetchFromHttpsOrIpfs] URI is missing"); + return; + } + + let fetchResult; + + // Try from IPFS + if (uri.startsWith("ipfs://")) { + fetchResult = await getFromIPFS(uri); + } + + // Try from HTTPS + if (uri.startsWith("https://")) { + fetchResult = await fetchFromHTTPS({ uri }); + } + + // If nothing found yet, try from IPFS as CID + if (!fetchResult) { + fetchResult = await getFromIPFS(uri); + } + + return fetchResult; +};