From f333770e34ad7569dbbe8cbf59d9f459be0de581 Mon Sep 17 00:00:00 2001 From: farhanW3 <132962163+farhanW3@users.noreply.github.com> Date: Sat, 20 Apr 2024 01:37:27 +0530 Subject: [PATCH] Update: Completed Tx-Override (#506) * CICD for beta-nightly image (#481) * Updated Packages + UserOp Confirmation flow updated (#479) * Updated Packages + UserOp Confirmation flow updated * wallets sdk updated * fix: missing querystring + description upd (#486) * Added querystring to fastify route (#487) * fix: reject deprecated chains (#488) * chore: Allow cancelling txs that already errored (#491) * chore: Allow cancelling txs that already errored * clean up response * naming * update cancelledAt * fix: Cancel tx if populating a tx to retry fails (#493) * fix: Cancel tx if populating a tx to retry fails * ensure cancel uses high enough gas * fix build * combine prepare + send flows again * updates to GH flow, to use branch (#484) * updates to GH flow, to use branch * removed prelease incorrect tag * upds * got back tag creation check * upds * comments updated * final upds to handle the flow * Updated to use release::create for CI/CD image build/push flow * Updates to GH workflow to not push to if not release not from main (#495) * feat(experimental): Keypair auth (#494) * reorganize helper file * wip * support keypair auth * fix unit tests * return error messages for keypair auth errors * Don't catch JsonWebToken errors * catch access token * move public keys to db * fix: add crud endpoints * wip * add algorithm * add feature envvar * handle each jwt type separately * rename * remove expiration limit * Fix: Deploy Published Contract Flow (#499) * Updated Deploy Published Contract Flow + ProcessTx * removed commented lines * Updates * chore: add updated template for the railway (#490) * chore: add updated template for the railway Signed-off-by: Waren Gonzaga * chore: remove referral code Signed-off-by: Waren Gonzaga --------- Signed-off-by: Waren Gonzaga * Build fixes (#500) * Fix for Issue 502 (#505) * Added tx overrides for EOA + AA --------- Signed-off-by: Waren Gonzaga Co-authored-by: Phillip Ho Co-authored-by: Waren Gonzaga --- .env.test | 5 + .github/workflows/tagBasedImageBuild.yml | 16 +- README.md | 2 +- package.json | 8 +- src/db/keypair/delete.ts | 12 + src/db/keypair/get.ts | 15 + src/db/keypair/insert.ts | 25 + src/db/keypair/list.ts | 6 + src/db/tokens/getToken.ts | 19 +- src/db/transactions/cleanTxs.ts | 10 +- src/db/transactions/queueTx.ts | 14 +- src/db/transactions/updateTx.ts | 2 + .../20240327202800_add_keypairs/migration.sql | 8 + .../migration.sql | 8 + .../migration.sql | 3 + src/prisma/schema.prisma | 11 + src/server/middleware/auth.ts | 374 ++++--- src/server/routes/auth/keypair/add.ts | 87 ++ src/server/routes/auth/keypair/list.ts | 36 + src/server/routes/auth/keypair/remove.ts | 47 + .../contract/subscriptions/getLatestBlock.ts | 7 +- src/server/routes/contract/write/write.ts | 9 + src/server/routes/deploy/published.ts | 16 +- src/server/routes/index.ts | 10 + src/server/routes/system/health.ts | 11 + src/server/routes/transaction/cancel.ts | 2 +- src/server/schemas/keypairs.ts | 63 ++ src/server/schemas/transaction/index.ts | 38 - src/server/schemas/txOverrides.ts | 12 + src/server/utils/chain.ts | 6 +- src/server/utils/transaction.ts | 166 ++-- src/tests/auth.test.ts | 263 ++++- src/tests/chain.test.ts | 4 +- src/utils/auth.ts | 43 + src/utils/cache/accessToken.ts | 2 +- src/utils/cache/clearCache.ts | 2 + src/utils/cache/keypair.ts | 20 + src/utils/crypto.ts | 16 +- src/utils/env.ts | 17 +- src/worker/tasks/processTx.ts | 56 +- src/worker/tasks/retryTx.ts | 94 +- src/worker/tasks/updateMinedTx.ts | 3 +- src/worker/tasks/updateMinedUserOps.ts | 20 +- yarn.lock | 928 ++++++++++-------- 44 files changed, 1703 insertions(+), 813 deletions(-) create mode 100644 .env.test create mode 100644 src/db/keypair/delete.ts create mode 100644 src/db/keypair/get.ts create mode 100644 src/db/keypair/insert.ts create mode 100644 src/db/keypair/list.ts create mode 100644 src/prisma/migrations/20240327202800_add_keypairs/migration.sql create mode 100644 src/prisma/migrations/20240410015450_add_keypair_algorithm/migration.sql create mode 100644 src/prisma/migrations/20240411235927_add_keypair_label/migration.sql create mode 100644 src/server/routes/auth/keypair/add.ts create mode 100644 src/server/routes/auth/keypair/list.ts create mode 100644 src/server/routes/auth/keypair/remove.ts create mode 100644 src/server/schemas/keypairs.ts create mode 100644 src/utils/auth.ts create mode 100644 src/utils/cache/keypair.ts diff --git a/.env.test b/.env.test new file mode 100644 index 000000000..93a0d25e9 --- /dev/null +++ b/.env.test @@ -0,0 +1,5 @@ +THIRDWEB_API_SECRET_KEY="test" +POSTGRES_CONNECTION_URL="postgresql://postgres:postgres@localhost:5432/postgres?sslmode=disable" +ADMIN_WALLET_ADDRESS="test" +ENCRYPTION_PASSWORD="test" +ENABLE_KEYPAIR_AUTH="true" \ No newline at end of file diff --git a/.github/workflows/tagBasedImageBuild.yml b/.github/workflows/tagBasedImageBuild.yml index b34b8b0f5..196ab8642 100644 --- a/.github/workflows/tagBasedImageBuild.yml +++ b/.github/workflows/tagBasedImageBuild.yml @@ -1,12 +1,15 @@ name: Tag Based Image Build on: - create: # This listens to create events, which includes tag creations + release: + types: [created] # This listens to release creation events jobs: buildImageForNewTag: - if: startsWith(github.ref, 'refs/tags/') # Only run this job when a tag is created runs-on: ubuntu-latest + # Set environment variables + env: + LATEST_TAG: ${{ (github.event.release.target_commitish == 'main') && 'thirdweb/engine:latest' || '' }} steps: - name: Check Disk Space Before Build @@ -17,6 +20,9 @@ jobs: - name: Checkout code uses: actions/checkout@v2 + with: + # Fetches the branch at which the release was made + ref: ${{ github.event.release.target_commitish }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 @@ -35,10 +41,10 @@ jobs: platforms: linux/amd64,linux/arm64 push: true tags: | - thirdweb/engine:${{ github.ref_name }} - thirdweb/engine:latest + thirdweb/engine:${{ github.event.release.tag_name }} + ${{ env.LATEST_TAG }} build-args: | - ENGINE_VERSION=${{ github.ref_name }} + ENGINE_VERSION=${{ github.event.release.tag_name }} - name: Check Disk Space After Build run: df -h diff --git a/README.md b/README.md index 0d63cbe44..d04f90167 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Host Engine on your own instructure for free. [View self-host instructions](http Other deployment options: -- [Deploy on Railway](https://railway.app/template/EASlyJ) +[![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/template/fcEVay) ### Cloud-host diff --git a/package.json b/package.json index 234391a61..df25bb8fc 100644 --- a/package.json +++ b/package.json @@ -39,11 +39,11 @@ "@prisma/client": "5.2.0", "@sinclair/typebox": "^0.31.28", "@t3-oss/env-core": "^0.6.0", - "@thirdweb-dev/auth": "^4.1.47", + "@thirdweb-dev/auth": "^4.1.55", "@thirdweb-dev/chains": "^0.1.77", - "@thirdweb-dev/sdk": "^4.0.49", + "@thirdweb-dev/sdk": "^4.0.59", "@thirdweb-dev/service-utils": "0.4.17", - "@thirdweb-dev/wallets": "2.4.17", + "@thirdweb-dev/wallets": "^2.4.36-nightly-6961e09a4cec4c276b233285e721dc0505792be5-20240408215531", "@types/base-64": "^1.0.2", "base-64": "^1.0.0", "body-parser": "^1.20.2", @@ -59,6 +59,7 @@ "fastify": "^4.15.0", "fastify-plugin": "^4.5.0", "http-status-codes": "^2.2.0", + "jsonwebtoken": "^9.0.2", "knex": "^3.1.0", "mnemonist": "^0.39.8", "node-cron": "^3.0.2", @@ -77,6 +78,7 @@ "@types/crypto-js": "^4.2.2", "@types/express": "^4.17.17", "@types/jest": "^29.5.11", + "@types/jsonwebtoken": "^9.0.6", "@types/node": "^18.15.4", "@types/node-cron": "^3.0.8", "@types/pg": "^8.6.6", diff --git a/src/db/keypair/delete.ts b/src/db/keypair/delete.ts new file mode 100644 index 000000000..08fd6529c --- /dev/null +++ b/src/db/keypair/delete.ts @@ -0,0 +1,12 @@ +import { Keypairs } from "@prisma/client"; +import { prisma } from "../client"; + +export const deleteKeypair = async ({ + hash, +}: { + hash: string; +}): Promise => { + return prisma.keypairs.delete({ + where: { hash }, + }); +}; diff --git a/src/db/keypair/get.ts b/src/db/keypair/get.ts new file mode 100644 index 000000000..3cfc24123 --- /dev/null +++ b/src/db/keypair/get.ts @@ -0,0 +1,15 @@ +import { Keypairs } from "@prisma/client"; +import { createHash } from "crypto"; +import { prisma } from "../client"; + +export const getKeypairByPublicKey = async ({ + publicKey, +}: { + publicKey: string; +}): Promise => { + const hash = createHash("sha256").update(publicKey).digest("hex"); + + return prisma.keypairs.findUnique({ + where: { hash }, + }); +}; diff --git a/src/db/keypair/insert.ts b/src/db/keypair/insert.ts new file mode 100644 index 000000000..c6d7b737d --- /dev/null +++ b/src/db/keypair/insert.ts @@ -0,0 +1,25 @@ +import { Keypairs } from "@prisma/client"; +import { createHash } from "crypto"; +import { KeypairAlgorithm } from "../../server/schemas/keypairs"; +import { prisma } from "../client"; + +export const insertKeypair = async ({ + publicKey, + algorithm, + label, +}: { + publicKey: string; + algorithm: KeypairAlgorithm; + label?: string; +}): Promise => { + const hash = createHash("sha256").update(publicKey).digest("hex"); + + return prisma.keypairs.create({ + data: { + hash, + publicKey, + algorithm, + label, + }, + }); +}; diff --git a/src/db/keypair/list.ts b/src/db/keypair/list.ts new file mode 100644 index 000000000..cc08bbda8 --- /dev/null +++ b/src/db/keypair/list.ts @@ -0,0 +1,6 @@ +import { Keypairs } from "@prisma/client"; +import { prisma } from "../client"; + +export const listKeypairs = async (): Promise => { + return prisma.keypairs.findMany(); +}; diff --git a/src/db/tokens/getToken.ts b/src/db/tokens/getToken.ts index 020aad360..4eb92380a 100644 --- a/src/db/tokens/getToken.ts +++ b/src/db/tokens/getToken.ts @@ -1,15 +1,14 @@ import { parseJWT } from "@thirdweb-dev/auth"; import { prisma } from "../client"; -interface GetTokenParams { - jwt: string; -} - -export const getToken = async ({ jwt }: GetTokenParams) => { +export const getToken = async (jwt: string) => { const { payload } = parseJWT(jwt); - return prisma.tokens.findUnique({ - where: { - id: payload.jti, - }, - }); + if (payload.jti) { + return prisma.tokens.findUnique({ + where: { + id: payload.jti, + }, + }); + } + return null; }; diff --git a/src/db/transactions/cleanTxs.ts b/src/db/transactions/cleanTxs.ts index 064f334e1..5875c2d1e 100644 --- a/src/db/transactions/cleanTxs.ts +++ b/src/db/transactions/cleanTxs.ts @@ -15,16 +15,14 @@ export const cleanTxs = ( sentAt: tx.sentAt?.toISOString() || null, minedAt: tx.minedAt?.toISOString() || null, cancelledAt: tx.cancelledAt?.toISOString() || null, - status: !!tx.errorMessage + status: tx.errorMessage ? "errored" - : !!tx.minedAt + : tx.minedAt ? "mined" - : !!tx.cancelledAt + : tx.cancelledAt ? "cancelled" - : !!tx.sentAt && tx.retryCount === 0 + : tx.sentAt ? "sent" - : !!tx.sentAt && tx.retryCount > 0 - ? "retried" : "queued", }; }); diff --git a/src/db/transactions/queueTx.ts b/src/db/transactions/queueTx.ts index 3643cf25c..1da93104e 100644 --- a/src/db/transactions/queueTx.ts +++ b/src/db/transactions/queueTx.ts @@ -15,6 +15,11 @@ interface QueueTxParams { deployedContractType?: string; simulateTx?: boolean; idempotencyKey?: string; + txOverrides?: { + gasLimit?: string; + maxFeePerGas?: string; + maxPriorityFeePerGas?: string; + }; } export const queueTx = async ({ @@ -26,6 +31,7 @@ export const queueTx = async ({ deployedContractType, simulateTx, idempotencyKey, + txOverrides, }: QueueTxParams) => { // TODO: We need a much safer way of detecting if the transaction should be a user operation const isUserOp = !!(tx.getSigner as ERC4337EthersSigner).erc4337provider; @@ -38,6 +44,7 @@ export const queueTx = async ({ deployedContractType: deployedContractType, data: tx.encode(), value: BigNumber.from(await tx.getValue()).toHexString(), + ...txOverrides, }; if (isUserOp) { @@ -60,7 +67,12 @@ export const queueTx = async ({ return queueId; } else { const fromAddress = await tx.getSignerAddress(); - const toAddress = tx.getTarget(); + const toAddress = + tx.getTarget() === "0x0000000000000000000000000000000000000000" && + txData.functionName === "deploy" && + extension === "deploy-published" + ? null + : tx.getTarget(); const { id: queueId } = await queueTxRaw({ pgtx, diff --git a/src/db/transactions/updateTx.ts b/src/db/transactions/updateTx.ts index 217b0a350..7e86426a4 100644 --- a/src/db/transactions/updateTx.ts +++ b/src/db/transactions/updateTx.ts @@ -24,6 +24,7 @@ type UpdateTxData = res: ethers.providers.TransactionRequest; sentAtBlockNumber: number; retryCount?: number; + deployedContractAddress?: string; } | { status: TransactionStatus.UserOpSent; @@ -84,6 +85,7 @@ export const updateTx = async ({ pgtx, queueId, data }: UpdateTxParams) => { maxFeePerGas: data.res?.maxFeePerGas?.toString(), maxPriorityFeePerGas: data.res?.maxPriorityFeePerGas?.toString(), value: data.res?.value?.toString(), + deployedContractAddress: data.deployedContractAddress, }, }); break; diff --git a/src/prisma/migrations/20240327202800_add_keypairs/migration.sql b/src/prisma/migrations/20240327202800_add_keypairs/migration.sql new file mode 100644 index 000000000..aff4b4e2f --- /dev/null +++ b/src/prisma/migrations/20240327202800_add_keypairs/migration.sql @@ -0,0 +1,8 @@ +-- CreateTable +CREATE TABLE "keypairs" ( + "hash" TEXT NOT NULL, + "publicKey" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "keypairs_pkey" PRIMARY KEY ("hash") +); diff --git a/src/prisma/migrations/20240410015450_add_keypair_algorithm/migration.sql b/src/prisma/migrations/20240410015450_add_keypair_algorithm/migration.sql new file mode 100644 index 000000000..4c806f34a --- /dev/null +++ b/src/prisma/migrations/20240410015450_add_keypair_algorithm/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - Added the required column `algorithm` to the `keypairs` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "keypairs" ADD COLUMN "algorithm" TEXT NOT NULL; diff --git a/src/prisma/migrations/20240411235927_add_keypair_label/migration.sql b/src/prisma/migrations/20240411235927_add_keypair_label/migration.sql new file mode 100644 index 000000000..7f04c3070 --- /dev/null +++ b/src/prisma/migrations/20240411235927_add_keypair_label/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "keypairs" ADD COLUMN "label" TEXT, +ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP; diff --git a/src/prisma/schema.prisma b/src/prisma/schema.prisma index 57dfc7578..b3d3c967c 100644 --- a/src/prisma/schema.prisma +++ b/src/prisma/schema.prisma @@ -265,3 +265,14 @@ model ChainIndexers { @@map("chain_indexers") } + +model Keypairs { + hash String @id + publicKey String + algorithm String + label String? + createdAt DateTime @default(now()) + updatedAt DateTime @default(now()) + + @@map("keypairs") +} diff --git a/src/server/middleware/auth.ts b/src/server/middleware/auth.ts index 4636e89bd..54111c77c 100644 --- a/src/server/middleware/auth.ts +++ b/src/server/middleware/auth.ts @@ -1,23 +1,24 @@ -import { Json, User, authenticateJWT, parseJWT } from "@thirdweb-dev/auth"; +import { parseJWT } from "@thirdweb-dev/auth"; import { ThirdwebAuth, ThirdwebAuthUser, getToken as getJWT, } from "@thirdweb-dev/auth/fastify"; -import { GenericAuthWallet } from "@thirdweb-dev/wallets"; import { AsyncWallet } from "@thirdweb-dev/wallets/evm/wallets/async"; -import { utils } from "ethers"; import { FastifyInstance } from "fastify"; import { FastifyRequest } from "fastify/types/request"; +import jsonwebtoken from "jsonwebtoken"; import { validate as uuidValidate } from "uuid"; import { getPermissions } from "../../db/permissions/getPermissions"; import { createToken } from "../../db/tokens/createToken"; import { revokeToken } from "../../db/tokens/revokeToken"; import { WebhooksEventTypes } from "../../schema/webhooks"; +import { THIRDWEB_DASHBOARD_ISSUER, handleSiwe } from "../../utils/auth"; import { getAccessToken } from "../../utils/cache/accessToken"; import { getAuthWallet } from "../../utils/cache/authWallet"; import { getConfig } from "../../utils/cache/getConfig"; import { getWebhook } from "../../utils/cache/getWebhook"; +import { getKeypair } from "../../utils/cache/keypair"; import { env } from "../../utils/env"; import { logger } from "../../utils/logger"; import { sendWebhookRequest } from "../../utils/webhook"; @@ -26,57 +27,19 @@ import { Permission } from "../schemas/auth"; export type TAuthData = never; export type TAuthSession = { permissions: string }; +interface AuthResponse { + isAuthed: boolean; + user?: ThirdwebAuthUser; + // If error is provided, return an error immediately. + error?: string; +} + declare module "fastify" { interface FastifyRequest { user: ThirdwebAuthUser; } } -const authWithApiServer = async (jwt: string, domain: string) => { - let user: User | null = null; - try { - user = await authenticateJWT({ - clientOptions: { - secretKey: env.THIRDWEB_API_SECRET_KEY, - }, - wallet: { - type: "evm", - getAddress: async () => "0x016757dDf2Ab6a998a4729A80a091308d9059E17", - verifySignature: async ( - message: string, - signature: string, - address: string, - ) => { - try { - const messageHash = utils.hashMessage(message); - const messageHashBytes = utils.arrayify(messageHash); - const recoveredAddress = utils.recoverAddress( - messageHashBytes, - signature, - ); - - if (recoveredAddress === address) { - return true; - } - } catch { - // no-op - } - - return false; - }, - } as GenericAuthWallet, - jwt, - options: { - domain, - }, - }); - } catch { - // no-op - } - - return user; -}; - export const withAuth = async (server: FastifyInstance) => { const config = await getConfig(); @@ -140,14 +103,19 @@ export const withAuth = async (server: FastifyInstance) => { // Add auth validation middleware to check for authenticated requests server.addHook("onRequest", async (req, res) => { + let message = + "Please provide a valid access token or other authentication. See: https://portal.thirdweb.com/engine/features/access-tokens"; + try { - const { isAuthed, user } = await onRequest({ req, getUser }); + const { isAuthed, user, error } = await onRequest({ req, getUser }); if (isAuthed) { if (user) { req.user = user; } // Allow this request to proceed. return; + } else if (error) { + message = error; } } catch (err: any) { logger({ @@ -158,14 +126,9 @@ export const withAuth = async (server: FastifyInstance) => { }); } - // Return 401 if: - // - There was an error authenticating this request. - // - No auth credentials were provided. - // - The auth credentials were invalid or revoked. return res.status(401).send({ error: "Unauthorized", - message: - "Please provide a valid access token or other authentication. See: https://portal.thirdweb.com/engine/features/permissions", + message, }); }); }; @@ -176,46 +139,181 @@ export const onRequest = async ({ }: { req: FastifyRequest; getUser: ReturnType>["getUser"]; -}): Promise<{ - isAuthed: boolean; - user?: ThirdwebAuthUser; -}> => { - if ( - req.url === "/favicon.ico" || - req.url === "/" || - req.url === "/system/health" || - req.url === "/json" || - req.url.startsWith("/auth/payload") || - req.url.startsWith("/auth/login") || - req.url.startsWith("/auth/user") || - req.url.startsWith("/auth/switch-account") || - req.url.startsWith("/auth/logout") || - req.url.startsWith("/transaction/status") - ) { - // Skip auth check for static endpoints and Thirdweb Auth routes. - return { isAuthed: true }; +}): Promise => { + // Handle websocket auth separately. + if (req.headers.upgrade?.toLowerCase() === "websocket") { + return handleWebsocketAuth(req, getUser); + } + + const publicRoutesResp = handlePublicEndpoints(req); + if (publicRoutesResp.isAuthed) { + return publicRoutesResp; } - if (req.method === "POST" && req.url.startsWith("/relayer/")) { - const relayerId = req.url.slice("/relayer/".length); - if (uuidValidate(relayerId)) { - // The "relay transaction" endpoint handles its own authentication. + const jwt = getJWT(req); + if (jwt) { + const payload = jsonwebtoken.decode(jwt, { json: true }); + + // The `iss` field determines the auth type. + if (payload?.iss) { + const authWallet = await getAuthWallet(); + if (payload.iss === (await authWallet.getAddress())) { + return await handleAccessToken(jwt, req, getUser); + } else if (payload.iss === THIRDWEB_DASHBOARD_ISSUER) { + return await handleDashboardAuth(jwt); + } else { + return await handleKeypairAuth(jwt, payload.iss); + } + } + } + + const secretKeyResp = await handleSecretKey(req); + if (secretKeyResp.isAuthed) { + return secretKeyResp; + } + + const authWebhooksResp = await handleAuthWebhooks(req); + if (authWebhooksResp.isAuthed) { + return authWebhooksResp; + } + + // Unauthorized: no auth patterns matched. + return { isAuthed: false }; +}; + +/** + * Handles unauthed routes. + * @param req FastifyRequest + * @returns AuthResponse + */ +const handlePublicEndpoints = (req: FastifyRequest): AuthResponse => { + if (req.method === "GET") { + if ( + req.url === "/favicon.ico" || + req.url === "/" || + req.url === "/system/health" || + req.url === "/json" || + req.url.startsWith("/auth/user") || + req.url.startsWith("/transaction/status") + ) { return { isAuthed: true }; } + } else if (req.method === "POST") { + if ( + req.url.startsWith("/auth/payload") || + req.url.startsWith("/auth/login") || + req.url.startsWith("/auth/switch-account") || + req.url.startsWith("/auth/logout") + ) { + return { isAuthed: true }; + } + + if (req.url.startsWith("/relayer/")) { + const relayerId = req.url.slice("/relayer/".length); + if (uuidValidate(relayerId)) { + // "Relay transaction" endpoint which handles its own authentication. + return { isAuthed: true }; + } + } } - // Handle websocket request: auth via access token - // Allow a request that provides a non-revoked access token for an owner/admin. - if ( - req.headers.upgrade && - req.headers.upgrade.toLowerCase() === "websocket" - ) { - const { token: jwt } = req.query as { token: string }; + return { isAuthed: false }; +}; +/** + * Handle websocket request: auth via access token + * Allow a request that provides a non-revoked access token for an owner/admin + * Handle websocket auth separately. + * @param req FastifyRequest + * @param getUser + * @returns AuthResponse + * @async + */ +const handleWebsocketAuth = async ( + req: FastifyRequest, + getUser: ReturnType>["getUser"], +): Promise => { + const { token: jwt } = req.query as { token: string }; + + const token = await getAccessToken({ jwt }); + if (token && token.revokedAt === null) { + // Set as a header for `getUsers` to parse the token. + req.headers.authorization = `Bearer ${jwt}`; + const user = await getUser(req); + if ( + user?.session?.permissions === Permission.Owner || + user?.session?.permissions === Permission.Admin + ) { + return { isAuthed: true, user }; + } + } + + // Destroy the websocket connection. + req.raw.socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n"); + req.raw.socket.destroy(); + return { isAuthed: false }; +}; + +/** + * Auth via keypair. + * Allow a request that provides a JWT signed by an ES256 private key + * matching the configured public key. + * @param req FastifyRequest + * @returns AuthResponse + */ +const handleKeypairAuth = async ( + jwt: string, + iss: string, +): Promise => { + // The keypair auth feature must be explicitly enabled. + if (!env.ENABLE_KEYPAIR_AUTH) { + return { isAuthed: false }; + } + + let error: string | undefined; + try { + const keypair = await getKeypair({ publicKey: iss }); + if (!keypair || keypair.publicKey !== iss) { + error = "The provided public key is incorrect or not added to Engine."; + throw error; + } + + // The JWT is valid if `verify` did not throw. + jsonwebtoken.verify(jwt, keypair.publicKey, { + algorithms: [keypair.algorithm as jsonwebtoken.Algorithm], + }) as jsonwebtoken.JwtPayload; + + return { isAuthed: true }; + } catch (e) { + if (e instanceof jsonwebtoken.TokenExpiredError) { + error = "Keypair token is expired."; + } else if (!error) { + // Default error. + error = + 'Error parsing "Authorization" header. See: https://portal.thirdweb.com/engine/features/access-tokens'; + } + } + + return { isAuthed: false, error }; +}; + +/** + * Auth via access token. + * Allow a request that provides a non-revoked access token for an owner/admin. + * @param jwt string + * @param req FastifyRequest + * @param getUser + * @returns AuthResponse + * @async + */ +const handleAccessToken = async ( + jwt: string, + req: FastifyRequest, + getUser: ReturnType>["getUser"], +): Promise => { + try { const token = await getAccessToken({ jwt }); if (token && token.revokedAt === null) { - // Set as a header for `getUsers` to parse the token. - req.headers.authorization = `Bearer ${jwt}`; const user = await getUser(req); if ( user?.session?.permissions === Permission.Owner || @@ -224,58 +322,53 @@ export const onRequest = async ({ return { isAuthed: true, user }; } } - - // Destroy the websocket connection. - req.raw.socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n"); - req.raw.socket.destroy(); - return { isAuthed: false }; + } catch (e) { + // Missing or invalid signature. This will occur if the JWT not intended for this auth pattern. } - try { - const jwt = getJWT(req); - if (jwt) { - // Auth via access token - // Allow a request that provides a non-revoked access token for an owner/admin. - const token = await getAccessToken({ jwt }); - if (token && token.revokedAt === null) { - const user = await getUser(req); - if ( - user?.session?.permissions === Permission.Owner || - user?.session?.permissions === Permission.Admin - ) { - return { isAuthed: true, user }; - } - } + return { isAuthed: false }; +}; - // Auth via dashboard - // Allow a request that provides a dashboard JWT. - const user = - (await authWithApiServer(jwt, "thirdweb.com")) || - (await authWithApiServer(jwt, "thirdweb-preview.com")); - if (user) { - const res = await getPermissions({ walletAddress: user.address }); - if ( - res?.permissions === Permission.Owner || - res?.permissions === Permission.Admin - ) { - return { - isAuthed: true, - user: { - address: user.address, - session: { - permissions: res.permissions, - }, - }, - }; - } - } +/** + * Auth via dashboard. + * Allow a request that provides a dashboard JWT. + * @param jwt string + * @returns AuthResponse + * @async + */ +const handleDashboardAuth = async (jwt: string): Promise => { + const user = + (await handleSiwe(jwt, "thirdweb.com", THIRDWEB_DASHBOARD_ISSUER)) || + (await handleSiwe(jwt, "thirdweb-preview.com", THIRDWEB_DASHBOARD_ISSUER)); + if (user) { + const res = await getPermissions({ walletAddress: user.address }); + if ( + res?.permissions === Permission.Owner || + res?.permissions === Permission.Admin + ) { + return { + isAuthed: true, + user: { + address: user.address, + session: { + permissions: res.permissions, + }, + }, + }; } - } catch { - // This throws if no JWT is provided. Continue to check other auth mechanisms. } - // Auth via thirdweb secret key - // Allow a request that provides the thirdweb secret key used to init Engine. + return { isAuthed: false }; +}; + +/** + * Auth via thirdweb secret key. + * Allow a request that provides the thirdweb secret key used to init Engine. + * + * @param req FastifyRequest + * @returns + */ +const handleSecretKey = async (req: FastifyRequest): Promise => { const thirdwebApiSecretKey = req.headers.authorization?.split(" ")[1]; if (thirdwebApiSecretKey === env.THIRDWEB_API_SECRET_KEY) { const authWallet = await getAuthWallet(); @@ -290,9 +383,20 @@ export const onRequest = async ({ }; } - // Auth via auth webhooks - // Allow a request if it satisfies all configured auth webhooks. - // Must have at least one auth webhook. + return { isAuthed: false }; +}; + +/** + * Auth via auth webhooks + * Allow a request if it satisfies all configured auth webhooks. + * Must have at least one auth webhook. + * @param req FastifyRequest + * @returns AuthResponse + * @async + */ +const handleAuthWebhooks = async ( + req: FastifyRequest, +): Promise => { const authWebhooks = await getWebhook(WebhooksEventTypes.AUTH); if (authWebhooks.length > 0) { const authResponses = await Promise.all( diff --git a/src/server/routes/auth/keypair/add.ts b/src/server/routes/auth/keypair/add.ts new file mode 100644 index 000000000..a8a3621f0 --- /dev/null +++ b/src/server/routes/auth/keypair/add.ts @@ -0,0 +1,87 @@ +import { Keypairs, Prisma } from "@prisma/client"; +import { Static, Type } from "@sinclair/typebox"; +import { FastifyInstance } from "fastify"; +import { StatusCodes } from "http-status-codes"; +import { insertKeypair } from "../../../../db/keypair/insert"; +import { isWellFormedPublicKey } from "../../../../utils/crypto"; +import { createCustomError } from "../../../middleware/error"; +import { + KeypairAlgorithmSchema, + KeypairSchema, + toKeypairSchema, +} from "../../../schemas/keypairs"; +import { standardResponseSchema } from "../../../schemas/sharedApiSchemas"; + +const BodySchema = Type.Object({ + publicKey: Type.String({ + description: + "The public key of your keypair beginning with '-----BEGIN PUBLIC KEY-----'.", + }), + algorithm: KeypairAlgorithmSchema, + label: Type.Optional(Type.String()), +}); + +const ReplySchema = Type.Object({ + result: Type.Object({ + keypair: KeypairSchema, + }), +}); + +export async function addKeypair(fastify: FastifyInstance) { + fastify.route<{ + Body: Static; + Reply: Static; + }>({ + method: "POST", + url: "/auth/keypair/add", + schema: { + summary: "Add public key", + description: "Add the public key for a keypair", + tags: ["Keypair"], + operationId: "add", + body: BodySchema, + response: { + ...standardResponseSchema, + [StatusCodes.OK]: ReplySchema, + }, + }, + handler: async (req, res) => { + const { publicKey: publicKeyRaw, algorithm, label } = req.body; + const publicKey = publicKeyRaw.trim(); + + if (!isWellFormedPublicKey(publicKey)) { + throw createCustomError( + "Invalid public key. Make sure it starts with '-----BEGIN PUBLIC KEY-----'.", + StatusCodes.BAD_REQUEST, + "INVALID_PUBLIC_KEY", + ); + } + + let keypair: Keypairs; + try { + keypair = await insertKeypair({ + publicKey, + algorithm, + label, + }); + } catch (e) { + if (e instanceof Prisma.PrismaClientKnownRequestError) { + if (e.code === "P2002") { + throw createCustomError( + "Public key already imported.", + StatusCodes.BAD_REQUEST, + "PUBLIC_KEY_EXISTS", + ); + } + } + throw e; + } + + res.status(200).send({ + result: { + keypair: toKeypairSchema(keypair), + }, + }); + }, + }); +} diff --git a/src/server/routes/auth/keypair/list.ts b/src/server/routes/auth/keypair/list.ts new file mode 100644 index 000000000..162a741e8 --- /dev/null +++ b/src/server/routes/auth/keypair/list.ts @@ -0,0 +1,36 @@ +import { Static, Type } from "@sinclair/typebox"; +import { FastifyInstance } from "fastify"; +import { StatusCodes } from "http-status-codes"; +import { listKeypairs } from "../../../../db/keypair/list"; +import { KeypairSchema, toKeypairSchema } from "../../../schemas/keypairs"; +import { standardResponseSchema } from "../../../schemas/sharedApiSchemas"; + +const ReplySchema = Type.Object({ + result: Type.Array(KeypairSchema), +}); + +export async function listPublicKeys(fastify: FastifyInstance) { + fastify.route<{ + Reply: Static; + }>({ + method: "GET", + url: "/auth/keypair/get-all", + schema: { + summary: "List public keys", + description: "List the public keys configured with Engine", + tags: ["Keypair"], + operationId: "list", + response: { + ...standardResponseSchema, + [StatusCodes.OK]: ReplySchema, + }, + }, + handler: async (req, res) => { + const keypairs = await listKeypairs(); + + res.status(200).send({ + result: keypairs.map(toKeypairSchema), + }); + }, + }); +} diff --git a/src/server/routes/auth/keypair/remove.ts b/src/server/routes/auth/keypair/remove.ts new file mode 100644 index 000000000..ba3eca477 --- /dev/null +++ b/src/server/routes/auth/keypair/remove.ts @@ -0,0 +1,47 @@ +import { Static, Type } from "@sinclair/typebox"; +import { FastifyInstance } from "fastify"; +import { StatusCodes } from "http-status-codes"; +import { deleteKeypair } from "../../../../db/keypair/delete"; +import { keypairCache } from "../../../../utils/cache/keypair"; +import { standardResponseSchema } from "../../../schemas/sharedApiSchemas"; + +const BodySchema = Type.Object({ + hash: Type.String(), +}); + +const ReplySchema = Type.Object({ + result: Type.Object({ + success: Type.Boolean(), + }), +}); + +export async function removePublicKey(fastify: FastifyInstance) { + fastify.route<{ + Body: Static; + Reply: Static; + }>({ + method: "POST", + url: "/auth/keypair/remove", + schema: { + summary: "Remove public key", + description: "Remove the public key for a keypair", + tags: ["Keypair"], + operationId: "remove", + body: BodySchema, + response: { + ...standardResponseSchema, + [StatusCodes.OK]: ReplySchema, + }, + }, + handler: async (req, res) => { + const { hash } = req.body; + + await deleteKeypair({ hash }); + keypairCache.clear(); + + res.status(200).send({ + result: { success: true }, + }); + }, + }); +} diff --git a/src/server/routes/contract/subscriptions/getLatestBlock.ts b/src/server/routes/contract/subscriptions/getLatestBlock.ts index 2e26191a3..eac39bdea 100644 --- a/src/server/routes/contract/subscriptions/getLatestBlock.ts +++ b/src/server/routes/contract/subscriptions/getLatestBlock.ts @@ -29,10 +29,11 @@ export async function getLatestBlock(fastify: FastifyInstance) { method: "GET", url: "/contract/subscriptions/get-last-block", schema: { - summary: "Get subscribed contract latest indexed block", - description: "Get latest indexed block for a subscribed contract", + summary: "Get latest indexed block for a chain", + description: "Get latest indexed block for a chain", tags: ["Contract-Subscriptions"], - operationId: "getContractSubscriptions", + operationId: "getLatestBlock", + querystring: chainRequestQuerystringSchema, response: { ...standardResponseSchema, [StatusCodes.OK]: responseSchema, diff --git a/src/server/routes/contract/write/write.ts b/src/server/routes/contract/write/write.ts index 880787e88..92c5ba190 100644 --- a/src/server/routes/contract/write/write.ts +++ b/src/server/routes/contract/write/write.ts @@ -88,14 +88,23 @@ export async function writeToContract(fastify: FastifyInstance) { const tx = contract.prepare(functionName, args, { value: txOverrides?.value, gasLimit: txOverrides?.gas, + maxFeePerGas: txOverrides?.maxFeePerGas, + maxPriorityFeePerGas: txOverrides?.maxPriorityFeePerGas, }); + const gasLimit = txOverrides?.gas; + delete txOverrides?.gas; + const queueId = await queueTx({ tx, chainId, simulateTx, extension: "none", idempotencyKey, + txOverrides: { + ...txOverrides, + gasLimit, + }, }); reply.status(StatusCodes.OK).send({ diff --git a/src/server/routes/deploy/published.ts b/src/server/routes/deploy/published.ts index 13f0ef22c..d2acf7e05 100644 --- a/src/server/routes/deploy/published.ts +++ b/src/server/routes/deploy/published.ts @@ -10,6 +10,7 @@ import { import { txOverrides } from "../../schemas/txOverrides"; import { walletHeaderSchema } from "../../schemas/wallet"; import { getChainIdFromChain } from "../../utils/chain"; +import { isAddress } from "thirdweb"; // INPUTS const requestSchema = publishedDeployParamSchema; @@ -35,7 +36,12 @@ requestBodySchema.examples = [ // OUTPUT const responseSchema = Type.Object({ queueId: Type.Optional(Type.String()), - deployedAddress: Type.Optional(Type.String()), + deployedAddress: Type.Optional( + Type.String({ + description: "Not all contracts return a deployed address.", + }), + ), + message: Type.Optional(Type.String()), }); export async function deployPublished(fastify: FastifyInstance) { @@ -76,7 +82,10 @@ export async function deployPublished(fastify: FastifyInstance) { constructorParams, version, ); - const deployedAddress = await tx.simulate(); + const _deployedAddress = await tx.simulate(); + const deployedAddress = isAddress(_deployedAddress) + ? _deployedAddress + : undefined; const queueId = await queueTx({ tx, @@ -90,6 +99,9 @@ export async function deployPublished(fastify: FastifyInstance) { reply.status(StatusCodes.OK).send({ deployedAddress, queueId, + message: !deployedAddress + ? `To retrieve the deployed contract address, use the endpoint '/transaction/status/${queueId}' and check the value of the 'deployedContractAddress' field` + : undefined, }); }, }); diff --git a/src/server/routes/index.ts b/src/server/routes/index.ts index c76bf2324..a64798980 100644 --- a/src/server/routes/index.ts +++ b/src/server/routes/index.ts @@ -79,6 +79,11 @@ import { getAllAccessTokens } from "./auth/access-tokens/getAll"; import { revokeAccessToken } from "./auth/access-tokens/revoke"; import { updateAccessToken } from "./auth/access-tokens/update"; +// Keypairs +import { addKeypair } from "./auth/keypair/add"; +import { listPublicKeys } from "./auth/keypair/list"; +import { removePublicKey } from "./auth/keypair/remove"; + // Admins import { getAllPermissions } from "./auth/permissions/getAll"; import { grantPermissions } from "./auth/permissions/grant"; @@ -184,6 +189,11 @@ export const withRoutes = async (fastify: FastifyInstance) => { await fastify.register(revokeAccessToken); await fastify.register(updateAccessToken); + // Keypairs + await fastify.register(listPublicKeys); + await fastify.register(addKeypair); + await fastify.register(removePublicKey); + // Chains await fastify.register(getChainData); await fastify.register(getAllChainData); diff --git a/src/server/routes/system/health.ts b/src/server/routes/system/health.ts index e4e207bb7..a31bf9c6f 100644 --- a/src/server/routes/system/health.ts +++ b/src/server/routes/system/health.ts @@ -2,10 +2,14 @@ import { Static, Type } from "@sinclair/typebox"; import { FastifyInstance } from "fastify"; import { StatusCodes } from "http-status-codes"; import { isDatabaseHealthy } from "../../../db/client"; +import { env } from "../../../utils/env"; + +type EngineFeature = "KEYPAIR_AUTH"; const ReplySchemaOk = Type.Object({ status: Type.String(), engineVersion: Type.Optional(Type.String()), + features: Type.Array(Type.Union([Type.Literal("KEYPAIR_AUTH")])), }); const ReplySchemaError = Type.Object({ @@ -42,7 +46,14 @@ export async function healthCheck(fastify: FastifyInstance) { res.status(StatusCodes.OK).send({ status: "OK", engineVersion: process.env.ENGINE_VERSION, + features: getFeatures(), }); }, }); } + +const getFeatures = (): EngineFeature[] => { + const features: EngineFeature[] = []; + if (env.ENABLE_KEYPAIR_AUTH) features.push("KEYPAIR_AUTH"); + return features; +}; diff --git a/src/server/routes/transaction/cancel.ts b/src/server/routes/transaction/cancel.ts index 70e794f66..214eefcc3 100644 --- a/src/server/routes/transaction/cancel.ts +++ b/src/server/routes/transaction/cancel.ts @@ -40,7 +40,7 @@ export const responseBodySchema = Type.Object({ responseBodySchema.example = { result: { - qeueuId: "a20ed4ce-301d-4251-a7af-86bd88f6c015", + queueId: "a20ed4ce-301d-4251-a7af-86bd88f6c015", status: "success", }, }; diff --git a/src/server/schemas/keypairs.ts b/src/server/schemas/keypairs.ts new file mode 100644 index 000000000..31a3a7bc7 --- /dev/null +++ b/src/server/schemas/keypairs.ts @@ -0,0 +1,63 @@ +import { Keypairs } from "@prisma/client"; +import { Static, Type } from "@sinclair/typebox"; + +// https://github.com/auth0/node-jsonwebtoken#algorithms-supported +const _supportedAlgorithms = [ + // Symmetric algorithms are disabled to avoid storing keys in plaintext. + // "HS256", + // "HS384", + // "HS512", + "RS256", + "RS384", + "RS512", + "ES256", + "ES384", + "ES512", + "PS256", + "PS384", + "PS512", +] as const; + +export type KeypairAlgorithm = (typeof _supportedAlgorithms)[number]; + +export const KeypairAlgorithmSchema = Type.Union( + _supportedAlgorithms.map((alg) => Type.Literal(alg)), +); + +export const KeypairSchema = Type.Object({ + hash: Type.String({ + description: "A unique identifier for the keypair", + }), + publicKey: Type.String({ + description: "The public key", + }), + algorithm: Type.String({ + description: "The keypair algorithm.", + }), + label: Type.Optional( + Type.String({ + description: "A description for the keypair.", + }), + ), + createdAt: Type.Unsafe({ + type: "string", + format: "date", + description: "When the keypair was added", + }), + updatedAt: Type.Unsafe({ + type: "string", + format: "date", + description: "When the keypair was updated", + }), +}); + +export const toKeypairSchema = ( + keypair: Keypairs, +): Static => ({ + hash: keypair.hash, + publicKey: keypair.publicKey, + algorithm: keypair.algorithm, + label: keypair.label ?? undefined, + createdAt: keypair.createdAt, + updatedAt: keypair.updatedAt, +}); diff --git a/src/server/schemas/transaction/index.ts b/src/server/schemas/transaction/index.ts index 88f363891..11fc00f0f 100644 --- a/src/server/schemas/transaction/index.ts +++ b/src/server/schemas/transaction/index.ts @@ -198,41 +198,3 @@ export enum TransactionStatus { // Tx was cancelled and will not be re-attempted. Cancelled = "cancelled", } - -export interface TransactionSchema { - identifier?: string; - walletAddress?: string; - contractAddress?: string; - chainId?: string; - extension?: string; - rawFunctionName?: string; - rawFunctionArgs?: string; - txProcessed?: boolean; - txSubmitted?: boolean; - txErrored?: boolean; - txMined?: boolean; - encodedInputData?: string; - txType?: number; - gasPrice?: string; - gasLimit?: string; - maxPriorityFeePerGas?: string; - maxFeePerGas?: string; - txHash?: string; - status?: string; - createdTimestamp?: Date; - txSubmittedTimestamp?: Date; - txProcessedTimestamp?: Date; - submittedTxNonce?: number; - deployedContractAddress?: string; - contractType?: string; - txValue?: string; - errorMessage?: string; - txMinedTimestamp?: Date; - blockNumber?: number; - toAddress?: string; - txSubmittedAtBlockNumber?: number; - numberOfRetries?: number; - overrideGasValuesForTx?: boolean; - overrideMaxFeePerGas?: string; - overrideMaxPriorityFeePerGas?: string; -} diff --git a/src/server/schemas/txOverrides.ts b/src/server/schemas/txOverrides.ts index 638663ef0..929da28b4 100644 --- a/src/server/schemas/txOverrides.ts +++ b/src/server/schemas/txOverrides.ts @@ -15,6 +15,18 @@ export const txOverrides = Type.Object({ description: "Gas limit for the transaction", }), ), + maxFeePerGas: Type.Optional( + Type.String({ + examples: ["1000000000"], + description: "Maximum fee per gas", + }), + ), + maxPriorityFeePerGas: Type.Optional( + Type.String({ + examples: ["1000000000"], + description: "Maximum priority fee per gas", + }), + ), }), ), }); diff --git a/src/server/utils/chain.ts b/src/server/utils/chain.ts index 3c71d371a..29d6f8bb9 100644 --- a/src/server/utils/chain.ts +++ b/src/server/utils/chain.ts @@ -43,18 +43,18 @@ export const getChainIdFromChain = async (input: string): Promise => { if (!isNaN(inputId)) { // Fetch by chain ID. const chainData = await getChainByChainIdAsync(inputId); - if (chainData) { + if (chainData && chainData.status !== "deprecated") { return chainData.chainId; } } else { // Fetch by chain name. const chainData = await getChainBySlugAsync(inputSlug); - if (chainData) { + if (chainData && chainData.status !== "deprecated") { return chainData.chainId; } } throw new Error( - `Invalid chain. Please confirm this is a valid chain: https://thirdweb.com/${input}`, + `Invalid or deprecated chain. Please confirm this is a valid chain: https://thirdweb.com/${input}`, ); }; diff --git a/src/server/utils/transaction.ts b/src/server/utils/transaction.ts index 1db9e3395..efd7d9f8d 100644 --- a/src/server/utils/transaction.ts +++ b/src/server/utils/transaction.ts @@ -1,11 +1,11 @@ -import { TransactionResponse } from "@ethersproject/abstract-provider"; -import { getDefaultGasOverrides } from "@thirdweb-dev/sdk"; +import { StaticJsonRpcProvider } from "@ethersproject/providers"; +import { Transactions } from "@prisma/client"; import { StatusCodes } from "http-status-codes"; -import { getTxById } from "../../db/transactions/getTxById"; +import { prisma } from "../../db/client"; import { updateTx } from "../../db/transactions/updateTx"; import { PrismaTransaction } from "../../schema/prisma"; import { getSdk } from "../../utils/cache/getSdk"; -import { multiplyGasOverrides } from "../../utils/gas"; +import { getGasSettingsForRetry } from "../../utils/gas"; import { createCustomError } from "../middleware/error"; import { TransactionStatus } from "../schemas/transaction"; @@ -18,19 +18,29 @@ export const cancelTransactionAndUpdate = async ({ queueId, pgtx, }: CancelTransactionAndUpdateParams) => { - const txData = await getTxById({ queueId, pgtx }); - if (!txData) { + const tx = await prisma.transactions.findUnique({ + where: { + id: queueId, + }, + }); + if (!tx) { return { message: `Transaction ${queueId} not found.`, }; } - let message = ""; - let error = null; - let transferTransactionResult: TransactionResponse | null = null; + const status: TransactionStatus = tx.errorMessage + ? TransactionStatus.Errored + : tx.minedAt + ? TransactionStatus.Mined + : tx.cancelledAt + ? TransactionStatus.Cancelled + : tx.sentAt + ? TransactionStatus.Sent + : TransactionStatus.Queued; - if (txData.signerAddress && txData.accountAddress) { - switch (txData.status) { + if (tx.signerAddress && tx.accountAddress) { + switch (status) { case TransactionStatus.Errored: throw createCustomError( `Cannot cancel user operation because it already errored`, @@ -62,25 +72,40 @@ export const cancelTransactionAndUpdate = async ({ status: TransactionStatus.Cancelled, }, }); - message = "Transaction cancelled on-database successfully."; - break; + return { + message: "Transaction cancelled on-database successfully.", + }; } } else { - switch (txData.status) { - case TransactionStatus.Errored: - error = createCustomError( - `Transaction has already errored: ${txData.errorMessage}`, + switch (status) { + case TransactionStatus.Errored: { + if (tx.chainId && tx.fromAddress && tx.nonce) { + const { message, transactionHash } = await cancelTransaction(tx); + if (transactionHash) { + await updateTx({ + queueId, + pgtx, + data: { + status: TransactionStatus.Cancelled, + }, + }); + } + + return { message, transactionHash }; + } + + throw createCustomError( + `Transaction has already errored: ${tx.errorMessage}`, StatusCodes.BAD_REQUEST, "TransactionErrored", ); - break; + } case TransactionStatus.Cancelled: - error = createCustomError( + throw createCustomError( "Transaction is already cancelled.", StatusCodes.BAD_REQUEST, "TransactionAlreadyCancelled", ); - break; case TransactionStatus.Queued: await updateTx({ queueId, @@ -89,61 +114,78 @@ export const cancelTransactionAndUpdate = async ({ status: TransactionStatus.Cancelled, }, }); - message = "Transaction cancelled successfully."; - break; + return { + message: "Transaction cancelled successfully.", + }; case TransactionStatus.Mined: - error = createCustomError( + throw createCustomError( "Transaction already mined.", StatusCodes.BAD_REQUEST, "TransactionAlreadyMined", ); - break; case TransactionStatus.Sent: { - const sdk = await getSdk({ - chainId: parseInt(txData.chainId!), - walletAddress: txData.fromAddress!, - }); + if (tx.chainId && tx.fromAddress && tx.nonce) { + const { message, transactionHash } = await cancelTransaction(tx); + if (transactionHash) { + await updateTx({ + queueId, + pgtx, + data: { + status: TransactionStatus.Cancelled, + }, + }); + } - const txReceipt = await sdk - .getProvider() - .getTransactionReceipt(txData.transactionHash!); - if (txReceipt) { - message = "Transaction already mined."; - break; + return { message, transactionHash }; } + } + } + } - const gasOverrides = await getDefaultGasOverrides(sdk.getProvider()); - transferTransactionResult = await sdk.wallet.sendRawTransaction({ - to: txData.fromAddress!, - from: txData.fromAddress!, - data: "0x", - value: "0x00", - nonce: txData.nonce!, - ...multiplyGasOverrides(gasOverrides, 2), - }); + throw new Error("Unhandled cancellation state."); +}; - message = "Transaction cancelled successfully."; +const cancelTransaction = async ( + tx: Transactions, +): Promise<{ + message: string; + transactionHash?: string; +}> => { + if (!tx.fromAddress || !tx.nonce) { + return { message: `Invalid transaction state to cancel. (${tx.id})` }; + } - await updateTx({ - queueId, - pgtx, - data: { - status: TransactionStatus.Cancelled, - }, - }); - break; - } - default: - break; + const sdk = await getSdk({ + chainId: parseInt(tx.chainId), + walletAddress: tx.fromAddress, + }); + const provider = sdk.getProvider() as StaticJsonRpcProvider; + + // Skip if the transaction is already mined. + if (tx.transactionHash) { + const receipt = await provider.getTransactionReceipt(tx.transactionHash); + if (receipt) { + return { message: "Transaction already mined." }; } } - if (error) { - throw error; - } + try { + const gasOptions = await getGasSettingsForRetry(tx, provider); + // Send 0 currency to self. + const { hash } = await sdk.wallet.sendRawTransaction({ + to: tx.fromAddress, + from: tx.fromAddress, + data: "0x", + value: "0", + nonce: tx.nonce, + ...gasOptions, + }); - return { - message, - transactionHash: transferTransactionResult?.hash, - }; + return { + message: "Transaction cancelled successfully.", + transactionHash: hash, + }; + } catch (e: any) { + return { message: e.toString() }; + } }; diff --git a/src/tests/auth.test.ts b/src/tests/auth.test.ts index e2180aa2d..21e1c15d2 100644 --- a/src/tests/auth.test.ts +++ b/src/tests/auth.test.ts @@ -1,13 +1,15 @@ -import { authenticateJWT } from "@thirdweb-dev/auth"; import { LocalWallet } from "@thirdweb-dev/wallets"; import { FastifyRequest } from "fastify/types/request"; +import jsonwebtoken from "jsonwebtoken"; import { getPermissions } from "../db/permissions/getPermissions"; import { WebhooksEventTypes } from "../schema/webhooks"; import { onRequest } from "../server/middleware/auth"; import { Permission } from "../server/schemas/auth"; +import { THIRDWEB_DASHBOARD_ISSUER, handleSiwe } from "../utils/auth"; import { getAccessToken } from "../utils/cache/accessToken"; import { getAuthWallet } from "../utils/cache/authWallet"; import { getWebhook } from "../utils/cache/getWebhook"; +import { getKeypair } from "../utils/cache/keypair"; import { sendWebhookRequest } from "../utils/webhook"; jest.mock("../utils/cache/accessToken"); @@ -15,11 +17,6 @@ const mockGetAccessToken = getAccessToken as jest.MockedFunction< typeof getAccessToken >; -jest.mock("@thirdweb-dev/auth"); -const mockAuthenticateJWT = authenticateJWT as jest.MockedFunction< - typeof authenticateJWT ->; - jest.mock("../db/permissions/getPermissions"); const mockGetPermissions = getPermissions as jest.MockedFunction< typeof getPermissions @@ -32,12 +29,27 @@ const mockGetAuthWallet = getAuthWallet as jest.MockedFunction< jest.mock("../utils/cache/getWebhook"); const mockGetWebhook = getWebhook as jest.MockedFunction; +mockGetWebhook.mockResolvedValue([]); -jest.mock("../server/utils/webhook"); +jest.mock("../utils/webhook"); const mockSendWebhookRequest = sendWebhookRequest as jest.MockedFunction< typeof sendWebhookRequest >; +jest.mock("../utils/auth"); +const mockHandleSiwe = handleSiwe as jest.MockedFunction; + +jest.mock("../utils/cache/keypair"); +const mockGetKeypair = getKeypair as jest.MockedFunction; + +let testAuthWallet: LocalWallet; +beforeAll(async () => { + // Initialize a local auth wallet. + testAuthWallet = new LocalWallet(); + await testAuthWallet.generate(); + mockGetAuthWallet.mockResolvedValue(testAuthWallet); +}); + describe("Static paths", () => { beforeEach(() => { jest.clearAllMocks(); @@ -48,7 +60,7 @@ describe("Static paths", () => { it("Static paths are authed", async () => { const pathsToTest = [ "/", - "/system/heath", + "/system/health", "/json", "/transaction/status/my-queue-id", ]; @@ -143,7 +155,7 @@ describe("Websocket requests", () => { const result = await onRequest({ req, getUser: mockGetUser }); expect(result.isAuthed).toBeTruthy(); - expect(result.user).not.toBeNull(); + expect(result.user).not.toBeUndefined(); }); it("A websocket request with a valid access token and non-admin permission is not authed", async () => { @@ -250,6 +262,10 @@ describe("Access tokens", () => { const mockGetUser = jest.fn(); it("Valid access token with admin permissions is authed", async () => { + const jwt = jsonwebtoken.sign( + { iss: await testAuthWallet.getAddress() }, + "test", + ); mockGetAccessToken.mockResolvedValue({ id: "my-access-token", tokenMask: "", @@ -268,17 +284,21 @@ describe("Access tokens", () => { const req: FastifyRequest = { method: "POST", url: "/backend-wallets/get-all", - headers: { authorization: "Bearer my-access-token" }, + headers: { authorization: `Bearer ${jwt}` }, // @ts-ignore raw: {}, }; const result = await onRequest({ req, getUser: mockGetUser }); expect(result.isAuthed).toBeTruthy(); - expect(result.user).not.toBeNull(); + expect(result.user).not.toBeUndefined(); }); it("Valid access token with non-admin permissions is not authed", async () => { + const jwt = jsonwebtoken.sign( + { iss: await testAuthWallet.getAddress() }, + "test", + ); mockGetAccessToken.mockResolvedValue({ id: "my-access-token", tokenMask: "", @@ -297,7 +317,7 @@ describe("Access tokens", () => { const req: FastifyRequest = { method: "POST", url: "/backend-wallets/get-all", - headers: { authorization: "Bearer my-access-token" }, + headers: { authorization: `Bearer ${jwt}` }, // @ts-ignore raw: {}, }; @@ -307,6 +327,10 @@ describe("Access tokens", () => { }); it("Revoked access token is not authed", async () => { + const jwt = jsonwebtoken.sign( + { iss: await testAuthWallet.getAddress() }, + "test", + ); mockGetAccessToken.mockResolvedValue({ id: "my-access-token", tokenMask: "", @@ -325,7 +349,7 @@ describe("Access tokens", () => { const req: FastifyRequest = { method: "POST", url: "/backend-wallets/get-all", - headers: { authorization: "Bearer my-access-token" }, + headers: { authorization: `Bearer ${jwt}` }, // @ts-ignore raw: {}, }; @@ -335,6 +359,10 @@ describe("Access tokens", () => { }); it("Invalid access token is not authed", async () => { + const jwt = jsonwebtoken.sign( + { iss: await testAuthWallet.getAddress() }, + "test", + ); mockGetAccessToken.mockResolvedValue(null); mockGetUser.mockReturnValue({ @@ -344,7 +372,7 @@ describe("Access tokens", () => { const req: FastifyRequest = { method: "POST", url: "/backend-wallets/get-all", - headers: { authorization: "Bearer my-access-token" }, + headers: { authorization: `Bearer ${jwt}` }, // @ts-ignore raw: {}, }; @@ -354,6 +382,163 @@ describe("Access tokens", () => { }); }); +describe("Keypair auth JWT", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + // Example ES256 keypair used only for unit tests. + const testKeypair = { + public: `-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKbqftPicYL3V+4gZHi16wUWSJ1gO +bsSyKJ/JW3qPUmL0fhdSNZz6C0cP9UNh7FQsLQ/l2BcOH8+G2xvh+8tjtQ== +-----END PUBLIC KEY-----`, + private: `-----BEGIN EC PRIVATE KEY----- +MHcCAQEEICIJbkRowq93OJvo2Tk4eopRbU8dDqp1bh9xHDpF9b6boAoGCCqGSM49 +AwEHoUQDQgAEKbqftPicYL3V+4gZHi16wUWSJ1gObsSyKJ/JW3qPUmL0fhdSNZz6 +C0cP9UNh7FQsLQ/l2BcOH8+G2xvh+8tjtQ== +-----END EC PRIVATE KEY-----`, + } as const; + + const mockGetUser = jest.fn(); + + it("Valid JWT signed by private key", async () => { + mockGetKeypair.mockResolvedValue({ + hash: "", + publicKey: testKeypair.public, + algorithm: "ES256", + label: null, + createdAt: new Date(), + updatedAt: new Date(), + }); + + // Sign a valid auth payload. + const jwt = jsonwebtoken.sign( + { iss: testKeypair.public }, + testKeypair.private, + { + algorithm: "ES256", + expiresIn: "20s", + }, + ); + + const req: FastifyRequest = { + method: "POST", + url: "/backend-wallets/get-all", + headers: { authorization: `Bearer ${jwt}` }, + // @ts-ignore + raw: {}, + }; + + const result = await onRequest({ req, getUser: mockGetUser }); + expect(result.isAuthed).toBeTruthy(); + expect(result.user).toBeUndefined(); + expect(result.error).toBeUndefined(); + }); + + it("Expired JWT signed by private key", async () => { + mockGetKeypair.mockResolvedValue({ + hash: "", + publicKey: testKeypair.public, + algorithm: "ES256", + label: null, + createdAt: new Date(), + updatedAt: new Date(), + }); + + // Sign an expired auth payload. + const jwt = jsonwebtoken.sign( + { iss: testKeypair.public }, + testKeypair.private, + { + algorithm: "ES256", + expiresIn: -3_000, + }, + ); + + const req: FastifyRequest = { + method: "POST", + url: "/backend-wallets/get-all", + headers: { authorization: `Bearer ${jwt}` }, + // @ts-ignore + raw: {}, + }; + + const result = await onRequest({ req, getUser: mockGetUser }); + expect(result.isAuthed).toBeFalsy(); + expect(result.user).toBeUndefined(); + expect(result.error).toEqual("Keypair token is expired."); + }); + + it("Unrecognized public key", async () => { + mockGetKeypair.mockResolvedValue({ + hash: "", + publicKey: testKeypair.public, + algorithm: "ES256", + label: null, + createdAt: new Date(), + updatedAt: new Date(), + }); + + // Sign an expired auth payload. + const jwt = jsonwebtoken.sign( + { iss: "some_other_public_key" }, + testKeypair.private, + { + algorithm: "ES256", + expiresIn: "15s", + }, + ); + + const req: FastifyRequest = { + method: "POST", + url: "/backend-wallets/get-all", + headers: { authorization: `Bearer ${jwt}` }, + // @ts-ignore + raw: {}, + }; + + const result = await onRequest({ req, getUser: mockGetUser }); + expect(result.isAuthed).toBeFalsy(); + expect(result.user).toBeUndefined(); + expect(result.error).toEqual( + "The provided public key is incorrect or not added to Engine.", + ); + }); + + it("Invalid JWT signed by the wrong private key", async () => { + // Sign a valid auth payload with a different private key. + const WRONG_PRIVATE_KEY = `-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIH719lhdn4CzboBQKr8E68htVNeQ2wwrxnsDhfLOgGNAoAoGCCqGSM49 +AwEHoUQDQgAE74w9+HXi/PCQZTu2AS4titehOFopNSrfqlFnFbtglPuwNB2ke53p +6sE9ABLmMjeNbKKz9ayyCGN/BC3MNikhfw== +-----END EC PRIVATE KEY-----`; + const jwt = jsonwebtoken.sign( + { iss: testKeypair.public }, + WRONG_PRIVATE_KEY, + { + algorithm: "ES256", + expiresIn: "15s", + }, + ); + + const req: FastifyRequest = { + method: "POST", + url: "/backend-wallets/get-all", + headers: { authorization: `Bearer ${jwt}` }, + // @ts-ignore + raw: {}, + }; + + const result = await onRequest({ req, getUser: mockGetUser }); + expect(result.isAuthed).toBeFalsy(); + expect(result.user).toBeUndefined(); + expect(result.error).toEqual( + 'Error parsing "Authorization" header. See: https://portal.thirdweb.com/engine/features/access-tokens', + ); + }); +}); + describe("Dashboard JWT", () => { beforeEach(() => { jest.clearAllMocks(); @@ -363,10 +548,10 @@ describe("Dashboard JWT", () => { mockGetAccessToken.mockResolvedValue(null); it("Valid dashboard JWT with admin permission is authed", async () => { - mockAuthenticateJWT.mockResolvedValue({ + const jwt = jsonwebtoken.sign({ iss: THIRDWEB_DASHBOARD_ISSUER }, "test"); + mockHandleSiwe.mockResolvedValue({ address: "0x0000000000000000000000000123", }); - mockGetPermissions.mockResolvedValue({ walletAddress: "0x0000000000000000000000000123", permissions: Permission.Admin, @@ -376,21 +561,22 @@ describe("Dashboard JWT", () => { const req: FastifyRequest = { method: "POST", url: "/backend-wallets/get-all", - headers: { authorization: "Bearer my-access-token" }, + headers: { authorization: `Bearer ${jwt}` }, // @ts-ignore raw: {}, }; const result = await onRequest({ req, getUser: mockGetUser }); expect(result.isAuthed).toBeTruthy(); - expect(result.user).not.toBeNull(); + expect(result.user).not.toBeUndefined(); }); it("Valid dashboard JWT with non-admin permission is not authed", async () => { - mockAuthenticateJWT.mockResolvedValue({ + // Mock dashboard JWTs. + const jwt = jsonwebtoken.sign({ iss: THIRDWEB_DASHBOARD_ISSUER }, "test"); + mockHandleSiwe.mockResolvedValue({ address: "0x0000000000000000000000000123", }); - mockGetPermissions.mockResolvedValue({ walletAddress: "0x0000000000000000000000000123", permissions: "none", @@ -400,7 +586,7 @@ describe("Dashboard JWT", () => { const req: FastifyRequest = { method: "POST", url: "/backend-wallets/get-all", - headers: { authorization: "Bearer my-access-token" }, + headers: { authorization: `Bearer ${jwt}` }, // @ts-ignore raw: {}, }; @@ -409,17 +595,35 @@ describe("Dashboard JWT", () => { expect(result.isAuthed).toBeFalsy(); }); - it("Invalid dashboard JWT is not authed", async () => { - mockAuthenticateJWT.mockResolvedValue({ + it("Dashboard JWT for an unknown user is not authed", async () => { + // Mock dashboard JWTs. + const jwt = jsonwebtoken.sign({ iss: THIRDWEB_DASHBOARD_ISSUER }, "test"); + mockHandleSiwe.mockResolvedValue({ address: "0x0000000000000000000000000123", }); - mockGetPermissions.mockResolvedValue(null); const req: FastifyRequest = { method: "POST", url: "/backend-wallets/get-all", - headers: { authorization: "Bearer my-access-token" }, + headers: { authorization: `Bearer ${jwt}` }, + // @ts-ignore + raw: {}, + }; + + const result = await onRequest({ req, getUser: mockGetUser }); + expect(result.isAuthed).toBeFalsy(); + }); + + it("Invalid dashboard JWT is not authed", async () => { + // Mock dashboard JWTs. + const jwt = jsonwebtoken.sign({ iss: THIRDWEB_DASHBOARD_ISSUER }, "test"); + mockHandleSiwe.mockResolvedValue(null); + + const req: FastifyRequest = { + method: "POST", + url: "/backend-wallets/get-all", + headers: { authorization: `Bearer ${jwt}` }, // @ts-ignore raw: {}, }; @@ -437,11 +641,6 @@ describe("thirdweb secret key", () => { const mockGetUser = jest.fn(); it("Valid thirdweb secret key is authed", async () => { - const localWallet = new LocalWallet(); - await localWallet.generate(); - - mockGetAuthWallet.mockResolvedValue(localWallet); - const req: FastifyRequest = { method: "POST", url: "/backend-wallets/get-all", @@ -452,7 +651,7 @@ describe("thirdweb secret key", () => { const result = await onRequest({ req, getUser: mockGetUser }); expect(result.isAuthed).toBeTruthy(); - expect(result.user).not.toBeNull(); + expect(result.user).not.toBeUndefined(); }); }); @@ -497,7 +696,7 @@ describe("auth webhooks", () => { const result = await onRequest({ req, getUser: mockGetUser }); expect(result.isAuthed).toBeTruthy(); - expect(result.user).not.toBeNull(); + expect(result.user).toBeUndefined(); }); it("A request that gets a non-2xx from any auth webhooks is not authed", async () => { diff --git a/src/tests/chain.test.ts b/src/tests/chain.test.ts index c686027c0..87f997429 100644 --- a/src/tests/chain.test.ts +++ b/src/tests/chain.test.ts @@ -131,8 +131,8 @@ describe("getChainIdFromChain", () => { // @ts-ignore mockGetConfig.mockResolvedValueOnce({}); - await expect(getChainIdFromChain("InvalidChain")).rejects.toThrow( - "Invalid chain. Please confirm this is a valid chain", + await expect(getChainIdFromChain("6666666666666")).rejects.toThrow( + "Invalid or deprecated chain. Please confirm this is a valid chain: https://thirdweb.com/6666666666666", ); }); }); diff --git a/src/utils/auth.ts b/src/utils/auth.ts new file mode 100644 index 000000000..0adec4ff7 --- /dev/null +++ b/src/utils/auth.ts @@ -0,0 +1,43 @@ +import { authenticateJWT } from "@thirdweb-dev/auth"; +import { utils } from "ethers"; +import { env } from "./env"; + +export const THIRDWEB_DASHBOARD_ISSUER = + "0x016757dDf2Ab6a998a4729A80a091308d9059E17"; + +export const handleSiwe = async ( + jwt: string, + domain: string, + issuer: string, +) => { + try { + return await authenticateJWT({ + clientOptions: { + secretKey: env.THIRDWEB_API_SECRET_KEY, + }, + // A stub implementation of a wallet that can only verify a signature. + wallet: { + type: "evm", + getAddress: async () => issuer, + verifySignature: async ( + message: string, + signature: string, + address: string, + ) => { + const messageHash = utils.hashMessage(message); + const messageHashBytes = utils.arrayify(messageHash); + const recoveredAddress = utils.recoverAddress( + messageHashBytes, + signature, + ); + return recoveredAddress === address; + }, + signMessage: async (_: string) => "", + }, + jwt, + options: { domain }, + }); + } catch { + return null; + } +}; diff --git a/src/utils/cache/accessToken.ts b/src/utils/cache/accessToken.ts index 97469b157..894a51dfb 100644 --- a/src/utils/cache/accessToken.ts +++ b/src/utils/cache/accessToken.ts @@ -16,7 +16,7 @@ export const getAccessToken = async ({ return cached; } - const accessToken = await getToken({ jwt }); + const accessToken = await getToken(jwt); accessTokenCache.set(jwt, accessToken); return accessToken; }; diff --git a/src/utils/cache/clearCache.ts b/src/utils/cache/clearCache.ts index ea22928cf..3e4fe2ea5 100644 --- a/src/utils/cache/clearCache.ts +++ b/src/utils/cache/clearCache.ts @@ -4,6 +4,7 @@ import { configCache } from "./getConfig"; import { sdkCache } from "./getSdk"; import { walletsCache } from "./getWallet"; import { webhookCache } from "./getWebhook"; +import { keypairCache } from "./keypair"; export const clearCache = async ( service: (typeof env)["LOG_SERVICES"][0], @@ -13,4 +14,5 @@ export const clearCache = async ( sdkCache.clear(); walletsCache.clear(); accessTokenCache.clear(); + keypairCache.clear(); }; diff --git a/src/utils/cache/keypair.ts b/src/utils/cache/keypair.ts new file mode 100644 index 000000000..e8a6ba86f --- /dev/null +++ b/src/utils/cache/keypair.ts @@ -0,0 +1,20 @@ +import type { Keypairs } from "@prisma/client"; +import { getKeypairByPublicKey } from "../../db/keypair/get"; + +// Cache a public key to the Keypair object, or null if not found. +export const keypairCache = new Map(); + +export const getKeypair = async ({ + publicKey, +}: { + publicKey: string; +}): Promise => { + const cached = keypairCache.get(publicKey); + if (cached) { + return cached; + } + + const keypair = await getKeypairByPublicKey({ publicKey }); + keypairCache.set(publicKey, keypair); + return keypair; +}; diff --git a/src/utils/crypto.ts b/src/utils/crypto.ts index ed9e60429..7b9052dd4 100644 --- a/src/utils/crypto.ts +++ b/src/utils/crypto.ts @@ -1,10 +1,20 @@ -import crypto from "crypto-js"; +import crypto from "crypto"; +import CryptoJS from "crypto-js"; import { env } from "./env"; export const encrypt = (data: string): string => { - return crypto.AES.encrypt(data, env.ENCRYPTION_PASSWORD).toString(); + return CryptoJS.AES.encrypt(data, env.ENCRYPTION_PASSWORD).toString(); }; export const decrypt = (data: string, password: string) => { - return crypto.AES.decrypt(data, password).toString(crypto.enc.Utf8); + return CryptoJS.AES.decrypt(data, password).toString(CryptoJS.enc.Utf8); +}; + +export const isWellFormedPublicKey = (key: string) => { + try { + crypto.createPublicKey(key); + return true; + } catch (e) { + return false; + } }; diff --git a/src/utils/env.ts b/src/utils/env.ts index 05e538c5d..600cc997b 100644 --- a/src/utils/env.ts +++ b/src/utils/env.ts @@ -3,7 +3,8 @@ import * as dotenv from "dotenv"; import type { ZodError } from "zod"; import { z } from "zod"; -dotenv.config(); +const path = process.env.NODE_ENV === "test" ? ".env.test" : ".env"; +dotenv.config({ path }); export const JsonSchema = z.string().refine( (value) => { @@ -14,22 +15,14 @@ export const JsonSchema = z.string().refine( return false; } }, - { message: "Not a valid JSON string" }, + { message: "Invalid JSON string" }, ); export const UrlSchema = z .string() .refine( (value) => value.startsWith("http://") || value.startsWith("https://"), - { message: "Not a valid URL" }, - ); - -export const FilePathSchema = z - .string() - .refine( - (value) => - value.startsWith("./") || value.startsWith("/") || value.includes("."), - { message: "Not a valid file path" }, + { message: "Invalid URL" }, ); const boolSchema = (defaultBool: "true" | "false") => @@ -73,6 +66,7 @@ export const env = createEnv({ .default("https://c.thirdweb.com/event"), SDK_BATCH_TIME_LIMIT: z.coerce.number().default(0), SDK_BATCH_SIZE_LIMIT: z.coerce.number().default(100), + ENABLE_KEYPAIR_AUTH: boolSchema("false"), }, clientPrefix: "NEVER_USED", client: {}, @@ -93,6 +87,7 @@ export const env = createEnv({ CLIENT_ANALYTICS_URL: process.env.CLIENT_ANALYTICS_URL, SDK_BATCH_TIME_LIMIT: process.env.SDK_BATCH_TIME_LIMIT, SDK_BATCH_SIZE_LIMIT: process.env.SDK_BATCH_SIZE_LIMIT, + ENABLE_KEYPAIR_AUTH: process.env.ENABLE_KEYPAIR_AUTH, }, onValidationError: (error: ZodError) => { console.error( diff --git a/src/worker/tasks/processTx.ts b/src/worker/tasks/processTx.ts index 80ac0eca3..65cc7cb1f 100644 --- a/src/worker/tasks/processTx.ts +++ b/src/worker/tasks/processTx.ts @@ -35,6 +35,7 @@ import { } from "../../utils/webhook"; import { randomNonce } from "../utils/nonce"; import { getWithdrawValue } from "../utils/withdraw"; +import { getContractAddress } from "ethers/lib/utils"; type RpcResponseData = { tx: Transactions; @@ -170,11 +171,27 @@ export const processTx = async () => { ...gasOverrides, }); - // TODO: We need to target specific cases - // Bump gas limit to avoid occasional out of gas errors - txRequest.gasLimit = txRequest.gasLimit - ? BigNumber.from(txRequest.gasLimit).mul(120).div(100) - : undefined; + // Gas limit override + if (tx.gasLimit) { + txRequest.gasLimit = BigNumber.from(tx.gasLimit); + } else { + // TODO: We need to target specific cases + // Bump gas limit to avoid occasional out of gas errors + txRequest.gasLimit = txRequest.gasLimit + ? BigNumber.from(txRequest.gasLimit).mul(120).div(100) + : undefined; + } + + // Gas price overrides + if (tx.maxFeePerGas) { + txRequest.maxFeePerGas = BigNumber.from(tx.maxFeePerGas); + } + + if (tx.maxPriorityFeePerGas) { + txRequest.maxPriorityFeePerGas = BigNumber.from( + tx.maxPriorityFeePerGas, + ); + } const signature = await signer.signTransaction(txRequest); const rpcRequest = { @@ -288,6 +305,16 @@ export const processTx = async () => { if (rpcResponse.result) { // Transaction was successful. const transactionHash = rpcResponse.result; + let contractAddress: string | undefined; + if ( + tx.extension === "deploy-published" && + tx.functionName === "deploy" + ) { + contractAddress = getContractAddress({ + from: txRequest.from!, + nonce: BigNumber.from(txRequest.nonce!), + }); + } await updateTx({ pgtx, queueId: tx.id, @@ -297,6 +324,7 @@ export const processTx = async () => { res: txRequest, sentAt: new Date(), sentAtBlockNumber: sentAtBlockNumber!, + deployedContractAddress: contractAddress, }, }); reportUsageForQueueIds.push({ @@ -366,6 +394,24 @@ export const processTx = async () => { nonce, }, ); + + // Temporary fix untill SDK allows us to do this + if (tx.gasLimit) { + unsignedOp.callGasLimit = BigNumber.from(tx.gasLimit); + unsignedOp.paymasterAndData = "0x"; + const DUMMY_SIGNATURE = + "0xfffffffffffffffffffffffffffffff0000000000000000000000000000000007aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1c"; + unsignedOp.signature = DUMMY_SIGNATURE; + const paymasterResult = + await signer.smartAccountAPI.paymasterAPI.getPaymasterAndData( + unsignedOp, + ); + const paymasterAndData = paymasterResult.paymasterAndData; + if (paymasterAndData && paymasterAndData !== "0x") { + unsignedOp.paymasterAndData = paymasterAndData; + } + } + const userOp = await signer.smartAccountAPI.signUserOp(unsignedOp); const userOpHash = await signer.smartAccountAPI.getUserOpHash( userOp, diff --git a/src/worker/tasks/retryTx.ts b/src/worker/tasks/retryTx.ts index 7b681a462..95990cece 100644 --- a/src/worker/tasks/retryTx.ts +++ b/src/worker/tasks/retryTx.ts @@ -4,16 +4,13 @@ import { prisma } from "../../db/client"; import { getTxToRetry } from "../../db/transactions/getTxToRetry"; import { updateTx } from "../../db/transactions/updateTx"; import { TransactionStatus } from "../../server/schemas/transaction"; +import { cancelTransactionAndUpdate } from "../../server/utils/transaction"; import { getConfig } from "../../utils/cache/getConfig"; import { getSdk } from "../../utils/cache/getSdk"; import { parseTxError } from "../../utils/errors"; import { getGasSettingsForRetry } from "../../utils/gas"; import { logger } from "../../utils/logger"; -import { - ReportUsageParams, - UsageEventTxActionEnum, - reportUsage, -} from "../../utils/usage"; +import { UsageEventTxActionEnum, reportUsage } from "../../utils/usage"; export const retryTx = async () => { try { @@ -26,13 +23,12 @@ export const retryTx = async () => { } const config = await getConfig(); - const reportUsageForQueueIds: ReportUsageParams[] = []; const sdk = await getSdk({ chainId: parseInt(tx.chainId!), walletAddress: tx.fromAddress!, }); const provider = sdk.getProvider() as StaticJsonRpcBatchProvider; - const blockNumber = await sdk.getProvider().getBlockNumber(); + const blockNumber = await provider.getBlockNumber(); if ( blockNumber - tx.sentAtBlockNumber! <= @@ -58,8 +54,7 @@ export const retryTx = async () => { }); const gasOverrides = await getGasSettingsForRetry(tx, provider); - let res: ethers.providers.TransactionResponse; - const txRequest = { + const transactionRequest = { to: tx.toAddress!, from: tx.fromAddress!, data: tx.data!, @@ -67,17 +62,28 @@ export const retryTx = async () => { value: tx.value!, ...gasOverrides, }; + + // Send transaction. + let transactionResponse: ethers.providers.TransactionResponse; try { - res = await sdk.getSigner()!.sendTransaction(txRequest); + transactionResponse = await sdk + .getSigner()! + .sendTransaction(transactionRequest); } catch (err: any) { + // The RPC rejected this transaction. logger({ service: "worker", level: "error", queueId: tx.id, - message: `Failed to retry`, + message: "Failed to retry", error: err, }); + // Consume the nonce. + await cancelTransactionAndUpdate({ + queueId: tx.id, + pgtx, + }); await updateTx({ pgtx, queueId: tx.id, @@ -87,21 +93,21 @@ export const retryTx = async () => { }, }); - reportUsageForQueueIds.push({ - input: { - fromAddress: tx.fromAddress || undefined, - toAddress: tx.toAddress || undefined, - value: tx.value || undefined, - chainId: tx.chainId || undefined, - functionName: tx.functionName || undefined, - extension: tx.extension || undefined, - retryCount: tx.retryCount + 1 || 0, - provider: provider.connection.url || undefined, + reportUsage([ + { + input: { + fromAddress: tx.fromAddress || undefined, + toAddress: tx.toAddress || undefined, + value: tx.value || undefined, + chainId: tx.chainId, + functionName: tx.functionName || undefined, + extension: tx.extension || undefined, + retryCount: tx.retryCount + 1, + provider: provider.connection.url, + }, + action: UsageEventTxActionEnum.ErrorTx, }, - action: UsageEventTxActionEnum.ErrorTx, - }); - - reportUsage(reportUsageForQueueIds); + ]); return; } @@ -112,35 +118,35 @@ export const retryTx = async () => { data: { sentAt: new Date(), status: TransactionStatus.Sent, - res: txRequest, - sentAtBlockNumber: await sdk.getProvider().getBlockNumber(), + res: transactionRequest, + sentAtBlockNumber: await provider.getBlockNumber(), retryCount: tx.retryCount + 1, - transactionHash: res.hash, + transactionHash: transactionResponse.hash, }, }); - reportUsageForQueueIds.push({ - input: { - fromAddress: tx.fromAddress || undefined, - toAddress: tx.toAddress || undefined, - value: tx.value || undefined, - chainId: tx.chainId || undefined, - functionName: tx.functionName || undefined, - extension: tx.extension || undefined, - retryCount: tx.retryCount + 1, - transactionHash: res.hash || undefined, - provider: provider.connection.url || undefined, + reportUsage([ + { + input: { + fromAddress: tx.fromAddress || undefined, + toAddress: tx.toAddress || undefined, + value: tx.value || undefined, + chainId: tx.chainId, + functionName: tx.functionName || undefined, + extension: tx.extension || undefined, + retryCount: tx.retryCount + 1, + transactionHash: transactionResponse.hash || undefined, + provider: provider.connection.url, + }, + action: UsageEventTxActionEnum.SendTx, }, - action: UsageEventTxActionEnum.SendTx, - }); - - reportUsage(reportUsageForQueueIds); + ]); logger({ service: "worker", level: "info", queueId: tx.id, - message: `Retried with hash ${res.hash} for nonce ${res.nonce}`, + message: `Retried with hash ${transactionResponse.hash} for nonce ${transactionResponse.nonce}`, }); }, { diff --git a/src/worker/tasks/updateMinedTx.ts b/src/worker/tasks/updateMinedTx.ts index e3cf58a0e..b9a0e472b 100644 --- a/src/worker/tasks/updateMinedTx.ts +++ b/src/worker/tasks/updateMinedTx.ts @@ -7,6 +7,7 @@ import { updateTx } from "../../db/transactions/updateTx"; import { TransactionStatus } from "../../server/schemas/transaction"; import { cancelTransactionAndUpdate } from "../../server/utils/transaction"; import { getSdk } from "../../utils/cache/getSdk"; +import { msSince } from "../../utils/date"; import { logger } from "../../utils/logger"; import { ReportUsageParams, @@ -65,7 +66,7 @@ export const updateMinedTx = async () => { chainId: tx.chainId || undefined, transactionHash: tx.transactionHash || undefined, provider: provider.connection.url || undefined, - msSinceSend: Date.now() - tx.sentAt!.getTime(), + msSinceSend: msSince(tx.sentAt!), }, action: UsageEventTxActionEnum.CancelTx, }); diff --git a/src/worker/tasks/updateMinedUserOps.ts b/src/worker/tasks/updateMinedUserOps.ts index 23b2422cd..fde57d139 100644 --- a/src/worker/tasks/updateMinedUserOps.ts +++ b/src/worker/tasks/updateMinedUserOps.ts @@ -36,12 +36,14 @@ export const updateMinedUserOps = async () => { }); const signer = sdk.getSigner() as ERC4337EthersSigner; - const txHash = await signer.smartAccountAPI.getUserOpReceipt( - userOp.userOpHash!, - 3000, - ); + const userOpReceipt = + await signer.smartAccountAPI.getUserOpReceipt( + signer.httpRpcClient, + userOp.userOpHash!, + 3000, + ); - if (!txHash) { + if (!userOpReceipt) { // If no receipt was received, return undefined to filter out tx return undefined; } @@ -49,10 +51,12 @@ export const updateMinedUserOps = async () => { chainId: parseInt(userOp.chainId!), }); - const tx = await signer.provider!.getTransaction(txHash); + const tx = await signer.provider!.getTransaction( + userOpReceipt.transactionHash, + ); const txReceipt = await _sdk .getProvider() - .getTransactionReceipt(txHash); + .getTransactionReceipt(tx.hash); const minedAt = new Date( ( await getBlock({ @@ -67,7 +71,7 @@ export const updateMinedUserOps = async () => { blockNumber: tx.blockNumber!, minedAt, onChainTxStatus: txReceipt.status, - transactionHash: txHash, + transactionHash: txReceipt.transactionHash, transactionType: tx.type, gasLimit: tx.gasLimit.toString(), maxFeePerGas: tx.maxFeePerGas?.toString(), diff --git a/yarn.lock b/yarn.lock index c6f3f481b..55272eed3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -767,7 +767,7 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@blocto/sdk@^0.5.4": +"@blocto/sdk@0.5.5": version "0.5.5" resolved "https://registry.yarnpkg.com/@blocto/sdk/-/sdk-0.5.5.tgz#807b9eaeee924c3eb0c5517c6b32891025f1f6b0" integrity sha512-u7bbAYmYDCf0QWvXleVOTeGFRbo8evT3uacsLJ6dv01HspmLDKZWjFyu7i3ARebJTpenHvwM78XHV7KTvBqTRg== @@ -777,17 +777,7 @@ eip1193-provider "^1.0.1" js-sha3 "^0.8.0" -"@chainlink/contracts@^0.6.1": - version "0.6.1" - resolved "https://registry.yarnpkg.com/@chainlink/contracts/-/contracts-0.6.1.tgz#8842b57e755793cbdbcbc45277fb5d179c993e19" - integrity sha512-EuwijGexttw0UjfrW+HygwhQIrGAbqpf1ue28R55HhWMHBzphEH0PhWm8DQmFfj5OZNy8Io66N4L0nStkZ3QKQ== - dependencies: - "@eth-optimism/contracts" "^0.5.21" - "@openzeppelin/contracts" "~4.3.3" - "@openzeppelin/contracts-upgradeable" "^4.7.3" - "@openzeppelin/contracts-v0.7" "npm:@openzeppelin/contracts@v3.4.2" - -"@coinbase/wallet-sdk@3.7.2": +"@coinbase/wallet-sdk@3.7.2", "@coinbase/wallet-sdk@^3.7.2": version "3.7.2" resolved "https://registry.yarnpkg.com/@coinbase/wallet-sdk/-/wallet-sdk-3.7.2.tgz#7a89bd9e3a06a1f26d4480d8642af33fb0c7e3aa" integrity sha512-lIGvXMsgpsQWci/XOMQIJ2nIZ8JUy/L+bvC0wkRaYarr0YylwpXrJ2gRM3hCXPS477pkyO7N/kSiAoRgEXUdJQ== @@ -810,29 +800,6 @@ stream-browserify "^3.0.0" util "^0.12.4" -"@coinbase/wallet-sdk@^3.7.1": - version "3.7.1" - resolved "https://registry.yarnpkg.com/@coinbase/wallet-sdk/-/wallet-sdk-3.7.1.tgz#44b3b7a925ff5cc974e4cbf7a44199ffdcf03541" - integrity sha512-LjyoDCB+7p0waQXfK+fUgcAs3Ezk6S6e+LYaoFjpJ6c9VTop3NyZF40Pi7df4z7QJohCwzuIDjz0Rhtig6Y7Pg== - dependencies: - "@metamask/safe-event-emitter" "2.0.0" - "@solana/web3.js" "^1.70.1" - bind-decorator "^1.0.11" - bn.js "^5.1.1" - buffer "^6.0.3" - clsx "^1.1.0" - eth-block-tracker "6.1.0" - eth-json-rpc-filters "5.1.0" - eth-rpc-errors "4.0.2" - json-rpc-engine "6.1.0" - keccak "^3.0.1" - preact "^10.5.9" - qs "^6.10.3" - rxjs "^6.6.3" - sha.js "^2.4.11" - stream-browserify "^3.0.0" - util "^0.12.4" - "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -984,6 +951,11 @@ resolved "https://registry.yarnpkg.com/@eth-optimism/contracts-bedrock/-/contracts-bedrock-0.17.1.tgz#729b1dc53ec23d02ea9e68181f994955129f7415" integrity sha512-Hc5peN5PM8kzl9dzqSD5jv6ED3QliO1DF0dXLRJxfrXR7/rmEeyuAYESUwUM0gdJZjkwRYiS5m230BI6bQmnlw== +"@eth-optimism/contracts-bedrock@0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@eth-optimism/contracts-bedrock/-/contracts-bedrock-0.17.2.tgz#501ae26c7fe4ef4edf6420c384f76677e85f62ae" + integrity sha512-YVwPHpBZgFwFX9qY8+iToVAAH7mSnVIVmih+YfHhqjAhlLvLZfYjvj+hRNgcB9eRyl1SOOB0jevp4JOOV1v2BA== + "@eth-optimism/contracts@0.6.0": version "0.6.0" resolved "https://registry.yarnpkg.com/@eth-optimism/contracts/-/contracts-0.6.0.tgz#15ae76222a9b4d958a550cafb1960923af613a31" @@ -993,15 +965,6 @@ "@ethersproject/abstract-provider" "^5.7.0" "@ethersproject/abstract-signer" "^5.7.0" -"@eth-optimism/contracts@^0.5.21": - version "0.5.40" - resolved "https://registry.yarnpkg.com/@eth-optimism/contracts/-/contracts-0.5.40.tgz#d13a04a15ea947a69055e6fc74d87e215d4c936a" - integrity sha512-MrzV0nvsymfO/fursTB7m/KunkPsCndltVgfdHaT1Aj5Vi6R/doKIGGkOofHX+8B6VMZpuZosKCMQ5lQuqjt8w== - dependencies: - "@eth-optimism/core-utils" "0.12.0" - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@eth-optimism/core-utils@0.12.0": version "0.12.0" resolved "https://registry.yarnpkg.com/@eth-optimism/core-utils/-/core-utils-0.12.0.tgz#6337e4599a34de23f8eceb20378de2a2de82b0ea" @@ -1044,10 +1007,30 @@ ethers "^5.7.2" node-fetch "^2.6.7" -"@eth-optimism/sdk@3.2.2", "@eth-optimism/sdk@^3.2.1": - version "3.2.2" - resolved "https://registry.yarnpkg.com/@eth-optimism/sdk/-/sdk-3.2.2.tgz#732c2d6fde96a25303b3c5b39b3b3ed1f913d9aa" - integrity sha512-P8YXAlh2lun0KZlwrw4FqmK4kNIoOOzI816XXhfkW3nMVADGRAru3TKSM74MgmEuyGiHrA9EoPRq1WLqUX4B0w== +"@eth-optimism/core-utils@0.13.2": + version "0.13.2" + resolved "https://registry.yarnpkg.com/@eth-optimism/core-utils/-/core-utils-0.13.2.tgz#c0187c3abf6d86dad039edf04ff81299253214fe" + integrity sha512-u7TOKm1RxH1V5zw7dHmfy91bOuEAZU68LT/9vJPkuWEjaTl+BgvPDRDTurjzclHzN0GbWdcpOqPZg4ftjkJGaw== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/contracts" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/web" "^5.7.1" + chai "^4.3.10" + ethers "^5.7.2" + node-fetch "^2.6.7" + +"@eth-optimism/sdk@3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@eth-optimism/sdk/-/sdk-3.2.3.tgz#42aa99ed388355ec85b5cf68589aaa15f0c6c7f6" + integrity sha512-e3XQTbbU+HTzsEv/VIsJpZifK6YZVlzEtF6tj/Vz/VIEDCjZk5JPcnCQOMVcs9ICI4EJyyur+y/+RU7fPa6qtg== dependencies: "@eth-optimism/contracts" "0.6.0" "@eth-optimism/contracts-bedrock" "0.17.1" @@ -1057,6 +1040,19 @@ rlp "^2.2.7" semver "^7.6.0" +"@eth-optimism/sdk@3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@eth-optimism/sdk/-/sdk-3.3.0.tgz#c7a3af4e7b5ab541be0c4e2acd02f2bf84bfb2e5" + integrity sha512-0Wt9roWe3itdzp08caCQLoFqhmT47ssquKAzBe7yXI6saVL+f2vWl6VgEaq0aYe2FsWvD9L0tSAJHLx1FiquNw== + dependencies: + "@eth-optimism/contracts" "0.6.0" + "@eth-optimism/contracts-bedrock" "0.17.2" + "@eth-optimism/core-utils" "0.13.2" + lodash "^4.17.21" + merkletreejs "^0.3.11" + rlp "^2.2.7" + semver "^7.6.0" + "@ethereumjs/common@^2.4.0": version "2.6.5" resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.5.tgz#0a75a22a046272579d91919cb12d84f2756e8d30" @@ -1764,7 +1760,7 @@ cookie "^0.5.0" fastify-plugin "^4.0.0" -"@fastify/cookie@^9.1.0": +"@fastify/cookie@^9.3.1": version "9.3.1" resolved "https://registry.yarnpkg.com/@fastify/cookie/-/cookie-9.3.1.tgz#48b89a356a23860c666e2fe522a084cc5c943d33" integrity sha512-h1NAEhB266+ZbZ0e9qUE6NnNR07i7DnNXWG9VbbZ8uC6O/hxHpl+Zoe5sw1yfdZ2U6XhToUGDnzQtWJdCaPwfg== @@ -1855,6 +1851,13 @@ dependencies: google-gax "^3.0.1" +"@google-cloud/kms@4.2.0": + version "4.2.0" + resolved "https://registry.yarnpkg.com/@google-cloud/kms/-/kms-4.2.0.tgz#7d8c1c1c7f906bdf6b5504518967aa9834a31375" + integrity sha512-EIFxBL2XbpRkW6TmmYNU3xmpbaDw49uD57q6/rRQMkWPENvPTrlonQeTBeXV1I18GMToVliQOwKs001Mzo7Dwg== + dependencies: + google-gax "^4.0.3" + "@google-cloud/kms@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@google-cloud/kms/-/kms-4.0.0.tgz#450f9b6b881c311ea640672ad08134528b75adb8" @@ -2246,7 +2249,7 @@ tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" -"@metamask/eth-sig-util@^4.0.0": +"@metamask/eth-sig-util@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz#3ad61f6ea9ad73ba5b19db780d40d9aae5157088" integrity sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ== @@ -2377,16 +2380,11 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== -"@noble/hashes@1.4.0": +"@noble/hashes@1.4.0", "@noble/hashes@^1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== -"@noble/hashes@^1.3.2": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" - integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== - "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -2408,12 +2406,7 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@openzeppelin/contracts-upgradeable@4.7.3": - version "4.7.3" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.7.3.tgz#f1d606e2827d409053f3e908ba4eb8adb1dd6995" - integrity sha512-+wuegAMaLcZnLCJIvrVUDzA9z/Wp93f0Dla/4jJvIhijRrPabjQbZe6fWiECLaJyfn5ci9fqf9vTw3xpQOad2A== - -"@openzeppelin/contracts-upgradeable@^4.4.2", "@openzeppelin/contracts-upgradeable@^4.7.3": +"@openzeppelin/contracts-upgradeable@^4.4.2": version "4.9.3" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.3.tgz#ff17a80fb945f5102571f8efecb5ce5915cc4811" integrity sha512-jjaHAVRMrE4UuZNfDwjlLGDxTHWIOwTJS2ldnc278a0gevfXfPr8hxKEVBGFBE96kl2G3VHDZhUimw/+G3TG2A== @@ -2423,26 +2416,11 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.6.tgz#38b21708a719da647de4bb0e4802ee235a0d24df" integrity sha512-m4iHazOsOCv1DgM7eD7GupTJ+NFVujRZt1wzddDPSVGpWdKq1SKkla5htKG7+IS4d2XOCtzkUNwRZ7Vq5aEUMA== -"@openzeppelin/contracts-v0.7@npm:@openzeppelin/contracts@v3.4.2": - version "3.4.2" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.2.tgz#d81f786fda2871d1eb8a8c5a73e455753ba53527" - integrity sha512-z0zMCjyhhp4y7XKAcDAi3Vgms4T2PstwBdahiO0+9NaGICQKjynK3wduSRplTgk4LXmoO1yfDGO5RbjKYxtuxA== - -"@openzeppelin/contracts@4.7.3": - version "4.7.3" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.7.3.tgz#939534757a81f8d69cc854c7692805684ff3111e" - integrity sha512-dGRS0agJzu8ybo44pCIf3xBaPQN/65AIXNgK8+4gzKd5kbvlqyxryUYVLJv7fK98Seyd2hDZzVEHSWAh0Bt1Yw== - "@openzeppelin/contracts@^4.9.3": version "4.9.6" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.6.tgz#2a880a24eb19b4f8b25adc2a5095f2aa27f39677" integrity sha512-xSmezSupL+y9VkHZJGDoCBpmnB2ogM13ccaYDWqJTfS3dbuHkgjuwDFUmaFauBCboQMGB/S5UqUl2y54X99BmA== -"@openzeppelin/contracts@~4.3.3": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.3.3.tgz#ff6ee919fc2a1abaf72b22814bfb72ed129ec137" - integrity sha512-tDBopO1c98Yk7Cv/PZlHqrvtVjlgK5R4J6jxLwoO7qxK4xqOiZG+zSkIvGFpPZ0ikc3QOED3plgdqjgNTnBc7g== - "@paperxyz/embedded-wallet-service-sdk@^1.2.5": version "1.2.5" resolved "https://registry.yarnpkg.com/@paperxyz/embedded-wallet-service-sdk/-/embedded-wallet-service-sdk-1.2.5.tgz#d635dd0a05d7b8231ca6ca6e692774cb5c791e25" @@ -2454,11 +2432,16 @@ "@ethersproject/providers" "^5.7.2" "@paperxyz/sdk-common-utilities" "*" -"@paperxyz/sdk-common-utilities@*", "@paperxyz/sdk-common-utilities@^0.1.0": +"@paperxyz/sdk-common-utilities@*": version "0.1.0" resolved "https://registry.yarnpkg.com/@paperxyz/sdk-common-utilities/-/sdk-common-utilities-0.1.0.tgz#a948ef20d080b63e8bc0caa3ef337177a782f370" integrity sha512-+zE2wp9gI5kjI6yHdrigeqLRDueAFz70v6hUKOT98Nyy4yL8YUR3OvXFAnAyZLXrr0v1uLlDYQdBz0fI2StmGg== +"@paperxyz/sdk-common-utilities@^0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@paperxyz/sdk-common-utilities/-/sdk-common-utilities-0.1.1.tgz#dfddaf8880c82bd665368793ebe4d06a365bede7" + integrity sha512-RefjXB3d5Ub1I3GoIf/mfgTsvmAneWoeQwpmiuXYx1NmmSdbtBxDUk4POtSWUCnvoiJP0Y2frATnYMV30J1b1A== + "@parcel/watcher-android-arm64@2.4.1": version "2.4.1" resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz#c2c19a3c442313ff007d2d7a9c2c1dd3e1c9ca84" @@ -2881,7 +2864,7 @@ semver "^7.3.8" web3-utils "^1.8.1" -"@safe-global/safe-core-sdk@^3.3.4": +"@safe-global/safe-core-sdk@^3.3.5": version "3.3.5" resolved "https://registry.yarnpkg.com/@safe-global/safe-core-sdk/-/safe-core-sdk-3.3.5.tgz#30884639d368a9f50aa5fc96f78de87261ebdab3" integrity sha512-ul+WmpxZOXgDIXrZ6MIHptThYbm0CVV3/rypMQEn4tZLkudh/yXK7EuWBFnx9prR3MePuku51Zcz9fu1vi7sfQ== @@ -3491,88 +3474,77 @@ dependencies: "@tanstack/query-core" "5.28.9" -"@thirdweb-dev/auth@^4.1.47": - version "4.1.47" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/auth/-/auth-4.1.47.tgz#9235d269e9119501f691d5969b962c8cd269a17e" - integrity sha512-nZzW4qmuNmS4HQOPiMovD+8LpLSWNXzdId9upOAuLaSAGMgF983vab6wxRGW9OgMsCVAxX/ZHTujfDIaC2bTYw== +"@thirdweb-dev/auth@^4.1.55": + version "4.1.55" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/auth/-/auth-4.1.55.tgz#bc7e48740e49c73df8751162b1629b9884771566" + integrity sha512-8lqSzZL6y5TCTj24GCaUa8e4j58xnpn4CaNnXpHvmXg7VZxOE+EJS8Kg/vJmKk7LcYCxWo13V+5QXA6nFIhA6Q== dependencies: - "@fastify/cookie" "^9.1.0" - "@thirdweb-dev/wallets" "2.4.25" - cookie "^0.5.0" + "@fastify/cookie" "^9.3.1" + "@thirdweb-dev/wallets" "2.4.33" + cookie "^0.6.0" fastify-type-provider-zod "^1.1.9" uuid "^9.0.1" - zod "^3.22.3" + zod "^3.22.4" -"@thirdweb-dev/chains@0.1.78": - version "0.1.78" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/chains/-/chains-0.1.78.tgz#480e61bfb3822c1d73702385dd9bfd9c2d95faa8" - integrity sha512-zXP+pymo1squvHyvwjtOlHYXDiaEBic0RIrfy/d6oP8Rhy4GIAG79knHD3hvvMDDIA48XkoGl3xyGMTan3skOw== +"@thirdweb-dev/chains@0.1.88": + version "0.1.88" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/chains/-/chains-0.1.88.tgz#7e3ee1f5ac0467be9f7232c4cea24ed7f93d2a65" + integrity sha512-2xRRCW+mDcfYniVHA09fTi8sUV783XyQBuHOMKtZw8PnC+/M8Lw26GBVnsAM7RDECwcPk+aL/rvaLYcNvCiNow== -"@thirdweb-dev/chains@0.1.81": - version "0.1.81" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/chains/-/chains-0.1.81.tgz#7e301f3919b4e2d0dbeaebf75a042afb238e504c" - integrity sha512-EgM0PsCKGCiHAsWGrC4COFSrHeVviQRmI5AjzrdB0Eis3A+5NX41NlNa6TppzeRgeFFteEDdnkrwLeHfzJqKhw== +"@thirdweb-dev/chains@0.1.90": + version "0.1.90" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/chains/-/chains-0.1.90.tgz#ad87e5677caffc34033ba8c4f6a8700cca685d8a" + integrity sha512-0LGUH3vr8VlK05eqGK1bk/qGenU3AzOOJY/o3YFY8LrZcof+Dnj3xGWxXC62laRs4lF0qAGHTve0D/8j3ecvug== + +"@thirdweb-dev/chains@0.1.91-nightly-6961e09a4cec4c276b233285e721dc0505792be5-20240408215531": + version "0.1.91-nightly-6961e09a4cec4c276b233285e721dc0505792be5-20240408215531" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/chains/-/chains-0.1.91-nightly-6961e09a4cec4c276b233285e721dc0505792be5-20240408215531.tgz#90a95c3c31c8e6d27731a752369e6c1f8e09a0f8" + integrity sha512-jIkEhieylZoNwJGWEg6SxLZshyUatutyKMes0rCntv6ImrXMlXk3aQTnxDeeTauXenWe474EsSCqSYoDsmfd+A== "@thirdweb-dev/chains@^0.1.77": version "0.1.77" resolved "https://registry.yarnpkg.com/@thirdweb-dev/chains/-/chains-0.1.77.tgz#7d938a71f27e39666704048840aaaacc1e51e86e" integrity sha512-Sn58vGCAVMUrzkEncgSIl7y1Ee04e8WzQPbL2UEZF6FyWi4bJgS69iZcKJyIJH7iczoChJ8wCZHHMzBtY8pJZQ== -"@thirdweb-dev/contracts-js@1.3.16": - version "1.3.16" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/contracts-js/-/contracts-js-1.3.16.tgz#264727b40b0f320c01eefcb4295e89c9e9947002" - integrity sha512-EpLcD5mdm8b+tvSO7gD9cxSAqjLRr7ygktMp4Pe7Wvobl5ffq8O95futxdVsYc5pyciPZYr8apHUJFYMDlaTqA== +"@thirdweb-dev/contracts-js@1.3.20": + version "1.3.20" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/contracts-js/-/contracts-js-1.3.20.tgz#0325e0c9cadd8944eb1ab095f8afbb1b7d349731" + integrity sha512-Gx+XFrFhtGo5swDknqCfzDKMRc+EwgfFmC1AsW2jGvzSLo0egBbz1NA+WvDxbLQJAi6rhSuomuX99tYN3nVzyw== dependencies: - "@thirdweb-dev/contracts" "3.10.3" + "@thirdweb-dev/contracts" "3.13.0" -"@thirdweb-dev/contracts-js@1.3.18": - version "1.3.18" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/contracts-js/-/contracts-js-1.3.18.tgz#b6745ce0a0a00c8665fa20251fc3bb803af82c9f" - integrity sha512-qQNnHyweDHjVxLDR9yBiWkH0tlxzW9COcydeOBC9IPMCDypZFhCO3c0m4QC2WCrC7EJxCWh73Q+hogFCv2Ct+Q== +"@thirdweb-dev/contracts-js@1.3.21": + version "1.3.21" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/contracts-js/-/contracts-js-1.3.21.tgz#c781cc67bf454757fc87b8741de96e55808527a8" + integrity sha512-mbJJ36xV7C9Zc7gzdaLxQqfkIVFwFYmN7P26JEPHCGtKqxjxejNc+tl/4G4FcjzckLaFBZC6oN6/+4HhgEh4XA== dependencies: - "@thirdweb-dev/contracts" "3.12.1" + "@thirdweb-dev/contracts" "3.13.0" -"@thirdweb-dev/contracts@3.10.3": - version "3.10.3" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/contracts/-/contracts-3.10.3.tgz#985b890b2bac051bc69a9108ac9e9df0fd37a1c1" - integrity sha512-wSVNaEoosn0AgUtnxlvv7rgK+3EUMzJm2ZasofPgJgqGS3gYH5nDBmK29VMquA2BLc38OAPyYMWc/iQCiCikMg== - dependencies: - "@chainlink/contracts" "^0.6.1" - "@openzeppelin/contracts" "4.7.3" - "@openzeppelin/contracts-upgradeable" "4.7.3" - "@thirdweb-dev/dynamic-contracts" "^1.1.2" - erc721a-upgradeable "^3.3.0" - -"@thirdweb-dev/contracts@3.12.1": - version "3.12.1" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/contracts/-/contracts-3.12.1.tgz#5c2debf4926e459ca39efebbf7fc50908a943b5d" - integrity sha512-FqgLO8ZQ31dwYMoDbZ+OXpEZbwx5bi8Ot9WQDdYohcTQTjM12tMXiBuobK5Iwpjqf2Q+GrN45IHEMh9zL0Wqkw== +"@thirdweb-dev/contracts@3.13.0": + version "3.13.0" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/contracts/-/contracts-3.13.0.tgz#7139c1b25d77eb58de24e89d7c2f84c4235ed386" + integrity sha512-v2ol+Wqf/W/7LGaP3xgStns6iUDB492b+rxUvkNPL89uGqj4Y+dJHdt0BfLF+Lm4IdWVXvxAintbF9uIoZCbJA== dependencies: "@openzeppelin/contracts" "^4.9.3" "@openzeppelin/contracts-upgradeable" "^4.9.3" "@thirdweb-dev/dynamic-contracts" "^1.2.4" erc721a-upgradeable "^3.3.0" -"@thirdweb-dev/crypto@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/crypto/-/crypto-0.2.1.tgz#7643c91c9d87e4d51a77163b87f6bff547e9506c" - integrity sha512-SYEkdtdhTOAcgGklqPrKgyIftA2x0WBTtpAEyJBTLCL1z+2IKvExWZyZn3Mx2cZ8skO3iAfGzC4Si2ORWBcS2g== +"@thirdweb-dev/crypto@0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/crypto/-/crypto-0.2.4.tgz#e70cb83fef0446a8c9139c263e07fddfb97b8922" + integrity sha512-26kvfv9TciNPXWzNYzOqXA4NQyv2LnF7iiZybkuZUf/QquB00p6ZvcA4/ymN5PZlTXxgLYyGUnzQF5MOs067eA== dependencies: - "@noble/hashes" "^1.3.2" - js-sha3 "^0.9.2" + "@noble/hashes" "^1.4.0" + js-sha3 "^0.9.3" -"@thirdweb-dev/crypto@0.2.2": - version "0.2.2" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/crypto/-/crypto-0.2.2.tgz#455c7564610a1eb4597ae1d02c0ce3d722072709" - integrity sha512-jOwHtdViJYZ5015F3xZvwmnFZLrgTx2RkE7bAiG/N83f5TduwQBM3PAPTbW3aBOECaoSrbmgj/lQEOv7543z3Q== +"@thirdweb-dev/crypto@0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/crypto/-/crypto-0.2.5.tgz#a2f06d35570f4158f366191bfff1372efe4e7fe3" + integrity sha512-qcGNeZAJ4a4w/XqYNqstUZpgWv7LynRlhiGIh5IBvEW1phsaAKt3AgehR4QsRfF4DAbcw+/0OsB7+alk9SciJQ== dependencies: - "@noble/hashes" "^1.3.2" - js-sha3 "^0.9.2" - -"@thirdweb-dev/dynamic-contracts@^1.1.2": - version "1.1.4" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/dynamic-contracts/-/dynamic-contracts-1.1.4.tgz#f14de117bad647d0f32073325627f4b31963446f" - integrity sha512-uvZBvcbrJH9IzGkQgaJGsKrRgKh3PcRtrbegk62aGEmv1+vlNakcbaVlOiNC8jHpc/S2pZ29CmuKZntl1cEF8Q== + "@noble/hashes" "^1.4.0" + js-sha3 "^0.9.3" "@thirdweb-dev/dynamic-contracts@^1.2.4": version "1.2.5" @@ -3584,73 +3556,96 @@ resolved "https://registry.yarnpkg.com/@thirdweb-dev/generated-abis/-/generated-abis-0.0.1.tgz#0d788d6aff0ac08f11e9eeb9ae4c8321845272a8" integrity sha512-vO9/3lSLO8smyyH1QVeYravSTzFwV1nf1C/Im1NBDPdH8//YvcbhtETGGiNfHWpyCvSi0vRYwvf+/7FKdwpDGQ== -"@thirdweb-dev/merkletree@0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/merkletree/-/merkletree-0.2.1.tgz#1604e238a921fe520520e18b63312ca049376707" - integrity sha512-NQEo+KlwQFWr0z4+OlD5WJ9GZEFOrVufvjG2zcn2eylFZacJq5GvRz04Yan9eMR844M7LNx5godA5B7DAinqKg== +"@thirdweb-dev/merkletree@0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/merkletree/-/merkletree-0.2.4.tgz#bf4ebd81fe4dc0e5d9144cc6d24626be5931b224" + integrity sha512-Z1CHARMhPX9i6YRSqsRlwuBsINrAmwq4KQzeX6ZIQYuUOwYfaH7Ll4mnBNs7kVSgTgUHNO0hQCvjzNE1aDD0Gw== dependencies: - "@thirdweb-dev/crypto" "0.2.1" + "@thirdweb-dev/crypto" "0.2.4" buffer "^6.0.3" buffer-reverse "^1.0.1" treeify "^1.1.0" -"@thirdweb-dev/merkletree@0.2.2": - version "0.2.2" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/merkletree/-/merkletree-0.2.2.tgz#179faa2cbfaaab0a8dfc2b4fb9601a4ec87f60f8" - integrity sha512-cOEU6ga8+Lyk3b/XsI0h40ljxcTyommQhA38eAWXxUYV1wxH/g7Mry3OOHyY1HCBC2R2MXykCdiFuaoUsQB6Pw== +"@thirdweb-dev/merkletree@0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/merkletree/-/merkletree-0.2.5.tgz#4eaf5ca10d22c375211dfaa7c39744d5c4ac799b" + integrity sha512-0l2MtqpX75LsVpfWrtZ0xTP1lHrecqj1KCioyqRy3cj43gq81EttvMMWoAbYIC6QSBbitUiMrK+INUUGSFQkEg== dependencies: - "@thirdweb-dev/crypto" "0.2.2" buffer "^6.0.3" buffer-reverse "^1.0.1" treeify "^1.1.0" -"@thirdweb-dev/sdk@4.0.42": - version "4.0.42" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/sdk/-/sdk-4.0.42.tgz#55d9968351c341fa710478add91b0a6f1b2e1672" - integrity sha512-LoJyM4iUbasWCC5C7XtHYqdr1GkqQJap0jgmf9IrPhHPZqZnWc209/TXtmL4FA1mBgPXSvLJpjimoJxsle9oog== +"@thirdweb-dev/sdk@4.0.57": + version "4.0.57" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/sdk/-/sdk-4.0.57.tgz#8acbdf13acb29eb8dff03e59977373c396103e47" + integrity sha512-qy1cjsmUTpB1thBGuqFve7OLhDrczCHf89u/7x84Kty0YAP46o4F9sOlAfQeGhpdT44E3dic4fYQpYqShV2tfA== dependencies: - "@eth-optimism/sdk" "^3.2.1" - "@thirdweb-dev/chains" "0.1.78" - "@thirdweb-dev/contracts-js" "1.3.16" - "@thirdweb-dev/crypto" "0.2.1" + "@eth-optimism/sdk" "3.2.3" + "@thirdweb-dev/chains" "0.1.88" + "@thirdweb-dev/contracts-js" "1.3.20" + "@thirdweb-dev/crypto" "0.2.4" "@thirdweb-dev/generated-abis" "0.0.1" - "@thirdweb-dev/merkletree" "0.2.1" - "@thirdweb-dev/storage" "2.0.10" - abitype "^0.2.5" - bn.js "^5.2.1" + "@thirdweb-dev/merkletree" "0.2.4" + "@thirdweb-dev/storage" "2.0.13" + abitype "1.0.0" + bn.js "5.2.1" bs58 "^5.0.0" buffer "^6.0.3" eventemitter3 "^5.0.1" fast-deep-equal "^3.1.3" - tiny-invariant "^1.2.0" + tiny-invariant "^1.3.3" tweetnacl "^1.0.3" uuid "^9.0.1" - yaml "^2.3.4" - zod "^3.22.3" - -"@thirdweb-dev/sdk@4.0.49", "@thirdweb-dev/sdk@^4.0.49": - version "4.0.49" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/sdk/-/sdk-4.0.49.tgz#fbddf5e342bfff5de2c268265d297519dfdacdd1" - integrity sha512-q7aanIgHuIo9V9K8y/13bFTW4fnlaTp5YwAfIAvlPebZFLTvmtiUFHXnaYYZ3pKu1nhR1jPwNpAf01o+/fEfPw== - dependencies: - "@eth-optimism/sdk" "3.2.2" - "@thirdweb-dev/chains" "0.1.81" - "@thirdweb-dev/contracts-js" "1.3.18" - "@thirdweb-dev/crypto" "0.2.2" + yaml "^2.4.1" + zod "^3.22.4" + +"@thirdweb-dev/sdk@4.0.60-nightly-6961e09a4cec4c276b233285e721dc0505792be5-20240408215531": + version "4.0.60-nightly-6961e09a4cec4c276b233285e721dc0505792be5-20240408215531" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/sdk/-/sdk-4.0.60-nightly-6961e09a4cec4c276b233285e721dc0505792be5-20240408215531.tgz#d3441c5a62fc7d8cc10a69f031b5d99bf2835b18" + integrity sha512-M7O+oT27bcNPhhsYVDukCy+qlP4yJ7tCJZ8i555ZiH3uux5fthwip1E411U4xcu9qxI7lHBQxIdY4nKiBRdapA== + dependencies: + "@eth-optimism/sdk" "3.3.0" + "@thirdweb-dev/chains" "0.1.91-nightly-6961e09a4cec4c276b233285e721dc0505792be5-20240408215531" + "@thirdweb-dev/contracts-js" "1.3.21" + "@thirdweb-dev/crypto" "0.2.5" "@thirdweb-dev/generated-abis" "0.0.1" - "@thirdweb-dev/merkletree" "0.2.2" - "@thirdweb-dev/storage" "2.0.11" - abitype "^0.2.5" - bn.js "^5.2.1" + "@thirdweb-dev/merkletree" "0.2.5" + "@thirdweb-dev/storage" "2.0.14" + abitype "1.0.0" + bn.js "5.2.1" bs58 "^5.0.0" buffer "^6.0.3" eventemitter3 "^5.0.1" fast-deep-equal "^3.1.3" - tiny-invariant "^1.2.0" + tiny-invariant "^1.3.3" tweetnacl "^1.0.3" uuid "^9.0.1" - yaml "^2.3.4" - zod "^3.22.3" + yaml "^2.4.1" + zod "^3.22.4" + +"@thirdweb-dev/sdk@^4.0.59": + version "4.0.59" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/sdk/-/sdk-4.0.59.tgz#a84d69a3bf9b253a1a7c2e3f892790c5dcdec91d" + integrity sha512-8krRRCxEYd43DBhCKs47rCmvAr6JA7hGX+4LSn8wLFWp8MfE1MWEu8IjRsVW8r89+3kowkWdP71c7RXD5++mZQ== + dependencies: + "@eth-optimism/sdk" "3.3.0" + "@thirdweb-dev/chains" "0.1.90" + "@thirdweb-dev/contracts-js" "1.3.21" + "@thirdweb-dev/crypto" "0.2.5" + "@thirdweb-dev/generated-abis" "0.0.1" + "@thirdweb-dev/merkletree" "0.2.5" + "@thirdweb-dev/storage" "2.0.14" + abitype "1.0.0" + bn.js "5.2.1" + bs58 "^5.0.0" + buffer "^6.0.3" + eventemitter3 "^5.0.1" + fast-deep-equal "^3.1.3" + tiny-invariant "^1.3.3" + tweetnacl "^1.0.3" + uuid "^9.0.1" + yaml "^2.4.1" + zod "^3.22.4" "@thirdweb-dev/service-utils@0.4.17": version "0.4.17" @@ -3660,99 +3655,99 @@ aws4fetch "^1.0.17" zod "^3.22.3" -"@thirdweb-dev/storage@2.0.10": - version "2.0.10" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/storage/-/storage-2.0.10.tgz#d9e06692b0cb37b3ff2480a6f3ec1133edf5e852" - integrity sha512-i7JrggQzlU97bHdGQ6cOhx1ojYUFyFsfc5MLT47pfCQxeFlUtGmWYNZ09mPPQoCgyoxFNJm5I5QLhnMrNMJtIQ== +"@thirdweb-dev/storage@2.0.13": + version "2.0.13" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/storage/-/storage-2.0.13.tgz#132bccedf329106cd58059c9118244485e1bb40e" + integrity sha512-m+q7RrI7c7G3XC/tmgdY23mAaYbLAIQN83ySpXSe/3Rrybg20EYofcvHVoMkRXSm5ojJvmwfE4SxiZfpsSsTHw== dependencies: - "@thirdweb-dev/crypto" "0.2.1" + "@thirdweb-dev/crypto" "0.2.4" cid-tool "^3.0.0" form-data "^4.0.0" uuid "^9.0.1" -"@thirdweb-dev/storage@2.0.11": - version "2.0.11" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/storage/-/storage-2.0.11.tgz#87d3ae5eaf37471741a595a56dd7e1ab44bf6f99" - integrity sha512-gCe/Q6n7RATKz8tHI0fQL8u5u08MGakCh76ROmHAPEBzMUCEJFIO9278na7l3uWOJignQ5Ym5nf0zcIutuF7HQ== +"@thirdweb-dev/storage@2.0.14": + version "2.0.14" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/storage/-/storage-2.0.14.tgz#366d059d9f7feb17609348bcbdb7b81eabfdef67" + integrity sha512-Ipbg6sZbh/QSh2IjjYWO5MFo5SiB3TdPNRm1b2Cs14UynOtp9rOv7+HyZg3kEhMZcqOyIIZ25zmWneIWyL8zfw== dependencies: - "@thirdweb-dev/crypto" "0.2.2" + "@thirdweb-dev/crypto" "0.2.5" cid-tool "^3.0.0" form-data "^4.0.0" uuid "^9.0.1" -"@thirdweb-dev/wallets@2.4.17": - version "2.4.17" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/wallets/-/wallets-2.4.17.tgz#f96fe5650269d11332d12eeb5372a6bd0c60905a" - integrity sha512-Cz8DkcXt+2Xh1b6IpqvZiykeIMHKJ7WUwfXu+vL2M8Ue2bJ334eshmTuZClJinf9jZ7ZLSbZaPuPR+Rf8ZlK4A== +"@thirdweb-dev/wallets@2.4.33": + version "2.4.33" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/wallets/-/wallets-2.4.33.tgz#33bcee1d04b511b941d73624089721926565c58c" + integrity sha512-L57tgljlsbaM2djKzZqa2/8645o7ufoBlpTITmGD/nXFkaW3vb0ybNgd/YxCAvmvt9XDqdgPXuOj71nKrXGeBw== dependencies: "@account-abstraction/contracts" "^0.5.0" - "@blocto/sdk" "^0.5.4" - "@coinbase/wallet-sdk" "^3.7.1" - "@google-cloud/kms" "3.0.1" + "@blocto/sdk" "0.5.5" + "@coinbase/wallet-sdk" "^3.7.2" + "@google-cloud/kms" "4.2.0" "@magic-ext/connect" "^6.7.2" "@magic-ext/oauth" "^7.6.2" "@magic-sdk/provider" "^13.6.2" - "@metamask/eth-sig-util" "^4.0.0" + "@metamask/eth-sig-util" "^4.0.1" "@paperxyz/embedded-wallet-service-sdk" "^1.2.5" - "@paperxyz/sdk-common-utilities" "^0.1.0" - "@safe-global/safe-core-sdk" "^3.3.4" + "@paperxyz/sdk-common-utilities" "^0.1.1" + "@safe-global/safe-core-sdk" "^3.3.5" "@safe-global/safe-ethers-adapters" "0.1.0-alpha.17" "@safe-global/safe-ethers-lib" "^1.9.4" - "@thirdweb-dev/chains" "0.1.78" - "@thirdweb-dev/contracts-js" "1.3.16" - "@thirdweb-dev/crypto" "0.2.1" - "@thirdweb-dev/sdk" "4.0.42" - "@walletconnect/core" "^2.9.1" - "@walletconnect/ethereum-provider" "^2.9.1" + "@thirdweb-dev/chains" "0.1.88" + "@thirdweb-dev/contracts-js" "1.3.20" + "@thirdweb-dev/crypto" "0.2.4" + "@thirdweb-dev/sdk" "4.0.57" + "@walletconnect/core" "^2.11.3" + "@walletconnect/ethereum-provider" "^2.11.3" "@walletconnect/jsonrpc-utils" "^1.0.8" - "@walletconnect/modal" "^2.6.1" - "@walletconnect/types" "^2.9.1" - "@walletconnect/utils" "^2.10.2" - "@walletconnect/web3wallet" "^1.8.7" + "@walletconnect/modal" "^2.6.2" + "@walletconnect/types" "^2.11.3" + "@walletconnect/utils" "^2.11.3" + "@walletconnect/web3wallet" "^1.10.3" asn1.js "5.4.1" - bn.js "5.2.0" + bn.js "5.2.1" buffer "^6.0.3" eth-provider "^0.13.6" - ethereumjs-util "^7.1.3" + ethereumjs-util "^7.1.5" eventemitter3 "^5.0.1" key-encoder "2.0.3" magic-sdk "^13.6.2" web3-core "1.5.2" -"@thirdweb-dev/wallets@2.4.25": - version "2.4.25" - resolved "https://registry.yarnpkg.com/@thirdweb-dev/wallets/-/wallets-2.4.25.tgz#f1ad7c7f996b87f0eedb52b6538cf6a436a69fd7" - integrity sha512-bDl1uOWDED/KfCI7PwZEMoS4J14CVE5lZEaJth30IGbBSo0KTEoYAkttI/ghkN8+s3T0ZtyjQibVLsEO24HWYQ== +"@thirdweb-dev/wallets@^2.4.36-nightly-6961e09a4cec4c276b233285e721dc0505792be5-20240408215531": + version "2.4.36-nightly-6961e09a4cec4c276b233285e721dc0505792be5-20240408215531" + resolved "https://registry.yarnpkg.com/@thirdweb-dev/wallets/-/wallets-2.4.36-nightly-6961e09a4cec4c276b233285e721dc0505792be5-20240408215531.tgz#ff73089ae3c092fa1af5bf5c5ce26a063d9cf693" + integrity sha512-2WSib2xca07VUO1k5P8fhs7uVtQepcYrUa1aOVmR5JOuJFXiQAU5c5CAcFGijlafvumVQAo13I2GeUxlX/S/qg== dependencies: "@account-abstraction/contracts" "^0.5.0" - "@blocto/sdk" "^0.5.4" - "@coinbase/wallet-sdk" "^3.7.1" - "@google-cloud/kms" "3.0.1" + "@blocto/sdk" "0.5.5" + "@coinbase/wallet-sdk" "^3.7.2" + "@google-cloud/kms" "4.2.0" "@magic-ext/connect" "^6.7.2" "@magic-ext/oauth" "^7.6.2" "@magic-sdk/provider" "^13.6.2" - "@metamask/eth-sig-util" "^4.0.0" + "@metamask/eth-sig-util" "^4.0.1" "@paperxyz/embedded-wallet-service-sdk" "^1.2.5" - "@paperxyz/sdk-common-utilities" "^0.1.0" - "@safe-global/safe-core-sdk" "^3.3.4" + "@paperxyz/sdk-common-utilities" "^0.1.1" + "@safe-global/safe-core-sdk" "^3.3.5" "@safe-global/safe-ethers-adapters" "0.1.0-alpha.17" "@safe-global/safe-ethers-lib" "^1.9.4" - "@thirdweb-dev/chains" "0.1.81" - "@thirdweb-dev/contracts-js" "1.3.18" - "@thirdweb-dev/crypto" "0.2.2" - "@thirdweb-dev/sdk" "4.0.49" - "@walletconnect/core" "^2.9.1" - "@walletconnect/ethereum-provider" "^2.9.1" + "@thirdweb-dev/chains" "0.1.91-nightly-6961e09a4cec4c276b233285e721dc0505792be5-20240408215531" + "@thirdweb-dev/contracts-js" "1.3.21" + "@thirdweb-dev/crypto" "0.2.5" + "@thirdweb-dev/sdk" "4.0.60-nightly-6961e09a4cec4c276b233285e721dc0505792be5-20240408215531" + "@walletconnect/core" "^2.12.1" + "@walletconnect/ethereum-provider" "2.12.1" "@walletconnect/jsonrpc-utils" "^1.0.8" - "@walletconnect/modal" "^2.6.1" - "@walletconnect/types" "^2.9.1" - "@walletconnect/utils" "^2.10.2" - "@walletconnect/web3wallet" "^1.8.7" + "@walletconnect/modal" "^2.6.2" + "@walletconnect/types" "^2.12.1" + "@walletconnect/utils" "^2.12.1" + "@walletconnect/web3wallet" "^1.11.1" asn1.js "5.4.1" - bn.js "5.2.0" + bn.js "5.2.1" buffer "^6.0.3" eth-provider "^0.13.6" - ethereumjs-util "^7.1.3" + ethereumjs-util "^7.1.5" eventemitter3 "^5.0.1" key-encoder "2.0.3" magic-sdk "^13.6.2" @@ -3948,6 +3943,13 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== +"@types/jsonwebtoken@^9.0.6": + version "9.0.6" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz#d1af3544d99ad992fb6681bbe60676e06b032bd3" + integrity sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw== + dependencies: + "@types/node" "*" + "@types/linkify-it@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.3.tgz#15a0712296c5041733c79efe233ba17ae5a7587b" @@ -4208,51 +4210,52 @@ "@typescript-eslint/types" "5.59.5" eslint-visitor-keys "^3.3.0" -"@walletconnect/auth-client@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@walletconnect/auth-client/-/auth-client-2.1.1.tgz#45548fc5d5e5ac155503d1b42ac97a96a2cba98d" - integrity sha512-rFGBG3pLkmwCc5DcL9JRCsvOAmPjUcHGxm+KlX31yXNOT1QACT8Gyd8ODSOmtvz5CXZS5dPWBuvO03LUSRbPkw== +"@walletconnect/auth-client@2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@walletconnect/auth-client/-/auth-client-2.1.2.tgz#cee304fb0cdca76f6bf4aafac96ef9301862a7e8" + integrity sha512-ubJLn+vGb8sTdBFX6xAh4kjR5idrtS3RBngQWaJJJpEPBQmxMb8pM2q0FIRs8Is4K6jKy+uEhusMV+7ZBmTzjw== dependencies: "@ethersproject/hash" "^5.7.0" "@ethersproject/transactions" "^5.7.0" "@stablelib/random" "^1.0.2" "@stablelib/sha256" "^1.0.1" - "@walletconnect/core" "^2.9.0" + "@walletconnect/core" "^2.10.1" "@walletconnect/events" "^1.0.1" "@walletconnect/heartbeat" "^1.2.1" "@walletconnect/jsonrpc-utils" "^1.0.8" "@walletconnect/logger" "^2.0.1" "@walletconnect/time" "^1.0.2" - "@walletconnect/utils" "^2.9.0" + "@walletconnect/utils" "^2.10.1" events "^3.3.0" isomorphic-unfetch "^3.1.0" -"@walletconnect/core@2.10.0", "@walletconnect/core@^2.9.1": - version "2.10.0" - resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.10.0.tgz#b659de4dfb374becd938964abd4f2150d410e617" - integrity sha512-Z8pdorfIMueuiBXLdnf7yloiO9JIiobuxN3j0OTal+MYc4q5/2O7d+jdD1DAXbLi1taJx3x60UXT/FPVkjIqIQ== +"@walletconnect/core@2.11.3": + version "2.11.3" + resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.11.3.tgz#c81855722cb9afd411f91f5345c7874f48bade0b" + integrity sha512-/9m4EqiggFUwkQDv5PDWbcTI+yCVnBd/iYW5iIHEkivg2/mnBr2bQz2r/vtPjp19r/ZK62Dx0+UN3U+BWP8ulQ== dependencies: "@walletconnect/heartbeat" "1.2.1" "@walletconnect/jsonrpc-provider" "1.0.13" "@walletconnect/jsonrpc-types" "1.0.3" "@walletconnect/jsonrpc-utils" "1.0.8" - "@walletconnect/jsonrpc-ws-connection" "1.0.13" - "@walletconnect/keyvaluestorage" "^1.0.2" + "@walletconnect/jsonrpc-ws-connection" "1.0.14" + "@walletconnect/keyvaluestorage" "^1.1.1" "@walletconnect/logger" "^2.0.1" "@walletconnect/relay-api" "^1.0.9" "@walletconnect/relay-auth" "^1.0.4" "@walletconnect/safe-json" "^1.0.2" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.10.0" - "@walletconnect/utils" "2.10.0" + "@walletconnect/types" "2.11.3" + "@walletconnect/utils" "2.11.3" events "^3.3.0" + isomorphic-unfetch "3.1.0" lodash.isequal "4.5.0" uint8arrays "^3.1.0" -"@walletconnect/core@2.11.3": - version "2.11.3" - resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.11.3.tgz#c81855722cb9afd411f91f5345c7874f48bade0b" - integrity sha512-/9m4EqiggFUwkQDv5PDWbcTI+yCVnBd/iYW5iIHEkivg2/mnBr2bQz2r/vtPjp19r/ZK62Dx0+UN3U+BWP8ulQ== +"@walletconnect/core@2.12.0", "@walletconnect/core@^2.10.1", "@walletconnect/core@^2.11.3": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.12.0.tgz#54c50eeb61466fbd8303eb0881b5e6bac69ccaa5" + integrity sha512-CORck4dRvCpIn6hl2ZtUnjrSJ0JHt9TRteGCViwPyXNSuvXz70RvaIkvPoybYZBGCRQR4WTJ4dMdqeQpuyrL/g== dependencies: "@walletconnect/heartbeat" "1.2.1" "@walletconnect/jsonrpc-provider" "1.0.13" @@ -4260,37 +4263,38 @@ "@walletconnect/jsonrpc-utils" "1.0.8" "@walletconnect/jsonrpc-ws-connection" "1.0.14" "@walletconnect/keyvaluestorage" "^1.1.1" - "@walletconnect/logger" "^2.0.1" + "@walletconnect/logger" "^2.1.0" "@walletconnect/relay-api" "^1.0.9" "@walletconnect/relay-auth" "^1.0.4" "@walletconnect/safe-json" "^1.0.2" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.11.3" - "@walletconnect/utils" "2.11.3" + "@walletconnect/types" "2.12.0" + "@walletconnect/utils" "2.12.0" events "^3.3.0" isomorphic-unfetch "3.1.0" lodash.isequal "4.5.0" uint8arrays "^3.1.0" -"@walletconnect/core@^2.9.0": - version "2.9.1" - resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.9.1.tgz#1a333933750f5f933d9b7788a8dae44ce1173063" - integrity sha512-xyWeP0eLhEEDQAVJSmqs4n/AClKUM+8os2ZFe7BTuw1tFYjeLNVDtKCHziVOSTh8wEChMsKSGKA4zerQoH8mAQ== +"@walletconnect/core@2.12.1", "@walletconnect/core@^2.12.1": + version "2.12.1" + resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.12.1.tgz#e905e42f6c2a5117a1166c1a1d35e40aa98e76d3" + integrity sha512-CIxWNRNvmFNwn+8kPbKyBXS1JHBFJpDE8f73dXtUIElVnZhmXzEOSE5fug91EX57wTrv4/qW66H9kNB3c7Pp5g== dependencies: "@walletconnect/heartbeat" "1.2.1" "@walletconnect/jsonrpc-provider" "1.0.13" "@walletconnect/jsonrpc-types" "1.0.3" "@walletconnect/jsonrpc-utils" "1.0.8" - "@walletconnect/jsonrpc-ws-connection" "1.0.13" - "@walletconnect/keyvaluestorage" "^1.0.2" - "@walletconnect/logger" "^2.0.1" + "@walletconnect/jsonrpc-ws-connection" "1.0.14" + "@walletconnect/keyvaluestorage" "^1.1.1" + "@walletconnect/logger" "^2.1.0" "@walletconnect/relay-api" "^1.0.9" "@walletconnect/relay-auth" "^1.0.4" "@walletconnect/safe-json" "^1.0.2" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.9.1" - "@walletconnect/utils" "2.9.1" + "@walletconnect/types" "2.12.1" + "@walletconnect/utils" "2.12.1" events "^3.3.0" + isomorphic-unfetch "3.1.0" lodash.isequal "4.5.0" uint8arrays "^3.1.0" @@ -4317,19 +4321,36 @@ "@walletconnect/utils" "2.11.3" events "^3.3.0" -"@walletconnect/ethereum-provider@^2.9.1": - version "2.10.0" - resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.10.0.tgz#eebde38674222a48be35bb4aa3f6a74247ba059b" - integrity sha512-NyTm7RcrtAiSaYQPh6G4sOtr1kg/pL5Z3EDE6rBTV3Se5pMsYvtuwMiSol7MidsQpf4ux9HFhthTO3imcoWImw== +"@walletconnect/ethereum-provider@2.12.1": + version "2.12.1" + resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.12.1.tgz#0085c6d9388e6f9322c81b698ad2653515f29e3f" + integrity sha512-C57sIcKDNKx6UgnW4EVrmBGAXGddfjgC88vpkOTBrClFF8zhSfdf/fKnLLo70spr8z3u77IppD36m6DGhJ+xpw== + dependencies: + "@walletconnect/jsonrpc-http-connection" "^1.0.7" + "@walletconnect/jsonrpc-provider" "^1.0.13" + "@walletconnect/jsonrpc-types" "^1.0.3" + "@walletconnect/jsonrpc-utils" "^1.0.8" + "@walletconnect/modal" "^2.6.2" + "@walletconnect/sign-client" "2.12.1" + "@walletconnect/types" "2.12.1" + "@walletconnect/universal-provider" "2.12.1" + "@walletconnect/utils" "2.12.1" + events "^3.3.0" + +"@walletconnect/ethereum-provider@^2.11.3": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.12.0.tgz#18f870826c78383feb3f05efa3a57be178aa0312" + integrity sha512-sX7vQHTRxByU+3/gY6eDTvt4jxQHfiX6WwqRI08UTN/Ixz+IJSBo3UnNRxNmPaC4vG8zUpsFQ4xYSsDnhfaviw== dependencies: "@walletconnect/jsonrpc-http-connection" "^1.0.7" "@walletconnect/jsonrpc-provider" "^1.0.13" "@walletconnect/jsonrpc-types" "^1.0.3" "@walletconnect/jsonrpc-utils" "^1.0.8" - "@walletconnect/sign-client" "2.10.0" - "@walletconnect/types" "2.10.0" - "@walletconnect/universal-provider" "2.10.0" - "@walletconnect/utils" "2.10.0" + "@walletconnect/modal" "^2.6.2" + "@walletconnect/sign-client" "2.12.0" + "@walletconnect/types" "2.12.0" + "@walletconnect/universal-provider" "2.12.0" + "@walletconnect/utils" "2.12.0" events "^3.3.0" "@walletconnect/events@^1.0.1": @@ -4385,17 +4406,6 @@ "@walletconnect/jsonrpc-types" "^1.0.3" tslib "1.14.1" -"@walletconnect/jsonrpc-ws-connection@1.0.13": - version "1.0.13" - resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.13.tgz#23b0cdd899801bfbb44a6556936ec2b93ef2adf4" - integrity sha512-mfOM7uFH4lGtQxG+XklYuFBj6dwVvseTt5/ahOkkmpcAEgz2umuzu7fTR+h5EmjQBdrmYyEBOWADbeaFNxdySg== - dependencies: - "@walletconnect/jsonrpc-utils" "^1.0.6" - "@walletconnect/safe-json" "^1.0.2" - events "^3.3.0" - tslib "1.14.1" - ws "^7.5.1" - "@walletconnect/jsonrpc-ws-connection@1.0.14": version "1.0.14" resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.14.tgz#eec700e74766c7887de2bd76c91a0206628732aa" @@ -4406,14 +4416,6 @@ events "^3.3.0" ws "^7.5.1" -"@walletconnect/keyvaluestorage@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.0.2.tgz#92f5ca0f54c1a88a093778842ce0c874d86369c8" - integrity sha512-U/nNG+VLWoPFdwwKx0oliT4ziKQCEoQ27L5Hhw8YOFGA2Po9A9pULUYNWhDgHkrb0gYDNt//X7wABcEWWBd3FQ== - dependencies: - safe-json-utils "^1.1.1" - tslib "1.14.1" - "@walletconnect/keyvaluestorage@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz#dd2caddabfbaf80f6b8993a0704d8b83115a1842" @@ -4431,12 +4433,13 @@ pino "7.11.0" tslib "1.14.1" -"@walletconnect/modal-core@2.6.1": - version "2.6.1" - resolved "https://registry.yarnpkg.com/@walletconnect/modal-core/-/modal-core-2.6.1.tgz#bc76055d0b644a2d4b98024324825c108a700905" - integrity sha512-f2hYlJ5pwzGvjyaZ6BoGR5uiMgXzWXt6w6ktt1N8lmY6PiYp8whZgqx2hTxVWwVlsGnaIfh6UHp1hGnANx0eTQ== +"@walletconnect/logger@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@walletconnect/logger/-/logger-2.1.0.tgz#f00b919609a442f596b4eef2bae9c20a072692c0" + integrity sha512-lyCRHlxlBHxvj1fJXa2YOW4whVNucPKF7Oc0D1UvYhfArpIIjlJJiTe5cLm8g4ZH4z5lKp14N/c9oRHlyv5v4A== dependencies: - valtio "1.11.0" + "@walletconnect/safe-json" "^1.0.2" + pino "7.11.0" "@walletconnect/modal-core@2.6.2": version "2.6.2" @@ -4445,16 +4448,6 @@ dependencies: valtio "1.11.2" -"@walletconnect/modal-ui@2.6.1": - version "2.6.1" - resolved "https://registry.yarnpkg.com/@walletconnect/modal-ui/-/modal-ui-2.6.1.tgz#200c54c8dfe3c71321abb2724e18bb357dfd6371" - integrity sha512-RFUOwDAMijSK8B7W3+KoLKaa1l+KEUG0LCrtHqaB0H0cLnhEGdLR+kdTdygw+W8+yYZbkM5tXBm7MlFbcuyitA== - dependencies: - "@walletconnect/modal-core" "2.6.1" - lit "2.7.6" - motion "10.16.2" - qrcode "1.5.3" - "@walletconnect/modal-ui@2.6.2": version "2.6.2" resolved "https://registry.yarnpkg.com/@walletconnect/modal-ui/-/modal-ui-2.6.2.tgz#fa57c087c57b7f76aaae93deab0f84bb68b59cf9" @@ -4465,14 +4458,6 @@ motion "10.16.2" qrcode "1.5.3" -"@walletconnect/modal@^2.6.1": - version "2.6.1" - resolved "https://registry.yarnpkg.com/@walletconnect/modal/-/modal-2.6.1.tgz#066fdbfcff83b58c8a9da66ab4af0eb93e3626de" - integrity sha512-G84tSzdPKAFk1zimgV7JzIUFT5olZUVtI3GcOk77OeLYjlMfnDT23RVRHm5EyCrjkptnvpD0wQScXePOFd2Xcw== - dependencies: - "@walletconnect/modal-core" "2.6.1" - "@walletconnect/modal-ui" "2.6.1" - "@walletconnect/modal@^2.6.2": version "2.6.2" resolved "https://registry.yarnpkg.com/@walletconnect/modal/-/modal-2.6.2.tgz#4b534a836f5039eeb3268b80be7217a94dd12651" @@ -4508,21 +4493,6 @@ dependencies: tslib "1.14.1" -"@walletconnect/sign-client@2.10.0": - version "2.10.0" - resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.10.0.tgz#0fee8f12821e37783099f0c7bd64e6efdfbd9d86" - integrity sha512-hbDljDS53kR/It3oXD91UkcOsT6diNnW5+Zzksm0YEfwww5dop/YfNlcdnc8+jKUhWOL/YDPNQCjzsCSNlVzbw== - dependencies: - "@walletconnect/core" "2.10.0" - "@walletconnect/events" "^1.0.1" - "@walletconnect/heartbeat" "1.2.1" - "@walletconnect/jsonrpc-utils" "1.0.8" - "@walletconnect/logger" "^2.0.1" - "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.10.0" - "@walletconnect/utils" "2.10.0" - events "^3.3.0" - "@walletconnect/sign-client@2.11.3": version "2.11.3" resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.11.3.tgz#3ea7b3acf92ee31cc42b45d42e66c44b4720b28b" @@ -4538,37 +4508,43 @@ "@walletconnect/utils" "2.11.3" events "^3.3.0" -"@walletconnect/time@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@walletconnect/time/-/time-1.0.2.tgz#6c5888b835750ecb4299d28eecc5e72c6d336523" - integrity sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g== - dependencies: - tslib "1.14.1" - -"@walletconnect/types@2.10.0", "@walletconnect/types@^2.9.1": - version "2.10.0" - resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.10.0.tgz#5d63235b49e03d609521402a4b49627dbc4ed514" - integrity sha512-kSTA/WZnbKdEbvbXSW16Ty6dOSzOZCHnGg6JH7q1MuraalD2HuNg00lVVu7QAZ/Rj1Gn9DAkrgP5Wd5a8Xq//Q== +"@walletconnect/sign-client@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.12.0.tgz#84cb7293f532c9db3803b8a9ec42542b5bc77eab" + integrity sha512-JUHJVZtW9iJmn3I2byLzhMRSFiQicTPU92PLuHIF2nG98CqsvlPn8Cu8Cx5CEPFrxPQWwLA+Dv/F+wuSgQiD/w== dependencies: + "@walletconnect/core" "2.12.0" "@walletconnect/events" "^1.0.1" "@walletconnect/heartbeat" "1.2.1" - "@walletconnect/jsonrpc-types" "1.0.3" - "@walletconnect/keyvaluestorage" "^1.0.2" + "@walletconnect/jsonrpc-utils" "1.0.8" "@walletconnect/logger" "^2.0.1" + "@walletconnect/time" "^1.0.2" + "@walletconnect/types" "2.12.0" + "@walletconnect/utils" "2.12.0" events "^3.3.0" -"@walletconnect/types@2.10.2": - version "2.10.2" - resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.10.2.tgz#68e433a29ec2cf42d79d8b50c77bd5c1d91db721" - integrity sha512-luNV+07Wdla4STi9AejseCQY31tzWKQ5a7C3zZZaRK/di+rFaAAb7YW04OP4klE7tw/mJRGPTlekZElmHxO8kQ== +"@walletconnect/sign-client@2.12.1": + version "2.12.1" + resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.12.1.tgz#a10f316f5681b7547db2714666a159574f31126f" + integrity sha512-6PegtNZgqmOX2G022fyrHjyN3PW6Ov2GVFvG8f+80uqikEO3IAL3dgazlnUYtuaUNYs+Hx7sSvjNVanMiJsE1Q== dependencies: + "@walletconnect/core" "2.12.1" "@walletconnect/events" "^1.0.1" "@walletconnect/heartbeat" "1.2.1" - "@walletconnect/jsonrpc-types" "1.0.3" - "@walletconnect/keyvaluestorage" "^1.0.2" + "@walletconnect/jsonrpc-utils" "1.0.8" "@walletconnect/logger" "^2.0.1" + "@walletconnect/time" "^1.0.2" + "@walletconnect/types" "2.12.1" + "@walletconnect/utils" "2.12.1" events "^3.3.0" +"@walletconnect/time@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@walletconnect/time/-/time-1.0.2.tgz#6c5888b835750ecb4299d28eecc5e72c6d336523" + integrity sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g== + dependencies: + tslib "1.14.1" + "@walletconnect/types@2.11.3": version "2.11.3" resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.11.3.tgz#8ce43cb77e8fd9d5269847cdd73bcfa7cce7dd1a" @@ -4581,31 +4557,28 @@ "@walletconnect/logger" "^2.0.1" events "^3.3.0" -"@walletconnect/types@2.9.1": - version "2.9.1" - resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.9.1.tgz#cb32ff396cc8880a7395f28716d1e82f407e1372" - integrity sha512-xbGgTPuD6xsb7YMvCESBIH55cjB86QAnnVL50a/ED42YkQzDsOdJ0VGTbrm0tG5cxUOF933rpxZQjxGdP+ovww== +"@walletconnect/types@2.12.0", "@walletconnect/types@^2.11.3": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.12.0.tgz#83e1057c795d41afaeecad3a2776aaa4ba12f5d6" + integrity sha512-uhB3waGmujQVJcPgJvGOpB8RalgYSBT+HpmVbfl4Qe0xJyqpRUo4bPjQa0UYkrHaW20xIw94OuP4+FMLYdeemg== dependencies: "@walletconnect/events" "^1.0.1" "@walletconnect/heartbeat" "1.2.1" "@walletconnect/jsonrpc-types" "1.0.3" - "@walletconnect/keyvaluestorage" "^1.0.2" + "@walletconnect/keyvaluestorage" "^1.1.1" "@walletconnect/logger" "^2.0.1" events "^3.3.0" -"@walletconnect/universal-provider@2.10.0": - version "2.10.0" - resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.10.0.tgz#565d6478dcb5cc66955e5f03d6a00f51c9bcac14" - integrity sha512-jtVWf+AeTCqBcB3lCmWkv3bvSmdRCkQdo67GNoT5y6/pvVHMxfjgrJNBOUsWQMxpREpWDpZ993X0JRjsYVsMcA== +"@walletconnect/types@2.12.1", "@walletconnect/types@^2.12.1": + version "2.12.1" + resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.12.1.tgz#a3cb49bdac43f5cff1d9543bcdbb65f75e19cacc" + integrity sha512-mPzGj5ssgcOJKqwn8qsdCr+J9swsjTmDPAV10CghXIe3GGQKOb4noTUhOofb4LDbFaio1GBql8+Xfy+6bulobw== dependencies: - "@walletconnect/jsonrpc-http-connection" "^1.0.7" - "@walletconnect/jsonrpc-provider" "1.0.13" - "@walletconnect/jsonrpc-types" "^1.0.2" - "@walletconnect/jsonrpc-utils" "^1.0.7" + "@walletconnect/events" "^1.0.1" + "@walletconnect/heartbeat" "1.2.1" + "@walletconnect/jsonrpc-types" "1.0.3" + "@walletconnect/keyvaluestorage" "^1.1.1" "@walletconnect/logger" "^2.0.1" - "@walletconnect/sign-client" "2.10.0" - "@walletconnect/types" "2.10.0" - "@walletconnect/utils" "2.10.0" events "^3.3.0" "@walletconnect/universal-provider@2.11.3": @@ -4623,25 +4596,35 @@ "@walletconnect/utils" "2.11.3" events "^3.3.0" -"@walletconnect/utils@2.10.0": - version "2.10.0" - resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.10.0.tgz#6918d12180d797b8bd4a19fb2ff128e394e181d6" - integrity sha512-9GRyEz/7CJW+G04RvrjPET5k7hOEsB9b3fF9cWDk/iDCxSWpbkU/hv/urRB36C+gvQMAZgIZYX3dHfzJWkY/2g== +"@walletconnect/universal-provider@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.12.0.tgz#412c98164e03792bee2f089c88c7f98f098cfb09" + integrity sha512-CMo10Lh6/DyCznVRMg1nHptWCTeVqMzXBcPNNyCnr3SazE0Shsne/5v/7Kr6j+Yts2hVbLp6lkI2F9ZAFpL6ug== dependencies: - "@stablelib/chacha20poly1305" "1.0.1" - "@stablelib/hkdf" "1.0.1" - "@stablelib/random" "^1.0.2" - "@stablelib/sha256" "1.0.1" - "@stablelib/x25519" "^1.0.3" - "@walletconnect/relay-api" "^1.0.9" - "@walletconnect/safe-json" "^1.0.2" - "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.10.0" - "@walletconnect/window-getters" "^1.0.1" - "@walletconnect/window-metadata" "^1.0.1" - detect-browser "5.3.0" - query-string "7.1.3" - uint8arrays "^3.1.0" + "@walletconnect/jsonrpc-http-connection" "^1.0.7" + "@walletconnect/jsonrpc-provider" "1.0.13" + "@walletconnect/jsonrpc-types" "^1.0.2" + "@walletconnect/jsonrpc-utils" "^1.0.7" + "@walletconnect/logger" "^2.0.1" + "@walletconnect/sign-client" "2.12.0" + "@walletconnect/types" "2.12.0" + "@walletconnect/utils" "2.12.0" + events "^3.3.0" + +"@walletconnect/universal-provider@2.12.1": + version "2.12.1" + resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.12.1.tgz#c092a123a7d1e5e0462a667bff5e3908d90d928f" + integrity sha512-ZLl5+wY3A7pss5UbIOKBcTwoFQmhW6ilDq33vX2Hu69yUnK+OEKlKcgAy4vjN2wAWakUctO4j7RhpionKBZfCw== + dependencies: + "@walletconnect/jsonrpc-http-connection" "^1.0.7" + "@walletconnect/jsonrpc-provider" "1.0.13" + "@walletconnect/jsonrpc-types" "^1.0.2" + "@walletconnect/jsonrpc-utils" "^1.0.7" + "@walletconnect/logger" "^2.0.1" + "@walletconnect/sign-client" "2.12.1" + "@walletconnect/types" "2.12.1" + "@walletconnect/utils" "2.12.1" + events "^3.3.0" "@walletconnect/utils@2.11.3": version "2.11.3" @@ -4663,10 +4646,10 @@ query-string "7.1.3" uint8arrays "^3.1.0" -"@walletconnect/utils@2.9.1", "@walletconnect/utils@^2.9.0": - version "2.9.1" - resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.9.1.tgz#92abc24b3af3ead42a3864e019dbf2f651ab2e47" - integrity sha512-tXeQVebF5oPBvhdmuUyVSkSIBYx/egIi4czav1QrnUpwrUS1LsrFhyWBxSbhN7TXY287ULWkEf6aFpWOHdp5EA== +"@walletconnect/utils@2.12.0", "@walletconnect/utils@^2.10.1", "@walletconnect/utils@^2.11.3": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.12.0.tgz#0a48f114d9c344d390730782d0d7a365814371bf" + integrity sha512-GIpfHUe1Bjp1Tjda0SkJEizKOT2biuv7VPFnKsOLT1T+8QxEP9NruC+K2UUEvijS1Qr/LKH9P5004RYNgrch+w== dependencies: "@stablelib/chacha20poly1305" "1.0.1" "@stablelib/hkdf" "1.0.1" @@ -4676,17 +4659,17 @@ "@walletconnect/relay-api" "^1.0.9" "@walletconnect/safe-json" "^1.0.2" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.9.1" + "@walletconnect/types" "2.12.0" "@walletconnect/window-getters" "^1.0.1" "@walletconnect/window-metadata" "^1.0.1" detect-browser "5.3.0" query-string "7.1.3" uint8arrays "^3.1.0" -"@walletconnect/utils@^2.10.2": - version "2.10.2" - resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.10.2.tgz#1f2c6a2f1bb95bcc4517b1e94aa7164c9286eb46" - integrity sha512-syxXRpc2yhSknMu3IfiBGobxOY7fLfLTJuw+ppKaeO6WUdZpIit3wfuGOcc0Ms3ZPFCrGfyGOoZsCvgdXtptRg== +"@walletconnect/utils@2.12.1", "@walletconnect/utils@^2.12.1": + version "2.12.1" + resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.12.1.tgz#5fced674e0a732eb62f30391943e79abbf3d5d1f" + integrity sha512-v2Oc8mTb+3y8MW94Rnj9hxVjJU3wdnE1g8eLZXmcNf7zAvsm1iJPtHl7ZxZsjpVpo1Vg79Oo1rS9gWq9z0kKKw== dependencies: "@stablelib/chacha20poly1305" "1.0.1" "@stablelib/hkdf" "1.0.1" @@ -4696,26 +4679,40 @@ "@walletconnect/relay-api" "^1.0.9" "@walletconnect/safe-json" "^1.0.2" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.10.2" + "@walletconnect/types" "2.12.1" "@walletconnect/window-getters" "^1.0.1" "@walletconnect/window-metadata" "^1.0.1" detect-browser "5.3.0" query-string "7.1.3" uint8arrays "^3.1.0" -"@walletconnect/web3wallet@^1.8.7": - version "1.9.0" - resolved "https://registry.yarnpkg.com/@walletconnect/web3wallet/-/web3wallet-1.9.0.tgz#ad4094e1e2ed757bc75efa961121b66b2eeb4306" - integrity sha512-3uu6GbOz2uwcmVaIpijkPlReywC1GsFtwJOB1bJZOkc8wjtNmR3jUMwqxWUv8ojbmDVVWQl1HN7Sptkrmq9Xyw== +"@walletconnect/web3wallet@^1.10.3": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@walletconnect/web3wallet/-/web3wallet-1.11.0.tgz#889588c8aca08c62811bcad1abc443fa45072dbc" + integrity sha512-kKwho8PYBPB2o/8huEvQwd7HR58hjOxZ+GI+KNVfu44yjbDL8NbL01zLqAp9ACy+zh8Jo17AXvN/M4U6tkw/Hg== dependencies: - "@walletconnect/auth-client" "2.1.1" - "@walletconnect/core" "2.10.0" + "@walletconnect/auth-client" "2.1.2" + "@walletconnect/core" "2.12.0" "@walletconnect/jsonrpc-provider" "1.0.13" "@walletconnect/jsonrpc-utils" "1.0.8" "@walletconnect/logger" "2.0.1" - "@walletconnect/sign-client" "2.10.0" - "@walletconnect/types" "2.10.0" - "@walletconnect/utils" "2.10.0" + "@walletconnect/sign-client" "2.12.0" + "@walletconnect/types" "2.12.0" + "@walletconnect/utils" "2.12.0" + +"@walletconnect/web3wallet@^1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@walletconnect/web3wallet/-/web3wallet-1.11.1.tgz#0716f493e0fa3923938ed0e31dffe275bff1c3bf" + integrity sha512-R50v3Ez73cLEaXPJOGMEBeEw5xN8/V6tya7+49OqwLLlZ6VR3tdJm8Az8TrvTrbRZ38oXP0cIl9ky+bSMCJtYw== + dependencies: + "@walletconnect/auth-client" "2.1.2" + "@walletconnect/core" "2.12.1" + "@walletconnect/jsonrpc-provider" "1.0.13" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/logger" "2.0.1" + "@walletconnect/sign-client" "2.12.1" + "@walletconnect/types" "2.12.1" + "@walletconnect/utils" "2.12.1" "@walletconnect/window-getters@^1.0.1": version "1.0.1" @@ -4755,11 +4752,6 @@ abitype@1.0.0: resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.0.tgz#237176dace81d90d018bebf3a45cb42f2a2d9e97" integrity sha512-NMeMah//6bJ56H5XRj8QCV4AwuW6hB6zqz2LnhhLdcWVQOsXki6/Pn3APeqxCma62nXIcmZWdu1DlHWS74umVQ== -abitype@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.2.5.tgz#e571ef2ed99db1cae551fffde5bcbcee4e446177" - integrity sha512-t1iiokWYpkrziu4WL2Gb6YdGvaP9ZKs7WnA39TI8TsW2E99GVRgDPW/xOKhzoCdyxOYt550CNYEFluCwGaFHaA== - abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -5197,16 +5189,16 @@ bn.js@5.2.0: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== +bn.js@5.2.1, bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.0, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== -bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== - body-parser@1.20.2, body-parser@^1.20.2: version "1.20.2" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" @@ -5495,6 +5487,19 @@ catharsis@^0.9.0: dependencies: lodash "^4.17.15" +chai@^4.3.10: + version "4.4.1" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.4.1.tgz#3603fa6eba35425b0f2ac91a009fe924106e50d1" + integrity sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.0.8" + chai@^4.3.4: version "4.3.8" resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.8.tgz#40c59718ad6928da6629c70496fe990b2bb5b17c" @@ -5810,7 +5815,7 @@ cookie@0.4.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== -cookie@0.6.0: +cookie@0.6.0, cookie@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== @@ -6633,7 +6638,7 @@ ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: ethjs-util "0.1.6" rlp "^2.2.3" -ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.3, ethereumjs-util@^7.1.5: +ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.5: version "7.1.5" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== @@ -8409,7 +8414,7 @@ js-sha3@0.8.0, js-sha3@^0.8.0: resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== -js-sha3@^0.9.2: +js-sha3@^0.9.3: version "0.9.3" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.9.3.tgz#f0209432b23a66a0f6c7af592c26802291a75c2a" integrity sha512-BcJPCQeLg6WjEx3FE591wVAevlli8lxsxm9/FzV4HXkV49TmBH38Yvrpce6fjbADGMKFrBMGTqrVz3qPIZ88Gg== @@ -8552,6 +8557,31 @@ jsonparse@^1.2.0: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== +jsonwebtoken@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" + integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^7.5.4" + +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + jwa@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/jwa/-/jwa-2.0.0.tgz#a7e9c3f29dae94027ebcaf49975c9345593410fc" @@ -8561,6 +8591,14 @@ jwa@^2.0.0: ecdsa-sig-formatter "1.0.11" safe-buffer "^5.0.1" +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + jws@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.0.tgz#2d4e8cf6a318ffaa12615e9dec7e86e6c97310f4" @@ -8721,15 +8759,6 @@ lit-html@^2.8.0: dependencies: "@types/trusted-types" "^2.0.2" -lit@2.7.6: - version "2.7.6" - resolved "https://registry.yarnpkg.com/lit/-/lit-2.7.6.tgz#810007b876ed43e0c70124de91831921598b1665" - integrity sha512-1amFHA7t4VaaDe+vdQejSVBklwtH9svGoG6/dZi9JhxtJBBlqY5D1RV7iLUYY0trCqQc4NfhYYZilZiVHt7Hxg== - dependencies: - "@lit/reactive-element" "^1.6.0" - lit-element "^3.3.0" - lit-html "^2.7.0" - lit@2.8.0, lit@^2.2.3: version "2.8.0" resolved "https://registry.yarnpkg.com/lit/-/lit-2.8.0.tgz#4d838ae03059bf9cafa06e5c61d8acc0081e974e" @@ -8765,11 +8794,41 @@ lodash.camelcase@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + lodash.isequal@4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + lodash.memoize@4.x: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -8780,6 +8839,11 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" @@ -10913,10 +10977,10 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" -tiny-invariant@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" - integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== +tiny-invariant@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" + integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== tiny-lru@^11.0.1: version "11.0.1" @@ -11345,14 +11409,6 @@ v8-to-istanbul@^9.0.1: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^2.0.0" -valtio@1.11.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.11.0.tgz#c029dcd17a0f99d2fbec933721fe64cfd32a31ed" - integrity sha512-65Yd0yU5qs86b5lN1eu/nzcTgQ9/6YnD6iO+DDaDbQLn1Zv2w12Gwk43WkPlUBxk5wL/6cD5YMFf7kj6HZ1Kpg== - dependencies: - proxy-compare "2.5.1" - use-sync-external-store "1.2.0" - valtio@1.11.2: version "1.11.2" resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.11.2.tgz#b8049c02dfe65620635d23ebae9121a741bb6530" @@ -11837,7 +11893,7 @@ yaml@^2.2.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b" integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== -yaml@^2.3.4: +yaml@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.1.tgz#2e57e0b5e995292c25c75d2658f0664765210eed" integrity sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg== @@ -11928,7 +11984,7 @@ zod@^3.21.4: resolved "https://registry.yarnpkg.com/zod/-/zod-3.21.4.tgz#10882231d992519f0a10b5dd58a38c9dabbb64db" integrity sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw== -zod@^3.22.3: +zod@^3.22.3, zod@^3.22.4: version "3.22.4" resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.4.tgz#f31c3a9386f61b1f228af56faa9255e845cf3fff" integrity sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==