diff --git a/apps/connect-v1/src/hooks/useConnectConfig.ts b/apps/connect-v1/src/hooks/useConnectConfig.ts index d4629fc0d..a6ab7db6e 100644 --- a/apps/connect-v1/src/hooks/useConnectConfig.ts +++ b/apps/connect-v1/src/hooks/useConnectConfig.ts @@ -18,6 +18,7 @@ import { getSortedChains } from "../utils/getSortedChains"; const defaultConfig: WormholeConnectConfig = { ...ENV.wormholeConnectConfig, + // @ts-expect-error: Type error because v1 is outdated eventHandler: (e: WormholeConnectEvent) => { if (isPreview || isProduction) { // Send the event to Mixpanel diff --git a/apps/connect-v1/src/navs/navs.test.ts b/apps/connect-v1/src/navs/navs.test.ts index 8a11019e1..eb4f7fc11 100644 --- a/apps/connect-v1/src/navs/navs.test.ts +++ b/apps/connect-v1/src/navs/navs.test.ts @@ -28,6 +28,8 @@ describe("navs", () => { toToken: EMPTY_TOKEN, toChain: 1, }, + // @ts-expect-error: Type error because v1 is outdated + meta: { version: "version", hash: "hash", host: "host" }, }); expect(global.window.history.pushState).toHaveBeenCalledWith( { event: "transfer.start" }, @@ -47,6 +49,8 @@ describe("navs", () => { toToken: EMPTY_TOKEN, toChain: 1, }, + // @ts-expect-error: Type error because v1 is outdated + meta: { version: "version", hash: "hash", host: "host" }, }); expect(global.window.history.pushState).toHaveBeenCalledWith( { event: "transfer.success" }, @@ -66,6 +70,8 @@ describe("navs", () => { toToken: EMPTY_TOKEN, toChain: 1, }, + // @ts-expect-error: Type error because v1 is outdated + meta: { version: "version", hash: "hash", host: "host" }, }); expect(global.window.history.pushState).toHaveBeenCalledWith( { event: "transfer.redeem.success" }, diff --git a/apps/connect-v1/src/providers/telemetry.test.ts b/apps/connect-v1/src/providers/telemetry.test.ts index 0de21a733..1f4236939 100644 --- a/apps/connect-v1/src/providers/telemetry.test.ts +++ b/apps/connect-v1/src/providers/telemetry.test.ts @@ -31,7 +31,11 @@ describe("telemetry", () => { }); it("should not track load events", () => { - eventHandler({ type: "load" }); + eventHandler({ + type: "load", + // @ts-expect-error: Type error because v1 is outdated + meta: { version: "version", hash: "hash", host: "host" }, + }); expect(mixpanel.track).not.toHaveBeenCalled(); }); @@ -44,6 +48,8 @@ describe("telemetry", () => { chain: "bsc", wallet: "wallet", }, + // @ts-expect-error: Type error because v1 is outdated + meta: { version: "version", hash: "hash", host: "host" }, }); expect(mixpanel.track).toHaveBeenCalledTimes(1); @@ -67,6 +73,8 @@ describe("telemetry", () => { route: "wstETH Bridge", txId: "txId", USDAmount: 123.456, + amount: undefined, + connectVersion: undefined, }); }); diff --git a/apps/connect-v1/src/providers/telemetry.ts b/apps/connect-v1/src/providers/telemetry.ts index 8d0ec945a..800fa96e2 100644 --- a/apps/connect-v1/src/providers/telemetry.ts +++ b/apps/connect-v1/src/providers/telemetry.ts @@ -4,7 +4,12 @@ import type { WormholeConnectConfig } from "@wormhole-foundation/wormhole-connec export type WormholeConnectEvent = Parameters< NonNullable ->[0]; +>[0] & { + meta: { + version: string; + hash: string; + }; +}; mixpanel.init( isProduction @@ -75,6 +80,7 @@ export const eventHandler = (e: WormholeConnectEvent) => { txId: e.details.txId, USDAmount: e.details.USDAmount, amount: e.details.amount, + connectVersion: e.meta?.version, route: { bridge: "Manual Bridge", diff --git a/apps/connect/package-lock.json b/apps/connect/package-lock.json index 684a69a7d..2d46c18ea 100644 --- a/apps/connect/package-lock.json +++ b/apps/connect/package-lock.json @@ -15,7 +15,7 @@ "@mui/material": "^5.12.1", "@tanstack/react-query": "^5.14.2", "@wormhole-foundation/sdk": "^0.10.3", - "@wormhole-foundation/wormhole-connect": "^1.0.0", + "@wormhole-foundation/wormhole-connect": "^1.1.1", "aptos": "^1.21.0", "bech32": "^2.0.0", "dompurify": "^3.0.6", @@ -174,186 +174,6 @@ "proxy-from-env": "^1.1.0" } }, - "node_modules/@artursapek/vite-plugin-checker": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/@artursapek/vite-plugin-checker/-/vite-plugin-checker-0.7.3.tgz", - "integrity": "sha512-Vk45xj7DSQ6Ny2a1FgX8dYEgqfIRLO+P3zVaPc1nTAWgd96BldufQf89uzJD8bzRKY7xk2gvXEaK6jKizISrCA==", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "ansi-escapes": "^4.3.0", - "chalk": "^4.1.1", - "chokidar": "^3.5.1", - "commander": "^8.0.0", - "fast-glob": "^3.2.7", - "fs-extra": "^11.1.0", - "npm-run-path": "^4.0.1", - "strip-ansi": "^6.0.0", - "tiny-invariant": "^1.1.0", - "vscode-languageclient": "^7.0.0", - "vscode-languageserver": "^7.0.0", - "vscode-languageserver-textdocument": "^1.0.1", - "vscode-uri": "^3.0.2" - }, - "engines": { - "node": ">=14.16" - }, - "peerDependencies": { - "@biomejs/biome": ">=1.7", - "eslint": ">=7", - "meow": "^9.0.0", - "optionator": "^0.9.1", - "stylelint": ">=13", - "typescript": "*", - "vite": ">=2.0.0", - "vls": "*", - "vti": "*", - "vue-tsc": ">=2.0.0" - }, - "peerDependenciesMeta": { - "@biomejs/biome": { - "optional": true - }, - "eslint": { - "optional": true - }, - "meow": { - "optional": true - }, - "optionator": { - "optional": true - }, - "stylelint": { - "optional": true - }, - "typescript": { - "optional": true - }, - "vls": { - "optional": true - }, - "vti": { - "optional": true - }, - "vue-tsc": { - "optional": true - } - } - }, - "node_modules/@artursapek/vite-plugin-checker/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@artursapek/vite-plugin-checker/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@artursapek/vite-plugin-checker/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@artursapek/vite-plugin-checker/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@artursapek/vite-plugin-checker/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "engines": { - "node": ">= 12" - } - }, - "node_modules/@artursapek/vite-plugin-checker/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@artursapek/vite-plugin-checker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@artursapek/vite-plugin-checker/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@artursapek/vite-plugin-checker/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@artursapek/vite-plugin-checker/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@artursapek/vite-plugin-checker/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/@babel/code-frame": { "version": "7.24.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", @@ -18701,11 +18521,10 @@ } }, "node_modules/@wormhole-foundation/wormhole-connect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@wormhole-foundation/wormhole-connect/-/wormhole-connect-1.0.0.tgz", - "integrity": "sha512-OuGtRlWYy31hFhHpK81lvMHHNy1qisySi80gYPEfNj2XHjPLTt2gOggdl6HonHf87JVMDUhbqePfI5yzVZnYBg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@wormhole-foundation/wormhole-connect/-/wormhole-connect-1.1.1.tgz", + "integrity": "sha512-rcuQJnKObZHlgb6sibfZZQxMTo0tgUWWMkp0oHU+HDx/cF1Y2ns4NT2EKfj5uWPQuOc4seCtc5kAzzW/HXNBdQ==", "dependencies": { - "@artursapek/vite-plugin-checker": "^0.7.3", "@coral-xyz/anchor": "^0.29.0", "@cosmjs/cosmwasm-stargate": "^0.31.3", "@cosmjs/stargate": "^0.31.3", @@ -18760,6 +18579,7 @@ "sha3": "^2.1.4", "tss-react": "^4.7.7", "use-debounce": "^9.0.4", + "vite-plugin-checker": "^0.8.0", "web-vitals": "^2.1.4" }, "peerDependencies": { @@ -34832,6 +34652,186 @@ } } }, + "node_modules/vite-plugin-checker": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/vite-plugin-checker/-/vite-plugin-checker-0.8.0.tgz", + "integrity": "sha512-UA5uzOGm97UvZRTdZHiQVYFnd86AVn8EVaD4L3PoVzxH+IZSfaAw14WGFwX9QS23UW3lV/5bVKZn6l0w+q9P0g==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "ansi-escapes": "^4.3.0", + "chalk": "^4.1.1", + "chokidar": "^3.5.1", + "commander": "^8.0.0", + "fast-glob": "^3.2.7", + "fs-extra": "^11.1.0", + "npm-run-path": "^4.0.1", + "strip-ansi": "^6.0.0", + "tiny-invariant": "^1.1.0", + "vscode-languageclient": "^7.0.0", + "vscode-languageserver": "^7.0.0", + "vscode-languageserver-textdocument": "^1.0.1", + "vscode-uri": "^3.0.2" + }, + "engines": { + "node": ">=14.16" + }, + "peerDependencies": { + "@biomejs/biome": ">=1.7", + "eslint": ">=7", + "meow": "^9.0.0", + "optionator": "^0.9.1", + "stylelint": ">=13", + "typescript": "*", + "vite": ">=2.0.0", + "vls": "*", + "vti": "*", + "vue-tsc": "~2.1.6" + }, + "peerDependenciesMeta": { + "@biomejs/biome": { + "optional": true + }, + "eslint": { + "optional": true + }, + "meow": { + "optional": true + }, + "optionator": { + "optional": true + }, + "stylelint": { + "optional": true + }, + "typescript": { + "optional": true + }, + "vls": { + "optional": true + }, + "vti": { + "optional": true + }, + "vue-tsc": { + "optional": true + } + } + }, + "node_modules/vite-plugin-checker/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/vite-plugin-checker/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/vite-plugin-checker/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/vite-plugin-checker/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/vite-plugin-checker/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/vite-plugin-checker/node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/vite-plugin-checker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/vite-plugin-checker/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/vite-plugin-checker/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/vite-plugin-checker/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/vite-plugin-checker/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/vite-plugin-html": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/vite-plugin-html/-/vite-plugin-html-3.2.2.tgz", diff --git a/apps/connect/package.json b/apps/connect/package.json index 54ae54696..753a661f4 100644 --- a/apps/connect/package.json +++ b/apps/connect/package.json @@ -31,7 +31,7 @@ "@mui/material": "^5.12.1", "@tanstack/react-query": "^5.14.2", "@wormhole-foundation/sdk": "^0.10.3", - "@wormhole-foundation/wormhole-connect": "^1.0.0", + "@wormhole-foundation/wormhole-connect": "^1.1.1", "aptos": "^1.21.0", "bech32": "^2.0.0", "dompurify": "^3.0.6", diff --git a/apps/connect/src/hooks/useConnectConfig.ts b/apps/connect/src/hooks/useConnectConfig.ts index cbe21231f..f104c0128 100644 --- a/apps/connect/src/hooks/useConnectConfig.ts +++ b/apps/connect/src/hooks/useConnectConfig.ts @@ -44,9 +44,25 @@ const defaultConfig: WormholeConnectConfig = { export const useConnectConfig = () => { const [networks, setNetworks] = useState(null); - const { txHash, sourceChain, targetChain, asset, requiredNetwork } = - useQueryParams(); - const token = useFormatAssetParam(asset); + const { + txHash, + sourceChain, + targetChain, + sourceToken, + targetToken, + requiredNetwork, + preferredRouteName, + } = useQueryParams(); + const tokenKey = useFormatAssetParam(sourceToken); + const toTokenKey = useFormatAssetParam(targetToken); + const token = useMemo( + () => ({ + tokenKey: tokenKey ?? undefined, + toTokenKey: toTokenKey ?? tokenKey ?? undefined, + }), + [tokenKey, toTokenKey] + ); + const config: WormholeConnectConfig = useMemo( () => ({ ...defaultConfig, @@ -60,12 +76,21 @@ export const useConnectConfig = () => { defaultInputs: { ...(sourceChain && { fromChain: sourceChain }), ...(targetChain && { toChain: targetChain }), - ...(token && { tokenKey: token }), + ...token, ...(requiredNetwork && { requiredChain: requiredNetwork }), + ...(preferredRouteName && { preferredRouteName }), }, }, }), - [networks, txHash, sourceChain, targetChain, token, requiredNetwork] + [ + networks, + txHash, + sourceChain, + targetChain, + token, + requiredNetwork, + preferredRouteName, + ] ); useEffect(() => { diff --git a/apps/connect/src/hooks/useQueryParams.test.ts b/apps/connect/src/hooks/useQueryParams.test.ts index 151893124..f80a0d442 100644 --- a/apps/connect/src/hooks/useQueryParams.test.ts +++ b/apps/connect/src/hooks/useQueryParams.test.ts @@ -17,12 +17,13 @@ describe("useQueryParams", () => { rewriteHref("https://portalbridge.com/"); const { result } = renderHook(() => useQueryParams()); expect(result.current).toEqual({ - asset: null, requiredNetwork: null, sourceChain: null, targetChain: null, txHash: null, - route: null, + preferredRouteName: null, + sourceToken: null, + targetToken: null, }); }); @@ -32,12 +33,13 @@ describe("useQueryParams", () => { ); const { result } = renderHook(() => useQueryParams()); expect(result.current).toEqual({ - asset: "asset", requiredNetwork: "Arbitrum", sourceChain: "Bsc", targetChain: "Arbitrum", txHash: "txHash", - route: "bridge", + preferredRouteName: "bridge", + sourceToken: "asset", + targetToken: null, }); }); @@ -47,12 +49,13 @@ describe("useQueryParams", () => { ); const { result } = renderHook(() => useQueryParams()); expect(result.current).toEqual({ - asset: "asset", requiredNetwork: "Arbitrum", sourceChain: "Bsc", targetChain: "Arbitrum", txHash: "txHash", - route: "bridge", + sourceToken: "asset", + targetToken: null, + preferredRouteName: "bridge", }); }); @@ -60,12 +63,13 @@ describe("useQueryParams", () => { rewriteHref("https://portalbridge.com/#/?transactionId=transactionId"); const { result } = renderHook(() => useQueryParams()); expect(result.current).toEqual({ - asset: null, requiredNetwork: null, sourceChain: null, targetChain: null, txHash: "transactionId", - route: null, + preferredRouteName: null, + sourceToken: null, + targetToken: null, }); }); @@ -75,12 +79,29 @@ describe("useQueryParams", () => { ); const { result } = renderHook(() => useQueryParams()); expect(result.current).toEqual({ - asset: null, requiredNetwork: "Arbitrum", sourceChain: "Bsc", targetChain: "Arbitrum", txHash: null, - route: null, + preferredRouteName: null, + sourceToken: null, + targetToken: null, + }); + }); + + it("should get QS with difference between source and target assets", () => { + rewriteHref( + "https://portalbridge.com/#/?sourceChain=arbitrum&targetChain=ethereum&sourceAsset=USDCarbitrum&targetAsset=USDCeth&route=ManualCCTP" + ); + const { result } = renderHook(() => useQueryParams()); + expect(result.current).toEqual({ + requiredNetwork: null, + sourceChain: "Arbitrum", + targetChain: "Ethereum", + txHash: null, + preferredRouteName: "ManualCCTP", + sourceToken: "USDCarbitrum", + targetToken: "USDCeth", }); }); }); diff --git a/apps/connect/src/hooks/useQueryParams.ts b/apps/connect/src/hooks/useQueryParams.ts index 857219e7e..76edf8e0e 100644 --- a/apps/connect/src/hooks/useQueryParams.ts +++ b/apps/connect/src/hooks/useQueryParams.ts @@ -35,6 +35,10 @@ const getRoute = (query: URLSearchParams): string | null => { return query.get("route") || null; }; +const getPreferredValue = (query: URLSearchParams): string | null => { + return query.get("preferredRouteName") || null; +}; + export const useQueryParams = () => { const query = useMemo( () => @@ -50,11 +54,13 @@ export const useQueryParams = () => { return useMemo( () => ({ txHash: getTxHash(query), + preferredRouteName: getRoute(query) ?? getPreferredValue(query), + sourceToken: + getTokenValue(query, "asset") ?? getTokenValue(query, "sourceAsset"), + targetToken: getTokenValue(query, "targetAsset"), sourceChain: getChainValue(query, "sourceChain"), targetChain: getChainValue(query, "targetChain"), - asset: getTokenValue(query, "asset"), requiredNetwork: getChainValue(query, "requiredNetwork"), - route: getRoute(query), }), [query] ); diff --git a/apps/connect/src/providers/telemetry.test.ts b/apps/connect/src/providers/telemetry.test.ts index e0a3d365b..a88d6c97b 100644 --- a/apps/connect/src/providers/telemetry.test.ts +++ b/apps/connect/src/providers/telemetry.test.ts @@ -28,11 +28,15 @@ describe("telemetry", () => { }, fromToken: { symbol: "WOM", tokenId: "native" }, }, + meta: { version: "version", hash: "hash", host: "host" }, }; }); it("should not track load events", () => { - eventHandler({ type: "load" }); + eventHandler({ + type: "load", + meta: { version: "version", hash: "hash", host: "host" }, + }); expect(mixpanel.track).not.toHaveBeenCalled(); }); @@ -45,12 +49,15 @@ describe("telemetry", () => { chain: "Bsc", wallet: "wallet", }, + meta: { version: "version", hash: "hash", host: "host" }, }); expect(mixpanel.track).toHaveBeenCalledTimes(1); expect(mixpanel.track).toHaveBeenCalledWith("wallet.connect", { "chain-sending": "Bsc", "wallet-sending": "wallet", + connectHash: "hash", + connectVersion: "version", }); }); @@ -69,6 +76,8 @@ describe("telemetry", () => { txId: "txId", amount: 0.0001, USDAmount: 123.456, + connectHash: "hash", + connectVersion: "version", }); }); diff --git a/apps/connect/src/providers/telemetry.ts b/apps/connect/src/providers/telemetry.ts index fc488b844..84c17dd4e 100644 --- a/apps/connect/src/providers/telemetry.ts +++ b/apps/connect/src/providers/telemetry.ts @@ -4,7 +4,12 @@ import type { WormholeConnectConfig } from "@wormhole-foundation/wormhole-connec export type WormholeConnectEvent = Parameters< NonNullable ->[0]; +>[0] & { + meta: { + version: string; + hash: string; + }; +}; mixpanel.init( isProduction @@ -53,6 +58,8 @@ export const eventHandler = (e: WormholeConnectEvent) => { properties: { [`wallet-${side}`]: e.details.wallet, [`chain-${side}`]: e.details.chain, + connectVersion: e.meta.version, + connectHash: e.meta.hash, }, }); } @@ -75,6 +82,8 @@ export const eventHandler = (e: WormholeConnectEvent) => { txId: e.details.txId, USDAmount: e.details.USDAmount, amount: e.details.amount, + connectVersion: e.meta.version, + connectHash: e.meta.hash, route: { ManualTokenBridge: "Manual Bridge", diff --git a/apps/connect/src/theme/connect.ts b/apps/connect/src/theme/connect.ts index da524dd89..6a5fbc42f 100644 --- a/apps/connect/src/theme/connect.ts +++ b/apps/connect/src/theme/connect.ts @@ -1,8 +1,6 @@ -import type { WormholeConnectPartialTheme } from "@wormhole-foundation/wormhole-connect"; +import type { WormholeConnectTheme } from "@wormhole-foundation/wormhole-connect"; -export const theme: WormholeConnectPartialTheme = { - background: { - default: "rgba(12, 9, 60, 0)", - badge: "rgb(15, 9, 44)", - }, +export const theme: WormholeConnectTheme = { + mode: "dark", + badge: "rgb(15, 9, 44)", }; diff --git a/apps/docs/docs/tutorials/how-to-deep-link.md b/apps/docs/docs/tutorials/how-to-deep-link.md index 297029939..d4a0b0ddb 100644 --- a/apps/docs/docs/tutorials/how-to-deep-link.md +++ b/apps/docs/docs/tutorials/how-to-deep-link.md @@ -3,6 +3,51 @@ sidebar_position: 6 --- # Deep link to Portal Bridge +> Note: This feature could work differently between the different bridge versions than +> what Portal Bridge currently offers. The documentation presented here works on https://portalbridge.com + +## Pre-select Assets and Preferred route + +|Query Parameter | Description | +|---|---|---| +|`sourceChain` |A source chain that will be pre-selected | +|`targetChain` |A target chain that will be pre-selected | +|`sourceAsset` or `asset` |It will be the key of an asset that is injected in configs, you could check [here](https://github.com/XLabs/portal-bridge-ui/blob/main/apps/connect/src/env/token-bridge.mainnet.ts#L505)| +|`targetAsset` |this could be useful for routes that offer swaps| +|`route` or `preferredRouteName` |the route names, check below| + +#### Routes + +> Note if the preferred route does not support the given tokens, +> it will fall back to the fastest available option. + +##### Mayan +- to prefer Mayan route, the value must be `MayanSwapWH` +- to prefer Mayan Swift route, the value must be `MayanSwapSWIFT` +- to prefer Mayan MCTP route, the value must be `MayanSwapMCTP` + + +##### CCTP +- to prefer CCTP Manual route, the value must be `ManualCCTP` +- to prefer CCTP Automatic, the value must be `AutomaticCCTP` + +##### Token Bridge +- to prefer Token Bridge Manual route, the value must be `ManualTokenBridge` +- to prefer Token Bridge Automatic route, the value must be `AutomaticTokenBridge` + + +##### NTT +- to prefer NTT Manual route, the value must be `ManualNtt` +- to prefer NTT Automatic route, the value must be `AutomaticNtt` + +#### Examples + +You can set a preferred route to bridge the assets by using the query param: `route` + +- https://portalbridge.com/?sourceChain=arbitrum&targetChain=ethereum&sourceAsset=USDCarbitrum&targetAsset=USDCeth&route=ManualCCTP + +- https://portalbridge.com/?sourceChain=ethereum&targetChain=bsc&sourceAsset=wstETH&targetAsset=wstETHBsc&route=AutomacticNtt + ## Transfer What if I want to share a link on social media or to a friend, and I want a pre-selection of **source-chain** and **target-chain**? @@ -107,4 +152,4 @@ Examples: #### What about ids? -you could use the same logic as [What about ids?](#what-about-ids) \ No newline at end of file +you could use the same logic as [What about ids?](#what-about-ids)