From b5a8612f1eaaf1c3f1ff6fc69525d9a7520c2be3 Mon Sep 17 00:00:00 2001 From: Jonas Daniels Date: Thu, 15 Feb 2024 17:34:32 -0800 Subject: [PATCH] remove reliance on `bs58` package --- packages/thirdweb/package.json | 1 - .../thirdweb/src/utils/base58/alphabet.ts | 2 + .../thirdweb/src/utils/base58/encode.test.ts | 119 ++++++++++++++++++ packages/thirdweb/src/utils/base58/encode.ts | 71 +++++++++++ .../src/utils/bytecode/extractIPFS.ts | 5 +- 5 files changed, 195 insertions(+), 3 deletions(-) create mode 100644 packages/thirdweb/src/utils/base58/alphabet.ts create mode 100644 packages/thirdweb/src/utils/base58/encode.test.ts create mode 100644 packages/thirdweb/src/utils/base58/encode.ts diff --git a/packages/thirdweb/package.json b/packages/thirdweb/package.json index d6495dcbf7b..bb955288b3e 100644 --- a/packages/thirdweb/package.json +++ b/packages/thirdweb/package.json @@ -143,7 +143,6 @@ "@tanstack/react-query": "5.20.2", "@walletconnect/ethereum-provider": "2.11.1", "abitype": "1.0.0", - "bs58": "5.0.0", "fuse.js": "7.0.0", "mipd": "0.0.5", "qrcode": "1.5.3", diff --git a/packages/thirdweb/src/utils/base58/alphabet.ts b/packages/thirdweb/src/utils/base58/alphabet.ts new file mode 100644 index 00000000000..2da9a1e883b --- /dev/null +++ b/packages/thirdweb/src/utils/base58/alphabet.ts @@ -0,0 +1,2 @@ +export const ALPHABET = + "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" as const; diff --git a/packages/thirdweb/src/utils/base58/encode.test.ts b/packages/thirdweb/src/utils/base58/encode.test.ts new file mode 100644 index 00000000000..61c2d52614a --- /dev/null +++ b/packages/thirdweb/src/utils/base58/encode.test.ts @@ -0,0 +1,119 @@ +import { describe, expect, test } from "vitest"; +import { base58Encode } from "./encode.js"; +import { hexToBytes } from "viem"; + +const TEST_CASES = [ + ["", ""], + ["61", "2g"], + ["626262", "a3gV"], + ["636363", "aPEr"], + ["73696d706c792061206c6f6e6720737472696e67", "2cFupjhnEsSn59qHXstmK2ffpLv2"], + [ + "00eb15231dfceb60925886b67d065299925915aeb172c06647", + "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L", + ], + ["516b6fcd0f", "ABnLTmg"], + ["bf4f89001e670274dd", "3SEo3LWLoPntC"], + ["572e4794", "3EFU7m"], + ["ecac89cad93923c02321", "EJDM8drfXA6uyA"], + ["10c8511e", "Rt5zm"], + ["00000000000000000000", "1111111111"], + [ + "801184cd2cdd640ca42cfc3a091c51d549b2f016d454b2774019c2b2d2e08529fd206ec97e", + "5Hx15HFGyep2CfPxsJKe2fXJsCVn5DEiyoeGGF6JZjGbTRnqfiD", + ], + [ + "003c176e659bea0f29a3e9bf7880c112b1b31b4dc826268187", + "16UjcYNBG9GTK4uq2f7yYEbuifqCzoLMGS", + ], + ["ffffffffffffffffffff", "FPBt6CHo3fovdL"], + ["ffffffffffffffffffffffffff", "NKioeUVktgzXLJ1B3t"], + ["ffffffffffffffffffffffffffffffff", "YcVfxkQb6JRzqk5kF2tNLv"], + ["ef41b9ce7e830af7", "h26E62FyLQN"], + ["606cbc791036d2e9", "H8Sa62HVULG"], + ["bdcb0ea69c2c8ec8", "YkESUPpnfoD"], + ["1a2358ba67fb71d5", "5NaBN89ajtQ"], + ["e6173f0f4d5fb5d7", "fVAoezT1ZkS"], + ["91c81cbfdd58bbd2", "RPGNSU3bqTX"], + ["329e0bf0e388dbfe", "9U41ZkwwysT"], + ["30b10393210fa65b", "99NMW3WHjjY"], + ["ab3bdd18e3623654", "VeBbqBb4rCT"], + ["fe29d1751ec4af8a", "jWhmYLN9dUm"], + ["c1273ab5488769807d", "3Tbh4kL3WKW6g"], + ["6c7907904de934f852", "2P5jNYhfpTJxy"], + ["05f0be055db47a0dc9", "5PN768Kr5oEp"], + ["3511e6206829b35b12", "gBREojGaJ6DF"], + ["d1c7c2ddc4a459d503", "3fsekq5Esq2KC"], + ["1f88efd17ab073e9a1", "QHJbmW9ZY7jn"], + ["0f45dadf4e64c5d5c2", "CGyVUMmCKLRf"], + ["de1e5c5f718bb7fafa", "3pyy8U7w3KUa5"], + ["123190b93e9a49a46c", "ES3DeFrG1zbd"], + ["8bee94a543e7242e5a", "2nJnuWyLpGf6y"], + ["9fd5f2285362f5cfd834", "9yqFhqeewcW3pF"], + ["6987bac63ad23828bb31", "6vskE5Y1LhS3U4"], + ["19d4a0f9d459cc2a08b0", "2TAsHPuaLhh5Aw"], + ["a1e47ffdbea5a807ab26", "A6XzPgSUJDf1W5"], + ["35c231e5b3a86a9b83db", "42B8reRwPAAoAa"], + ["b2351012a48b8347c351", "B1hPyomGx4Vhqa"], + ["71d402694dd9517ea653", "7Pv2SyAQx2Upu8"], + ["55227c0ec7955c2bd6e8", "5nR64BkskyjHMq"], + ["17b3d8ee7907c1be34df", "2LEg7TxosoxTGS"], + ["7e7bba7b68bb8e95827f", "879o2ATGnmYyAW"], + ["db9c13f5ba7654b01407fb", "wTYfxjDVbiks874"], + ["6186449d20f5fd1e6c4393", "RBeiWhzZNL6VtMG"], + ["5248751cebf4ad1c1a83c3", "MQSVNnc8ehFCqtW"], + ["32090ef18cd479fc376a74", "DQdu351ExDaeYeX"], + ["7cfa5d6ed1e467d986c426", "XzW67T5qfEnFcaZ"], + ["9d8707723c7ede51103b6d", "g4eTCg6QJnB1UU4"], + ["6f4d1e392d6a9b4ed8b223", "Ubo7kZY5aDpAJp2"], + ["38057d98797cd39f80a0c9", "EtjQ2feamJvuqse"], + ["de7e59903177e20880e915", "xB2N7yRBnDYEoT2"], + ["b2ea24a28bc4a60b5c4b8d", "mNFMpJ2P3TGYqhv"], + ["cf84938958589b6ffba6114d", "4v8ZbsGh2ePz5sipt"], + ["dee13be7b8d8a08c94a3c02a", "5CwmE9jQqwtHkTF45"], + ["14cb9c6b3f8cd2e02710f569", "Pm85JHVAAdeUdxtp"], + ["ca3f2d558266bdcc44c79cb5", "4pMwomBAQHuUnoLUC"], + ["c031215be44cbad745f38982", "4dMeTrcxiVw9RWvj3"], + ["1435ab1dbc403111946270a5", "P7wX3sCWNrbqhBEC"], + ["d8c6e4d775e7a66a0d0f9f41", "56GLoRDGWGuGJJwPN"], + ["dcee35e74f0fd74176fce2f4", "5Ap1zyuYiJJFwWcMR"], + ["bfcc0ca4b4855d1cf8993fc0", "4cvafQW4PEhARKv9D"], + ["e02a3ac25ece7b54584b670a", "5EMM28xkpxZ1kkVUM"], + ["fe4d938fc3719f064cabb4bfff", "NBXKkbHwrAsiWTLAk6"], + ["9289cb4f6b15c57e6086b87ea5", "DCvDpjEXEbHjZqskKv"], + ["fc266f35626b3612bfe978537b", "N186PVoBWrNre35BGE"], + ["33ff08c06d92502bf258c07166", "5LC4SoW6jmTtbkbePw"], + ["6a81cac1f3666bc59dc67b1c3c", "9sXgUySUzwiqDU5WHy"], + ["9dfb8e7e744c544c0f323ea729", "EACsmGmkgcwsrPFzLg"], + ["1e7a1e284f70838b38442b682b", "3YEVk9bE7rw5qExMkv"], + ["2a862ad57901a8235f5dc74eaf", "4YS259nuTLfeXa5Wuc"], + ["74c82096baef21f9d3089e5462", "AjAcKEhUfrqm8smvM7"], + ["7a3edbc23d7b600263920261cc", "BBZXyRgey5S5DDZkcK"], + ["20435664c357d25a9c8df751cf4f", "CrwNL6Fbv4pbRx1zd9g"], + ["51a7aa87cf5cb1c12d045ec3422d", "X27NHGgKXmGzzQvDtpC"], + ["344d2e116aa26f1062a2cb6ebbef", "LEDLDvL1Hg4qt1efVXt"], + ["6941add7be4c0b5c7163e4928f8e", "fhMyN6gwoxE3uYraVzV"], + ["10938fcbb7c4ab991649734a14bf", "76TPrSDxzGQfSzMu974"], + ["eafe04d944ba504e9af9117b07de", "2VPgov563ryfe4L2Bj6M"], + ["58d0aeed4d35da20b6f052127edf", "ZenZhXF9YwP8nQvNtNz"], + ["d734984e2f5aecf25f7a3e353f8a", "2N7n3jFsTdyN49Faoq6h"], + ["57d873fdb405b7daf4bafa62068a", "ZJ7NwoP4wHvwyZg3Wjs"], + ["bda4ec7b40d0d65ca95dec4c4d3b", "2CijxjsNyvqTwPCfDcpA"], + ["826c4abdceb1b91f0d4ad665f86d2e", "4edfvuDQu9KzVxLuXHfMo"], + ["e7ecb35d07e65b960cb10574a4f51a", "7VLRYdB4cToipp2J2p3v9"], + ["4f2d72ead87b31d6869fba39eac6dc", "3DUjqJRcfdWhpsrLrGcQs"], + ["8b4f5788d60030950d5dfbf94c585d", "4u44JSRH5jP5X39YhPsmE"], + ["ee4c0a0025d1a74ace9fe349355cc5", "7fgACjABRQUGUEpN6VBBA"], + ["58ac05b9a0b4b66083ff1d489b8d84", "3UtJPyTwGXapcxHx8Rom5"], + ["1aa35c05e1132e8e049aafaef035d8", "kE2eSU7gM2619pT82iGP"], + ["771b0c28608484562a292e5d5d2b30", "4LGYeWhyfrjUByibUqdVR"], + ["78ff9a0e56f9e88dc1cd654b40d019", "4PLggs66qAdbmZgkaPihe"], + ["6d691bdd736346aa5a0a95b373b2ab", "44Y6qTgSvRMkdqpQ5ufkN"], +]; + +describe("base58Encode", () => { + test.each(TEST_CASES)("encodes %s to %s", (input, expected) => { + const encoded = base58Encode(hexToBytes(`0x${input}`)); + expect(encoded).toBe(expected); + }); +}); diff --git a/packages/thirdweb/src/utils/base58/encode.ts b/packages/thirdweb/src/utils/base58/encode.ts new file mode 100644 index 00000000000..5d5d8d6e0f1 --- /dev/null +++ b/packages/thirdweb/src/utils/base58/encode.ts @@ -0,0 +1,71 @@ +import { ALPHABET } from "./alphabet.js"; + +const BASE = ALPHABET.length; +const LEADER = /* @__PURE__ */ (() => ALPHABET.charAt(0))(); +const iFACTOR = /* @__PURE__ */ (() => Math.log(256) / Math.log(BASE))(); // log(256) / log(BASE), rounded up + +/** + * Encodes a Uint8Array into a base58 string. + * @param source - The Uint8Array to encode. + * @returns The base58 encoded string. + * @throws {TypeError} If the source is not a Uint8Array. + * @throws {Error} If there is a non-zero carry during the encoding process. + * @example + * ```ts + * import { base58Encode } from "thirdweb/utils; + * const source = new Uint8Array([0, 1, 2, 3, 4, 5]); + * const encoded = base58Encode(source); + * console.log(encoded); + * ``` + */ +export function base58Encode(source: Uint8Array): string { + if (!(source instanceof Uint8Array)) { + throw new TypeError("Expected Uint8Array"); + } + if (source.length === 0) { + return ""; + } + // Skip & count leading zeroes. + let zeroes = 0; + let length = 0; + let pbegin = 0; + const pend = source.length; + while (pbegin !== pend && source[pbegin] === 0) { + pbegin++; + zeroes++; + } + // Allocate enough space in big-endian base58 representation. + const size = ((pend - pbegin) * iFACTOR + 1) >>> 0; + const b58 = new Uint8Array(size); + // Process the bytes. + while (pbegin !== pend) { + let carry = source[pbegin] || 0; + // Apply "b58 = b58 * 256 + ch". + let i = 0; + for ( + let it1 = size - 1; + (carry !== 0 || i < length) && it1 !== -1; + it1--, i++ + ) { + carry += (256 * (b58[it1] || 0)) >>> 0; + b58[it1] = carry % BASE >>> 0; + carry = (carry / BASE) >>> 0; + } + if (carry !== 0) { + throw new Error("Non-zero carry"); + } + length = i; + pbegin++; + } + // Skip leading zeroes in base58 result. + let it2 = size - length; + while (it2 !== size && b58[it2] === 0) { + it2++; + } + // Translate the result into a string. + let str = LEADER.repeat(zeroes); + for (; it2 < size; ++it2) { + str += ALPHABET.charAt(b58[it2] || 0); + } + return str; +} diff --git a/packages/thirdweb/src/utils/bytecode/extractIPFS.ts b/packages/thirdweb/src/utils/bytecode/extractIPFS.ts index a1c8a1022d2..2aaebefba66 100644 --- a/packages/thirdweb/src/utils/bytecode/extractIPFS.ts +++ b/packages/thirdweb/src/utils/bytecode/extractIPFS.ts @@ -1,6 +1,7 @@ import { hexToBytes } from "@noble/hashes/utils"; -import bs58 from "bs58"; + import { decode } from "./cbor-decode.js"; +import { base58Encode } from "../base58/encode.js"; /** * Extracts the IPFS URI from the given bytecode. @@ -33,7 +34,7 @@ export function extractIPFSUri(bytecode: string): string | undefined { const cborData = decode(bytecodeBuffer); if ("ipfs" in cborData) { - return `ipfs://${bs58.encode(cborData["ipfs"])}`; + return `ipfs://${base58Encode(cborData["ipfs"])}`; } return undefined;