Skip to content

Commit e6b5d9c

Browse files
authored
fix: ens avatar resolution (#2756)
1 parent c4d51e0 commit e6b5d9c

File tree

4 files changed

+39
-14
lines changed

4 files changed

+39
-14
lines changed

.changeset/giant-mangos-mix.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
improve `resolveScheme` reliability and handle cases where `getNFT` for ERC1155 was breaking on missing `totalSupply` method

packages/thirdweb/src/extensions/ens/resolve-avatar.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ describe.runIf(process.env.TW_SECRET_KEY)("ENS:resolve-avatar", () => {
2727
);
2828
});
2929

30+
it("resolves vitalik.eth", async () => {
31+
const avatarUri = await resolveAvatar({
32+
client: TEST_CLIENT,
33+
name: "vitalik.eth",
34+
});
35+
expect(avatarUri?.split("/ipfs/")[1]).toMatchInlineSnapshot(
36+
`"QmSP4nq9fnN9dAiCj42ug9Wa79rqmQerZXZch82VqpiH7U/image.gif"`,
37+
);
38+
});
39+
3040
it("resolves name without avatar record to null", async () => {
3141
const avatarUri = await resolveAvatar({
3242
client: TEST_CLIENT,

packages/thirdweb/src/extensions/erc1155/read/getNFT.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ export async function getNFT(
3636
totalSupply({
3737
contract: options.contract,
3838
id: options.tokenId,
39-
}),
39+
// in cases where the supply is not available -> fall back to 0
40+
}).catch(() => 0n),
4041
]);
4142
return parseNFT(
4243
await fetchTokenMetadata({

packages/thirdweb/src/utils/ipfs.ts

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,35 @@ const DEFAULT_GATEWAY = "https://{clientId}.ipfscdn.io/ipfs/{cid}";
2828
* @storage
2929
*/
3030
export function resolveScheme(options: ResolveSchemeOptions) {
31-
let url: string;
3231
if (options.uri.startsWith("ipfs://")) {
3332
const gateway =
3433
options.client.config?.storage?.gatewayUrl ?? DEFAULT_GATEWAY;
3534
const clientId = options.client.clientId;
36-
const cid = options.uri.slice(7);
37-
url =
38-
// purpusefully using SPLIT here and and not replace for CID to avoid cases where users don't know the schema
39-
// also only splitting on `/ipfs` to avoid cases where people pass non `/` terminated gateway urls
40-
`${
41-
gateway.replace("{clientId}", clientId).split("/ipfs")[0]
42-
}/ipfs/${cid}`;
43-
} else if (options.uri.startsWith("http")) {
44-
url = options.uri;
45-
} else {
46-
throw new Error(`Invalid URI scheme, expected "ipfs://" or "http(s)://"`);
35+
const cid = findIPFSCidFromUri(options.uri);
36+
37+
// purpusefully using SPLIT here and and not replace for CID to avoid cases where users don't know the schema
38+
// also only splitting on `/ipfs` to avoid cases where people pass non `/` terminated gateway urls
39+
return `${
40+
gateway.replace("{clientId}", clientId).split("/ipfs")[0]
41+
}/ipfs/${cid}`;
42+
}
43+
if (options.uri.startsWith("http")) {
44+
return options.uri;
4745
}
48-
return url;
46+
throw new Error(`Invalid URI scheme, expected "ipfs://" or "http(s)://"`);
4947
}
5048

49+
function findIPFSCidFromUri(uri: string) {
50+
if (!uri.startsWith("ipfs://")) {
51+
// do not touch URIs that are not ipfs URIs
52+
return uri;
53+
}
54+
55+
// first index of `/Qm` or `/bafy` in the uri (case insensitive)
56+
const firstIndex = uri.search(/\/(Qm|bafy)/i);
57+
// we start one character after the first `/` to avoid including it in the CID
58+
return uri.slice(firstIndex + 1);
59+
}
5160
/**
5261
* Uploads or extracts URIs from the given files.
5362
* @template T - The type of the files (File, Buffer, String).

0 commit comments

Comments
 (0)