diff --git a/apps/canonical-bridge-ui/token-config/mainnet/stargate/config.json b/apps/canonical-bridge-ui/token-config/mainnet/stargate/config.json index fbcb4237..a9efa181 100644 --- a/apps/canonical-bridge-ui/token-config/mainnet/stargate/config.json +++ b/apps/canonical-bridge-ui/token-config/mainnet/stargate/config.json @@ -367,7 +367,7 @@ "address": "0x19e26B0638bf63aa9fa4d14c6baF8D52eBE86C5C", "bridgeAddress": "0x77C71633C34C3784ede189d74223122422492a0f", "decimals": 6, - "symbol": "USDC", + "symbol": "USDC.e", "type": "hydra", "endpointID": 30290, "name": "USD Coin" @@ -407,7 +407,7 @@ "address": "0x06efdbff2a14a7c8e15944d1f4a48f9f95f663a4", "bridgeAddress": "0x3Fc69CC4A842838bCDC9499178740226062b14E4", "decimals": 6, - "symbol": "USDC.e", + "symbol": "USDC", "endpointID": 30214, "name": "USD Coin" }, diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index d6031cf5..7a6f5d05 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -247,6 +247,10 @@ importers: version: 5.5.4 ../../packages/canonical-bridge-sdk: + dependencies: + '@types/jest': + specifier: ~29.5.14 + version: 29.5.14 devDependencies: '@types/react': specifier: ^18 @@ -260,6 +264,9 @@ importers: axios: specifier: ~0.27.2 version: 0.27.2 + jest: + specifier: ~29.7.0 + version: 29.7.0(@types/node@22.7.5)(babel-plugin-macros@3.1.0) react: specifier: ~18.3.1 version: 18.3.1 @@ -269,6 +276,9 @@ importers: rollup-plugin-peer-deps-external: specifier: ^2.2.4 version: 2.2.4(rollup@3.29.5) + ts-jest: + specifier: ~29.2.5 + version: 29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.7.5)(babel-plugin-macros@3.1.0))(typescript@5.5.4) typescript: specifier: ^5 version: 5.5.4 @@ -844,6 +854,27 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-static-block@7.14.5': + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-decorators@7.25.9': resolution: {integrity: sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==} engines: {node: '>=6.9.0'} @@ -873,6 +904,16 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-jsx@7.12.1': resolution: {integrity: sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==} peerDependencies: @@ -884,6 +925,11 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: @@ -899,6 +945,11 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-optional-chaining@7.8.3': resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: @@ -910,6 +961,12 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-typescript@7.25.9': resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} engines: {node: '>=6.9.0'} @@ -2415,14 +2472,80 @@ packages: resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} engines: {node: '>=8'} + '@jest/console@29.7.0': + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/core@29.7.0': + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/environment@29.7.0': + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect@29.7.0': + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/fake-timers@29.7.0': + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/globals@29.7.0': + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/reporters@29.7.0': + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/source-map@29.6.3': + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-result@29.7.0': + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-sequencer@29.7.0': + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/transform@26.6.2': resolution: {integrity: sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==} engines: {node: '>= 10.14.2'} + '@jest/transform@29.7.0': + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/types@26.6.2': resolution: {integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==} engines: {node: '>= 10.14.2'} + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jnwng/walletconnect-solana@0.2.0': resolution: {integrity: sha512-nyRq0xLEj9i2J4UXQ0Mr4KzsooTMbLu0ewHOqdQV7iZE0PfbtKa8poTSF4ZBAQD8hoMHEx+I7zGFCNMI9BTrTA==} peerDependencies: @@ -3265,9 +3388,18 @@ packages: '@scure/bip39@1.4.0': resolution: {integrity: sha512-BEEm6p8IueV/ZTfQLp/0vhw4NPnT9oWf5+28nvmeUICjP99f4vr2d+qc7AVGDDtwRep6ifR43Yed9ERVmiITzw==} + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + '@sinclair/typebox@0.33.22': resolution: {integrity: sha512-auUj4k+f4pyrIVf4GW5UKquSZFHJWri06QgARy9C0t9ZTjJLIuNIrr1yl9bWcJWJ1Gz1vOvYN1D+QPaIlNMVkQ==} + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@10.3.0': + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} @@ -4367,6 +4499,9 @@ packages: '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/jest@29.5.14': + resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -4457,6 +4592,9 @@ packages: '@types/source-list-map@0.1.6': resolution: {integrity: sha512-5JcVt1u5HDmlXkwOD2nslZVllBBc7HDuOICfiZah2Z0is8M8g+ddAEawbmd3VjedfDHBzxCaXLs07QEmb7y54g==} + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/tapable@1.0.12': resolution: {integrity: sha512-bTHG8fcxEqv1M9+TD14P8ok8hjxoOCkfKc8XXLaaD05kI7ohpeI956jtDOD3XHKBQrlyPughUtzm1jtVhHpA5Q==} @@ -4502,6 +4640,9 @@ packages: '@types/yargs@15.0.19': resolution: {integrity: sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==} + '@types/yargs@17.0.33': + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@typescript-eslint/eslint-plugin@5.57.1': resolution: {integrity: sha512-1MeobQkQ9tztuleT3v72XmY0XuKXVXusAhryoLuU5YZ+mXoYKZP9SQ7Flulh1NX4DTjpGTc2b/eMu4u7M7dhnQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -5164,6 +5305,10 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} @@ -5326,6 +5471,9 @@ packages: async-mutex@0.4.1: resolution: {integrity: sha512-WfoBo4E/TbCX1G95XTjbWTE3X2XLG0m1Xbv2cwOtuPdyH9CZvnaA5nCt1ucjaKEgW2A5IF71hxrRhr83Je5xjA==} + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -5367,6 +5515,12 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + babel-jest@29.7.0: + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + babel-loader@8.4.1: resolution: {integrity: sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==} engines: {node: '>= 8.9'} @@ -5389,6 +5543,10 @@ packages: resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} engines: {node: '>=8'} + babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-plugin-macros@3.1.0: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} engines: {node: '>=10', npm: '>=6'} @@ -5422,6 +5580,17 @@ packages: babel-plugin-transform-react-remove-prop-types@0.4.24: resolution: {integrity: sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==} + babel-preset-current-node-syntax@1.1.0: + resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} + peerDependencies: + '@babel/core': ^7.0.0 + + babel-preset-jest@29.6.3: + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + babel-preset-react-app@10.0.1: resolution: {integrity: sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg==} @@ -5593,6 +5762,10 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + bs58@4.0.1: resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} @@ -5744,6 +5917,10 @@ packages: resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + character-entities-legacy@1.1.4: resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} @@ -5781,6 +5958,10 @@ packages: ci-info@2.0.0: resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + cipher-base@1.0.5: resolution: {integrity: sha512-xq7ICKB4TMHUx7Tz1L9O2SGKOhYMOTR32oir45Bq28/AQTpHogKgHcoYFSdRbMtddl+ozNXfXY9jWcgYKmde0w==} engines: {node: '>= 0.10'} @@ -5788,6 +5969,9 @@ packages: citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + cjs-module-lexer@1.4.1: + resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==} + class-utils@0.3.6: resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} engines: {node: '>=0.10.0'} @@ -5852,6 +6036,10 @@ packages: cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + clone-deep@4.0.1: resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} engines: {node: '>=6'} @@ -5868,9 +6056,16 @@ packages: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + collapse-white-space@1.0.6: resolution: {integrity: sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==} + collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + collection-visit@1.0.0: resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} engines: {node: '>=0.10.0'} @@ -6083,6 +6278,11 @@ packages: create-hmac@1.1.7: resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + create-jest@29.7.0: + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + cron-parser@4.9.0: resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==} engines: {node: '>=12.0.0'} @@ -6209,6 +6409,14 @@ packages: dedent@0.7.0: resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} + dedent@1.5.3: + resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -6298,6 +6506,10 @@ packages: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} @@ -6310,6 +6522,10 @@ packages: engines: {node: '>= 4.0.0'} hasBin: true + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + diffie-hellman@5.0.3: resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} @@ -6399,6 +6615,11 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + electron-to-chromium@1.5.63: resolution: {integrity: sha512-ddeXKuY9BHo/mw145axlyWjlJ1UBt4WK3AlvkT7W2AbqfRQoacVoRUCF6wL3uIx/8wT9oLKXzI+rFqHHscByaA==} @@ -6414,6 +6635,10 @@ packages: elliptic@6.6.1: resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} + emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + emoji-regex@7.0.3: resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==} @@ -6863,10 +7088,18 @@ packages: exenv@1.2.2: resolution: {integrity: sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==} + exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + expand-brackets@2.1.4: resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} engines: {node: '>=0.10.0'} + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + express-prom-bundle@7.0.2: resolution: {integrity: sha512-ffFV4HGHvCKnkNJFqm42sYztRJE5mLgOj8MpGey1HOatuFhtcwXoBD2m5gca7ZbcyjkIf7lOH5ZdrhlrBf0sGw==} engines: {node: '>=18'} @@ -6982,6 +7215,9 @@ packages: file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + fill-range@4.0.0: resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} engines: {node: '>=0.10.0'} @@ -7551,6 +7787,11 @@ packages: resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} engines: {node: '>=8'} + import-local@3.2.0: + resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} + engines: {node: '>=8'} + hasBin: true + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -7759,6 +8000,10 @@ packages: is-function@1.0.2: resolution: {integrity: sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==} + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + is-generator-function@1.0.10: resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} engines: {node: '>= 0.4'} @@ -7954,10 +8199,18 @@ packages: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} + istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} + istanbul-lib-report@3.0.1: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} + istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + istanbul-reports@3.1.7: resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} engines: {node: '>=8'} @@ -7983,27 +8236,147 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jake@10.9.2: + resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} + engines: {node: '>=10'} + hasBin: true + jayson@4.1.2: resolution: {integrity: sha512-5nzMWDHy6f+koZOuYsArh2AXs73NfWYVlFyJJuCedr93GpY+Ku8qq10ropSXVfHK+H0T6paA88ww+/dV+1fBNA==} engines: {node: '>=8'} hasBin: true + jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-cli@29.7.0: + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@29.7.0: + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-haste-map@26.6.2: resolution: {integrity: sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==} engines: {node: '>= 10.14.2'} + jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + jest-regex-util@26.0.0: resolution: {integrity: sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==} engines: {node: '>= 10.14.2'} + jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-serializer@26.6.2: resolution: {integrity: sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==} engines: {node: '>= 10.14.2'} + jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-util@26.6.2: resolution: {integrity: sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==} engines: {node: '>= 10.14.2'} + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-worker@26.6.2: resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} engines: {node: '>= 10.13.0'} @@ -8012,6 +8385,20 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest@29.7.0: + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + jiti@2.4.0: resolution: {integrity: sha512-H5UpaUI+aHOqZXlYOaFP/8AzKsg+guWu+Pr3Y8i7+Y3zr1aXAvCvTAQ1RxSc6oVD8R8c7brgNtTVP91E7upH/g==} hasBin: true @@ -8173,6 +8560,10 @@ packages: resolution: {integrity: sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ==} engines: {node: '>=6.0.0', npm: '>=6.0.0', yarn: '>=1.0.0'} + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -8282,6 +8673,9 @@ packages: lodash.isequal@4.5.0: resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -8363,6 +8757,9 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} @@ -8532,6 +8929,10 @@ packages: minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + minimatch@9.0.3: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} engines: {node: '>=16 || 14 >=14.17'} @@ -9320,6 +9721,10 @@ packages: pretty-error@4.0.0: resolution: {integrity: sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==} + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + pretty-hrtime@1.0.3: resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} engines: {node: '>= 0.8'} @@ -9412,6 +9817,9 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + pushdata-bitcoin@1.0.1: resolution: {integrity: sha512-hw7rcYTJRAl4olM8Owe8x0fBuJJ+WGbMhQuLWOXEMN3PxPCKQHRkhfL+XG0+iXUmSHjkMmb3Ba55Mt21cZc9kQ==} @@ -9564,6 +9972,9 @@ packages: react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-lifecycles-compat@3.0.4: resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==} @@ -9809,6 +10220,10 @@ packages: require-main-filename@2.0.0: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -9824,6 +10239,10 @@ packages: resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} deprecated: https://github.com/lydell/resolve-url#deprecated + resolve.exports@2.0.3: + resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} + engines: {node: '>=10'} + resolve@1.19.0: resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} @@ -10168,6 +10587,9 @@ packages: resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} deprecated: See https://github.com/lydell/source-map-resolve#deprecated + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} @@ -10231,6 +10653,10 @@ packages: resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==} deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility' + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + stackframe@1.3.4: resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} @@ -10285,6 +10711,10 @@ packages: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + string-natural-compare@3.0.1: resolution: {integrity: sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==} @@ -10360,6 +10790,10 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + strip-eof@1.0.0: resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==} engines: {node: '>=0.10.0'} @@ -10629,6 +11063,30 @@ packages: resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} engines: {node: '>=6.10'} + ts-jest@29.2.5: + resolution: {integrity: sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==} + engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/transform': ^29.0.0 + '@jest/types': ^29.0.0 + babel-jest: ^29.0.0 + esbuild: '*' + jest: ^29.0.0 + typescript: '>=4.3 <6' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/transform': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + ts-mixer@6.0.4: resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==} @@ -10689,6 +11147,10 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} @@ -11357,6 +11819,10 @@ packages: write-file-atomic@3.0.3: resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} + write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + ws@7.4.6: resolution: {integrity: sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==} engines: {node: '>=8.3.0'} @@ -11469,6 +11935,10 @@ packages: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -11951,7 +12421,7 @@ snapshots: '@babel/plugin-proposal-object-rest-spread@7.12.1(@babel/core@7.12.9)': dependencies: '@babel/core': 7.12.9 - '@babel/helper-plugin-utils': 7.10.4 + '@babel/helper-plugin-utils': 7.25.9 '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.12.9) '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.12.9) @@ -11999,6 +12469,26 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-decorators@7.25.9(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -12034,6 +12524,16 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-jsx@7.12.1(@babel/core@7.12.9)': dependencies: '@babel/core': 7.12.9 @@ -12049,6 +12549,11 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -12069,6 +12574,11 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.0)': dependencies: '@babel/core': 7.26.0 @@ -12079,6 +12589,11 @@ snapshots: '@babel/core': 7.26.0 '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0(supports-color@9.4.0))': dependencies: '@babel/core': 7.26.0(supports-color@9.4.0) @@ -14516,34 +15031,196 @@ snapshots: '@istanbuljs/schema@0.1.3': {} - '@jest/transform@26.6.2': + '@jest/console@29.7.0': dependencies: - '@babel/core': 7.26.0 - '@jest/types': 26.6.2 - babel-plugin-istanbul: 6.1.1 + '@jest/types': 29.6.3 + '@types/node': 20.17.6 chalk: 4.1.2 - convert-source-map: 1.9.0 - fast-json-stable-stringify: 2.1.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + + '@jest/core@29.7.0(babel-plugin-macros@3.1.0)': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.17.6 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 graceful-fs: 4.2.11 - jest-haste-map: 26.6.2 - jest-regex-util: 26.0.0 - jest-util: 26.6.2 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.17.6)(babel-plugin-macros@3.1.0) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 micromatch: 4.0.8 - pirates: 4.0.6 + pretty-format: 29.7.0 slash: 3.0.0 - source-map: 0.6.1 - write-file-atomic: 3.0.3 + strip-ansi: 6.0.1 transitivePeerDependencies: + - babel-plugin-macros - supports-color + - ts-node - '@jest/types@26.6.2': + '@jest/environment@29.7.0': dependencies: - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 3.0.4 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.17.6 + jest-mock: 29.7.0 + + '@jest/expect-utils@29.7.0': + dependencies: + jest-get-type: 29.6.3 + + '@jest/expect@29.7.0': + dependencies: + expect: 29.7.0 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + '@jest/fake-timers@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 20.17.6 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + '@jest/globals@29.7.0': + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/types': 29.6.3 + jest-mock: 29.7.0 + transitivePeerDependencies: + - supports-color + + '@jest/reporters@29.7.0': + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + '@types/node': 20.17.6 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.7 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.8 + + '@jest/source-map@29.6.3': + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + '@jest/test-result@29.7.0': + dependencies: + '@jest/console': 29.7.0 + '@jest/types': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.2 + + '@jest/test-sequencer@29.7.0': + dependencies: + '@jest/test-result': 29.7.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + + '@jest/transform@26.6.2': + dependencies: + '@babel/core': 7.26.0 + '@jest/types': 26.6.2 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 1.9.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 26.6.2 + jest-regex-util: 26.0.0 + jest-util: 26.6.2 + micromatch: 4.0.8 + pirates: 4.0.6 + slash: 3.0.0 + source-map: 0.6.1 + write-file-atomic: 3.0.3 + transitivePeerDependencies: + - supports-color + + '@jest/transform@29.7.0': + dependencies: + '@babel/core': 7.26.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.8 + pirates: 4.0.6 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + + '@jest/types@26.6.2': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 '@types/node': 20.17.6 '@types/yargs': 15.0.19 chalk: 4.1.2 + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 20.17.6 + '@types/yargs': 17.0.33 + chalk: 4.1.2 + '@jnwng/walletconnect-solana@0.2.0(@react-native-async-storage/async-storage@1.24.0)(@solana/web3.js@1.95.4(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(bufferutil@4.0.8)(ioredis@5.4.1(supports-color@9.4.0))(utf-8-validate@5.0.10)': dependencies: '@solana/web3.js': 1.95.4(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) @@ -15606,8 +16283,18 @@ snapshots: '@noble/hashes': 1.5.0 '@scure/base': 1.1.9 + '@sinclair/typebox@0.27.8': {} + '@sinclair/typebox@0.33.22': {} + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@10.3.0': + dependencies: + '@sinonjs/commons': 3.0.1 + '@socket.io/component-emitter@3.1.2': {} '@solana-mobile/mobile-wallet-adapter-protocol-web3js@2.1.4(@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.95.4(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10)))(@solana/web3.js@1.95.4(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10))(react@18.3.1)': @@ -17793,6 +18480,11 @@ snapshots: dependencies: '@types/istanbul-lib-report': 3.0.3 + '@types/jest@29.5.14': + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -17882,6 +18574,8 @@ snapshots: '@types/source-list-map@0.1.6': {} + '@types/stack-utils@2.0.3': {} + '@types/tapable@1.0.12': {} '@types/tough-cookie@4.0.5': {} @@ -17931,6 +18625,10 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 + '@types/yargs@17.0.33': + dependencies: + '@types/yargs-parser': 21.0.3 + '@typescript-eslint/eslint-plugin@5.57.1(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -19222,6 +19920,8 @@ snapshots: dependencies: color-convert: 2.0.1 + ansi-styles@5.2.0: {} + ansi-styles@6.2.1: {} ansi-to-html@0.6.15: @@ -19412,6 +20112,8 @@ snapshots: dependencies: tslib: 2.8.1 + async@3.2.6: {} + asynckit@0.4.0: {} at-least-node@1.0.0: {} @@ -19461,6 +20163,19 @@ snapshots: axobject-query@4.1.0: {} + babel-jest@29.7.0(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.26.0) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + babel-loader@8.4.1(@babel/core@7.26.0)(webpack@4.47.0): dependencies: '@babel/core': 7.26.0 @@ -19501,6 +20216,13 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-jest-hoist@29.6.3: + dependencies: + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.20.6 + babel-plugin-macros@3.1.0: dependencies: '@babel/runtime': 7.26.0 @@ -19575,6 +20297,31 @@ snapshots: babel-plugin-transform-react-remove-prop-types@0.4.24: {} + babel-preset-current-node-syntax@1.1.0(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.26.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.26.0) + '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.26.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.26.0) + + babel-preset-jest@29.6.3(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0) + babel-preset-react-app@10.0.1: dependencies: '@babel/core': 7.26.0 @@ -19811,6 +20558,10 @@ snapshots: node-releases: 2.0.18 update-browserslist-db: 1.1.1(browserslist@4.24.2) + bs-logger@0.2.6: + dependencies: + fast-json-stable-stringify: 2.1.0 + bs58@4.0.1: dependencies: base-x: 3.0.10 @@ -20033,6 +20784,8 @@ snapshots: chalk@5.3.0: {} + char-regex@1.0.2: {} + character-entities-legacy@1.1.4: {} character-entities@1.2.4: {} @@ -20080,6 +20833,8 @@ snapshots: ci-info@2.0.0: {} + ci-info@3.9.0: {} + cipher-base@1.0.5: dependencies: inherits: 2.0.4 @@ -20089,6 +20844,8 @@ snapshots: dependencies: consola: 3.2.3 + cjs-module-lexer@1.4.1: {} + class-utils@0.3.6: dependencies: arr-union: 3.1.0 @@ -20160,6 +20917,12 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + clone-deep@4.0.1: dependencies: is-plain-object: 2.0.4 @@ -20172,8 +20935,12 @@ snapshots: cluster-key-slot@1.1.2: {} + co@4.6.0: {} + collapse-white-space@1.0.6: {} + collect-v8-coverage@1.0.2: {} + collection-visit@1.0.0: dependencies: map-visit: 1.0.0 @@ -20398,6 +21165,21 @@ snapshots: safe-buffer: 5.2.1 sha.js: 2.4.11 + create-jest@29.7.0(@types/node@22.7.5)(babel-plugin-macros@3.1.0): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@22.7.5)(babel-plugin-macros@3.1.0) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + cron-parser@4.9.0: dependencies: luxon: 3.5.0 @@ -20565,6 +21347,10 @@ snapshots: dedent@0.7.0: {} + dedent@1.5.3(babel-plugin-macros@3.1.0): + optionalDependencies: + babel-plugin-macros: 3.1.0 + deep-is@0.1.4: {} deepmerge@4.3.1: {} @@ -20641,6 +21427,8 @@ snapshots: detect-libc@2.0.3: optional: true + detect-newline@3.1.0: {} + detect-node-es@1.1.0: {} detect-package-manager@2.0.1: @@ -20654,6 +21442,8 @@ snapshots: transitivePeerDependencies: - supports-color + diff-sequences@29.6.3: {} + diffie-hellman@5.0.3: dependencies: bn.js: 4.12.1 @@ -20759,6 +21549,10 @@ snapshots: ee-first@1.1.1: {} + ejs@3.1.10: + dependencies: + jake: 10.9.2 + electron-to-chromium@1.5.63: {} element-resize-detector@1.2.4: @@ -20795,6 +21589,8 @@ snapshots: minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 + emittery@0.13.1: {} + emoji-regex@7.0.3: {} emoji-regex@8.0.0: {} @@ -21691,6 +22487,8 @@ snapshots: exenv@1.2.2: {} + exit@0.1.2: {} + expand-brackets@2.1.4: dependencies: debug: 2.6.9 @@ -21701,6 +22499,14 @@ snapshots: snapdragon: 0.8.2 to-regex: 3.0.2 + expect@29.7.0: + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + express-prom-bundle@7.0.2(prom-client@15.1.3): dependencies: '@types/express': 4.17.21 @@ -21856,6 +22662,10 @@ snapshots: file-uri-to-path@1.0.0: {} + filelist@1.0.4: + dependencies: + minimatch: 5.1.6 + fill-range@4.0.0: dependencies: extend-shallow: 2.0.1 @@ -22552,6 +23362,11 @@ snapshots: import-lazy@4.0.0: {} + import-local@3.2.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + imurmurhash@0.1.4: {} indent-string@2.1.0: @@ -22777,6 +23592,8 @@ snapshots: is-function@1.0.2: {} + is-generator-fn@2.1.0: {} + is-generator-function@1.0.10: dependencies: has-tostringtag: 1.0.2 @@ -22938,12 +23755,30 @@ snapshots: transitivePeerDependencies: - supports-color + istanbul-lib-instrument@6.0.3: + dependencies: + '@babel/core': 7.26.0 + '@babel/parser': 7.26.2 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.6.3 + transitivePeerDependencies: + - supports-color + istanbul-lib-report@3.0.1: dependencies: istanbul-lib-coverage: 3.2.2 make-dir: 4.0.0 supports-color: 7.2.0 + istanbul-lib-source-maps@4.0.1: + dependencies: + debug: 4.3.7(supports-color@9.4.0) + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + istanbul-reports@3.1.7: dependencies: html-escaper: 2.0.2 @@ -22978,6 +23813,13 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jake@10.9.2: + dependencies: + async: 3.2.6 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + jayson@4.1.2(bufferutil@4.0.8)(utf-8-validate@5.0.10): dependencies: '@types/connect': 3.4.38 @@ -22996,6 +23838,147 @@ snapshots: - bufferutil - utf-8-validate + jest-changed-files@29.7.0: + dependencies: + execa: 5.1.1 + jest-util: 29.7.0 + p-limit: 3.1.0 + + jest-circus@29.7.0(babel-plugin-macros@3.1.0): + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.17.6 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.5.3(babel-plugin-macros@3.1.0) + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.1.0 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-cli@29.7.0(@types/node@22.7.5)(babel-plugin-macros@3.1.0): + dependencies: + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@22.7.5)(babel-plugin-macros@3.1.0) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@22.7.5)(babel-plugin-macros@3.1.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + jest-config@29.7.0(@types/node@20.17.6)(babel-plugin-macros@3.1.0): + dependencies: + '@babel/core': 7.26.0 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.0) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.17.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-config@29.7.0(@types/node@22.7.5)(babel-plugin-macros@3.1.0): + dependencies: + '@babel/core': 7.26.0 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.0) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.7.5 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-diff@29.7.0: + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-docblock@29.7.0: + dependencies: + detect-newline: 3.1.0 + + jest-each@29.7.0: + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + jest-get-type: 29.6.3 + jest-util: 29.7.0 + pretty-format: 29.7.0 + + jest-environment-node@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.17.6 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + jest-get-type@29.6.3: {} + jest-haste-map@26.6.2: dependencies: '@jest/types': 26.6.2 @@ -23014,13 +23997,162 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + jest-haste-map@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 20.17.6 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.8 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-leak-detector@29.7.0: + dependencies: + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-matcher-utils@29.7.0: + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-message-util@29.7.0: + dependencies: + '@babel/code-frame': 7.26.2 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.17.6 + jest-util: 29.7.0 + + jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + optionalDependencies: + jest-resolve: 29.7.0 + jest-regex-util@26.0.0: {} + jest-regex-util@29.6.3: {} + + jest-resolve-dependencies@29.7.0: + dependencies: + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + jest-resolve@29.7.0: + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + resolve: 1.22.8 + resolve.exports: 2.0.3 + slash: 3.0.0 + + jest-runner@29.7.0: + dependencies: + '@jest/console': 29.7.0 + '@jest/environment': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.17.6 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.11 + jest-docblock: 29.7.0 + jest-environment-node: 29.7.0 + jest-haste-map: 29.7.0 + jest-leak-detector: 29.7.0 + jest-message-util: 29.7.0 + jest-resolve: 29.7.0 + jest-runtime: 29.7.0 + jest-util: 29.7.0 + jest-watcher: 29.7.0 + jest-worker: 29.7.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + + jest-runtime@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/globals': 29.7.0 + '@jest/source-map': 29.6.3 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.17.6 + chalk: 4.1.2 + cjs-module-lexer: 1.4.1 + collect-v8-coverage: 1.0.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + jest-serializer@26.6.2: dependencies: '@types/node': 20.17.6 graceful-fs: 4.2.11 + jest-snapshot@29.7.0: + dependencies: + '@babel/core': 7.26.0 + '@babel/generator': 7.26.2 + '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) + '@babel/types': 7.26.0 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0) + chalk: 4.1.2 + expect: 29.7.0 + graceful-fs: 4.2.11 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + natural-compare: 1.4.0 + pretty-format: 29.7.0 + semver: 7.6.3 + transitivePeerDependencies: + - supports-color + jest-util@26.6.2: dependencies: '@jest/types': 26.6.2 @@ -23030,6 +24162,35 @@ snapshots: is-ci: 2.0.0 micromatch: 4.0.8 + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.17.6 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + jest-validate@29.7.0: + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + + jest-watcher@29.7.0: + dependencies: + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.17.6 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 29.7.0 + string-length: 4.0.2 + jest-worker@26.6.2: dependencies: '@types/node': 20.17.6 @@ -23042,6 +24203,25 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 + jest-worker@29.7.0: + dependencies: + '@types/node': 20.17.6 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest@29.7.0(@types/node@22.7.5)(babel-plugin-macros@3.1.0): + dependencies: + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@22.7.5)(babel-plugin-macros@3.1.0) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jiti@2.4.0: {} jju@1.4.0: {} @@ -23178,6 +24358,8 @@ snapshots: dotenv: 8.6.0 dotenv-expand: 5.1.0 + leven@3.1.0: {} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -23337,6 +24519,8 @@ snapshots: lodash.isequal@4.5.0: {} + lodash.memoize@4.1.2: {} + lodash.merge@4.6.2: {} lodash.mergewith@4.6.2: {} @@ -23417,6 +24601,8 @@ snapshots: dependencies: semver: 7.6.3 + make-error@1.3.6: {} + makeerror@1.0.12: dependencies: tmpl: 1.0.5 @@ -23591,6 +24777,10 @@ snapshots: dependencies: brace-expansion: 1.1.11 + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + minimatch@9.0.3: dependencies: brace-expansion: 2.0.1 @@ -24449,6 +25639,12 @@ snapshots: lodash: 4.17.21 renderkid: 3.0.0 + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + pretty-hrtime@1.0.3: {} prisma@5.19.1: @@ -24563,6 +25759,8 @@ snapshots: punycode@2.3.1: {} + pure-rand@6.1.0: {} + pushdata-bitcoin@1.0.1: dependencies: bitcoin-ops: 1.4.1 @@ -24745,6 +25943,8 @@ snapshots: react-is@17.0.2: {} + react-is@18.3.1: {} + react-lifecycles-compat@3.0.4: {} react-modal@3.16.1(react-dom@16.13.1(react@16.13.1))(react@16.13.1): @@ -25081,6 +26281,10 @@ snapshots: require-main-filename@2.0.0: {} + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + resolve-from@4.0.0: {} resolve-from@5.0.0: {} @@ -25089,6 +26293,8 @@ snapshots: resolve-url@0.2.1: {} + resolve.exports@2.0.3: {} + resolve@1.19.0: dependencies: is-core-module: 2.15.1 @@ -25526,6 +26732,11 @@ snapshots: source-map-url: 0.4.1 urix: 0.1.0 + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 @@ -25577,6 +26788,10 @@ snapshots: stable@0.1.8: {} + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + stackframe@1.3.4: {} standard-as-callback@2.1.0: {} @@ -25629,6 +26844,11 @@ snapshots: string-argv@0.3.2: {} + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + string-natural-compare@3.0.1: {} string-width@3.1.0: @@ -25739,6 +26959,8 @@ snapshots: strip-bom@3.0.0: {} + strip-bom@4.0.0: {} + strip-eof@1.0.0: {} strip-final-newline@2.0.0: {} @@ -26012,6 +27234,25 @@ snapshots: ts-dedent@2.2.0: {} + ts-jest@29.2.5(@babel/core@7.26.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.0))(jest@29.7.0(@types/node@22.7.5)(babel-plugin-macros@3.1.0))(typescript@5.5.4): + dependencies: + bs-logger: 0.2.6 + ejs: 3.1.10 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@22.7.5)(babel-plugin-macros@3.1.0) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.6.3 + typescript: 5.5.4 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.26.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.0) + ts-mixer@6.0.4: {} ts-pnp@1.2.0(typescript@5.5.4): @@ -26074,6 +27315,8 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-detect@4.0.8: {} + type-fest@0.20.2: {} type-fest@0.21.3: {} @@ -26842,6 +28085,11 @@ snapshots: signal-exit: 3.0.7 typedarray-to-buffer: 3.1.5 + write-file-atomic@4.0.2: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + ws@7.4.6(bufferutil@4.0.8)(utf-8-validate@5.0.10): optionalDependencies: bufferutil: 4.0.8 @@ -26935,6 +28183,16 @@ snapshots: y18n: 5.0.8 yargs-parser: 20.2.9 + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + yocto-queue@0.1.0: {} z-schema@5.0.5: diff --git a/packages/canonical-bridge-sdk/__tests__/cbridge/index.test.ts b/packages/canonical-bridge-sdk/__tests__/cbridge/index.test.ts new file mode 100644 index 00000000..d0f8af3c --- /dev/null +++ b/packages/canonical-bridge-sdk/__tests__/cbridge/index.test.ts @@ -0,0 +1,579 @@ +import { CBridge } from '../../src/cbridge'; +declare global { + interface BigInt { + toJSON(): Number; + } +} + +BigInt.prototype.toJSON = function () { + return Number(this); +}; + +describe('cBridge', () => { + let bridge: CBridge; + + beforeEach(() => { + bridge = new CBridge({ + endpoint: 'http://localhost:3000', + timeout: 30 * 1000, + bridgeType: 'cBridge', + }); + }); + // === pegged transfer test === + it('Test 1: cBridge validation with wrong bridge address', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: true, + fromChainId: 56, + fromTokenAddress: '0xA9b038285F43cD6fE9E16B4C80B4B9bCcd3C161b', + fromTokenSymbol: 'AI', + bridgeAddress: '0x89b8AA89FDd0507a99d334CBe3C808fAFC7d850E', // wrong address + toChainId: 42161, + toTokenAddress: '0x8d7c2588c365b9e98Ea464b63DBCCDf13ECd9809', + toTokenSymbol: 'AI', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 18, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 2: cBridge validation with wrong from token decimals', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: true, + fromChainId: 56, + fromTokenAddress: '0xA9b038285F43cD6fE9E16B4C80B4B9bCcd3C161b', + fromTokenSymbol: 'AI', + fromTokenDecimals: 12, + bridgeAddress: '0x11a0c9270D88C99e221360BCA50c2f6Fda44A980', + toChainId: 42161, + toTokenAddress: '0x8d7c2588c365b9e98Ea464b63DBCCDf13ECd9809', + toTokenSymbol: 'AI', + amount: 20.1, + toTokenDecimals: 18, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 3: cBridge validation with wrong from token symbol', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: true, + fromChainId: 56, + fromTokenAddress: '0xA9b038285F43cD6fE9E16B4C80B4B9bCcd3C161b', + fromTokenSymbol: 'AIX', + bridgeAddress: '0x11a0c9270D88C99e221360BCA50c2f6Fda44A980', + toChainId: 42161, + toTokenAddress: '0x8d7c2588c365b9e98Ea464b63DBCCDf13ECd9809', + toTokenSymbol: 'AI', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 18, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 4: cBridge validation with wrong from token address', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: true, + fromChainId: 56, + fromTokenAddress: '0xA9b038285F43cD6fE9E16B4C80B4B9bCcd3C1ddd', + fromTokenSymbol: 'AI', + bridgeAddress: '0x11a0c9270D88C99e221360BCA50c2f6Fda44A980', + toChainId: 42161, + toTokenAddress: '0x8d7c2588c365b9e98Ea464b63DBCCDf13ECd9809', + toTokenSymbol: 'AI', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 18, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 5: cBridge validation with wrong from chain id', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: true, + fromChainId: 121, + fromTokenAddress: '0xA9b038285F43cD6fE9E16B4C80B4B9bCcd3C161b', + fromTokenSymbol: 'AI', + bridgeAddress: '0x11a0c9270D88C99e221360BCA50c2f6Fda44A980', + toChainId: 42161, + toTokenAddress: '0x8d7c2588c365b9e98Ea464b63DBCCDf13ECd9809', + toTokenSymbol: 'AI', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 18, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 6: cBridge validation with wrong to token address', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: true, + fromChainId: 56, + fromTokenAddress: '0xA9b038285F43cD6fE9E16B4C80B4B9bCcd3C161b', + fromTokenSymbol: 'AI', + bridgeAddress: '0x11a0c9270D88C99e221360BCA50c2f6Fda44A980', + toChainId: 42161, + toTokenAddress: '0x8d7c2588c365b9e98Ea464b63DBCCDf13ECd980d', + toTokenSymbol: 'AI', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 18, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 7: cBridge validation with wrong to token symbol', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: true, + fromChainId: 56, + fromTokenAddress: '0xA9b038285F43cD6fE9E16B4C80B4B9bCcd3C161b', + fromTokenSymbol: 'AI', + bridgeAddress: '0x11a0c9270D88C99e221360BCA50c2f6Fda44A980', + toChainId: 42161, + toTokenAddress: '0x8d7c2588c365b9e98Ea464b63DBCCDf13ECd9809', + toTokenSymbol: 'AIY', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 18, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 8: cBridge validation with wrong to token decimal', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: true, + fromChainId: 56, + fromTokenAddress: '0xA9b038285F43cD6fE9E16B4C80B4B9bCcd3C161b', + fromTokenSymbol: 'AI', + bridgeAddress: '0x11a0c9270D88C99e221360BCA50c2f6Fda44A980', + toChainId: 42161, + toTokenAddress: '0x8d7c2588c365b9e98Ea464b63DBCCDf13ECd9809', + toTokenSymbol: 'AI', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 10, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 9: cBridge validation with wrong to chain id', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: true, + fromChainId: 56, + fromTokenAddress: '0xA9b038285F43cD6fE9E16B4C80B4B9bCcd3C161b', + fromTokenSymbol: 'AI', + bridgeAddress: '0x11a0c9270D88C99e221360BCA50c2f6Fda44A980', + toChainId: 125, + toTokenAddress: '0x8d7c2588c365b9e98Ea464b63DBCCDf13ECd9809', + toTokenSymbol: 'AI', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 18, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 10: cBridge validation with wrong API endpoint', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: true, + fromChainId: 56, + fromTokenAddress: '0xA9b038285F43cD6fE9E16B4C80B4B9bCcd3C161b', + fromTokenSymbol: 'AI', + bridgeAddress: '0x11a0c9270D88C99e221360BCA50c2f6Fda44A980', + toChainId: 42161, + toTokenAddress: '0x8d7c2588c365b9e98Ea464b63DBCCDf13ECd9809', + toTokenSymbol: 'AI', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 18, + cBridgeEndpoint: 'https://cbridge-prod2.celer.app/v2/wrongEndpoint', + }) + ).toBe(false); + }); + + it('Test 11: cBridge validation with wrong amount', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: true, + fromChainId: 56, + fromTokenAddress: '0xA9b038285F43cD6fE9E16B4C80B4B9bCcd3C161b', + fromTokenSymbol: 'AI', + bridgeAddress: '0x11a0c9270D88C99e221360BCA50c2f6Fda44A980', + toChainId: 42161, + toTokenAddress: '0x8d7c2588c365b9e98Ea464b63DBCCDf13ECd9809', + toTokenSymbol: 'AI', + amount: -2, + fromTokenDecimals: 18, + toTokenDecimals: 18, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 12: cBridge validation with wrong pegged setting', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: false, + fromChainId: 56, + fromTokenAddress: '0xA9b038285F43cD6fE9E16B4C80B4B9bCcd3C161b', + fromTokenSymbol: 'AI', + bridgeAddress: '0x11a0c9270D88C99e221360BCA50c2f6Fda44A980', + toChainId: 42161, + toTokenAddress: '0x8d7c2588c365b9e98Ea464b63DBCCDf13ECd9809', + toTokenSymbol: 'AI', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 18, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + // Correct bridge and contract information + it('Test 13: cBridge validation with correct information', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: true, + fromChainId: 56, + fromTokenAddress: '0xA9b038285F43cD6fE9E16B4C80B4B9bCcd3C161b', + fromTokenSymbol: 'AI', + bridgeAddress: '0x11a0c9270D88C99e221360BCA50c2f6Fda44A980', + toChainId: 42161, + toTokenAddress: '0x8d7c2588c365b9e98Ea464b63DBCCDf13ECd9809', + toTokenSymbol: 'AI', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 18, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(true); + }); + + // === pool base transfer test === + it('Test 14: cBridge pool based validation with correct information', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: false, + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + bridgeAddress: '0xdd90E5E87A2081Dcf0391920868eBc2FFB81a1aF', + toChainId: 137, + toTokenAddress: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', + toTokenSymbol: 'USDT', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 6, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(true); + }); + + it('Test 15: cBridge pool based validation with from chain id', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: false, + fromChainId: 10, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + bridgeAddress: '0xdd90E5E87A2081Dcf0391920868eBc2FFB81a1aF', + toChainId: 137, + toTokenAddress: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', + toTokenSymbol: 'USDT', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 6, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 16: cBridge pool based validation with form token address', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: false, + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B31979xx', + fromTokenSymbol: 'USDT', + bridgeAddress: '0xdd90E5E87A2081Dcf0391920868eBc2FFB81a1aF', + toChainId: 137, + toTokenAddress: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', + toTokenSymbol: 'USDT', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 6, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 17: cBridge pool based validation with wrong from token symbol', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: false, + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDC', + bridgeAddress: '0xdd90E5E87A2081Dcf0391920868eBc2FFB81a1aF', + toChainId: 137, + toTokenAddress: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', + toTokenSymbol: 'USDT', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 6, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 18: cBridge pool based validation with wrong bridge address', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: false, + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + bridgeAddress: '0xdd90E5E87A2081Dcf0391920868eBc2FFB81a1xx', + toChainId: 137, + toTokenAddress: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', + toTokenSymbol: 'USDT', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 6, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 19: cBridge pool based validation with wrong to chain id', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: false, + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + bridgeAddress: '0xdd90E5E87A2081Dcf0391920868eBc2FFB81a1aF', + toChainId: 10, + toTokenAddress: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', + toTokenSymbol: 'USDT', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 6, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 20: cBridge pool based validation with wrong to token address', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: false, + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + bridgeAddress: '0xdd90E5E87A2081Dcf0391920868eBc2FFB81a1aF', + toChainId: 137, + toTokenAddress: '0xc2132D05D31c914a87C6611C10748AEb04B58exx', + toTokenSymbol: 'USDT', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 6, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 21: cBridge pool based validation with to token symbol', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: false, + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + bridgeAddress: '0xdd90E5E87A2081Dcf0391920868eBc2FFB81a1aF', + toChainId: 137, + toTokenAddress: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', + toTokenSymbol: 'USDC', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 6, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 22: cBridge pool based validation with wrong from token decimal', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: false, + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + bridgeAddress: '0xdd90E5E87A2081Dcf0391920868eBc2FFB81a1aF', + toChainId: 137, + toTokenAddress: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', + toTokenSymbol: 'USDT', + amount: 20.1, + fromTokenDecimals: 10, + toTokenDecimals: 6, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 23: cBridge pool based validation with to token decimal', async () => { + expect( + await bridge.validateCBridgeToken({ + isPegged: false, + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + bridgeAddress: '0xdd90E5E87A2081Dcf0391920868eBc2FFB81a1aF', + toChainId: 137, + toTokenAddress: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F', + toTokenSymbol: 'USDT', + amount: 20.1, + fromTokenDecimals: 18, + toTokenDecimals: 10, + cBridgeEndpoint: + 'https://cbridge-prod2.celer.app/v2/getTransferConfigsForAll', + }) + ).toBe(false); + }); + + it('Test 24: cBridge get pegged deposit function name', async () => { + expect( + await bridge.getTransferFunction({ + isPegged: true, + transferType: 'deposit', + }) + ).toBe('deposit'); + }); + + it('Test 25: cBridge get pegged deposit function name', async () => { + expect( + await bridge.getTransferFunction({ + isPegged: true, + transferType: 'withdraw', + }) + ).toBe('burn'); + }); + + it('Test 27: cBridge get pool based function name', async () => { + expect( + await bridge.getTransferFunction({ + isPegged: false, + transferType: undefined, + }) + ).toBe('send'); + }); + + const AIpeggedConfig = { + org_chain_id: 56, + org_token: { + token: { + symbol: 'AI', + address: '0xA9b038285F43cD6fE9E16B4C80B4B9bCcd3C161b', + decimal: 18, + xfer_disabled: false, + }, + name: 'Flourishing AI', + icon: 'https://i.postimg.cc/vTzMmCVW/AI.png', + inbound_lmt: '', + inbound_epoch_cap: '', + transfer_disabled: false, + liq_add_disabled: false, + liq_rm_disabled: false, + liq_agg_rm_src_disabled: false, + delay_threshold: '', + delay_period: 0, + }, + pegged_chain_id: 42161, + pegged_token: { + token: { + symbol: 'AI', + address: '0x8d7c2588c365b9e98Ea464b63DBCCDf13ECd9809', + decimal: 18, + xfer_disabled: false, + }, + name: 'Flourishing AI', + icon: 'https://i.postimg.cc/vTzMmCVW/AI.png', + inbound_lmt: '', + inbound_epoch_cap: '', + transfer_disabled: false, + liq_add_disabled: false, + liq_rm_disabled: false, + liq_agg_rm_src_disabled: false, + delay_threshold: '', + delay_period: 0, + }, + pegged_deposit_contract_addr: '0x11a0c9270D88C99e221360BCA50c2f6Fda44A980', + pegged_burn_contract_addr: '0xc72e7fC220e650e93495622422F3c14fb03aAf6B', + canonical_token_contract_addr: '', + vault_version: 2, + bridge_version: 2, + migration_peg_burn_contract_addr: '', + }; + + it('Test 27: cBridge get pool based function name', async () => { + expect( + await bridge.getTransferParams({ + address: '0x4DcfAF0ae6034e31191390c04006d0169326DEc7', + amount: 20100000000000000000n, + isPegged: true, + maxSlippage: 10000, + nonce: 1733983028205, + peggedConfig: AIpeggedConfig, + toChainId: 42161, + tokenAddress: '0xA9b038285F43cD6fE9E16B4C80B4B9bCcd3C161b', + transferType: 'deposit', + }) + ).toEqual([ + '0xA9b038285F43cD6fE9E16B4C80B4B9bCcd3C161b', + 20100000000000000000n, + 42161, + '0x4DcfAF0ae6034e31191390c04006d0169326DEc7', + 1733983028205, + ]); + }); +}); diff --git a/packages/canonical-bridge-sdk/__tests__/debridge/index.test.ts b/packages/canonical-bridge-sdk/__tests__/debridge/index.test.ts new file mode 100644 index 00000000..e4ed93db --- /dev/null +++ b/packages/canonical-bridge-sdk/__tests__/debridge/index.test.ts @@ -0,0 +1,295 @@ +// import { CBridge } from '../../src/cbridge'; +import { DeBridge } from '../../src/debridge'; + +describe('deBridge test cases', () => { + let bridge: DeBridge; + + beforeEach(() => { + // + bridge = new DeBridge({ + endpoint: 'http://localhost:3000', + statsEndpoint: 'http://localhost:3000', + timeout: 5 * 1000, + }); + }); + + it('Test 1: deBridge validation with wrong from chain id', async () => { + expect( + await bridge.validateDeBridgeToken({ + fromChainId: 10, + fromChainType: 'evm', + fromTokenSymbol: 'CAKE', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenDecimals: 18, + fromBridgeAddress: '0x663DC15D3C1aC63ff12E45Ab68FeA3F0a883C251', + toChainId: 42161, + toChainType: 'evm', + toTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67cf57767298b9073d2c1ba2c', + toTokenDecimals: 18, + amount: 1, + deBridgeEndpoint: 'https://deswap.debridge.finance/v1.0', + }) + ).toBe(false); + }); + + it('Test 2: deBridge validation with wrong chain type', async () => { + expect( + await bridge.validateDeBridgeToken({ + fromChainId: 56, + fromChainType: 'solana', + fromTokenSymbol: 'CAKE', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenDecimals: 18, + fromBridgeAddress: '0x663DC15D3C1aC63ff12E45Ab68FeA3F0a883C251', + toChainId: 42161, + toChainType: 'evm', + toTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67cf57767298b9073d2c1ba2c', + toTokenDecimals: 18, + amount: 1, + deBridgeEndpoint: 'https://deswap.debridge.finance/v1.0', + }) + ).toBe(false); + }); + + it('Test 3: deBridge validation with wrong from token symbol', async () => { + expect( + await bridge.validateDeBridgeToken({ + fromChainId: 56, + fromChainType: 'evm', + fromTokenSymbol: 'PEPE', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenDecimals: 18, + fromBridgeAddress: '0x663DC15D3C1aC63ff12E45Ab68FeA3F0a883C251', + toChainId: 42161, + toChainType: 'evm', + toTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67cf57767298b9073d2c1ba2c', + toTokenDecimals: 18, + amount: 1, + deBridgeEndpoint: 'https://deswap.debridge.finance/v1.0', + }) + ).toBe(false); + }); + + it('Test 4: deBridge validation with wrong from token address', async () => { + expect( + await bridge.validateDeBridgeToken({ + fromChainId: 56, + fromChainType: 'evm', + fromTokenSymbol: 'CAKE', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81cexx', + fromTokenDecimals: 18, + fromBridgeAddress: '0x663DC15D3C1aC63ff12E45Ab68FeA3F0a883C251', + toChainId: 42161, + toChainType: 'evm', + toTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67cf57767298b9073d2c1ba2c', + toTokenDecimals: 18, + amount: 1, + deBridgeEndpoint: 'https://deswap.debridge.finance/v1.0', + }) + ).toBe(false); + }); + + it('Test 5: deBridge validation with wrong from token decimals', async () => { + expect( + await bridge.validateDeBridgeToken({ + fromChainId: 56, + fromChainType: 'evm', + fromTokenSymbol: 'CAKE', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenDecimals: 10, + fromBridgeAddress: '0x663DC15D3C1aC63ff12E45Ab68FeA3F0a883C251', + toChainId: 42161, + toChainType: 'evm', + toTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67cf57767298b9073d2c1ba2c', + toTokenDecimals: 18, + amount: 1, + deBridgeEndpoint: 'https://deswap.debridge.finance/v1.0', + }) + ).toBe(false); + }); + + it('Test 6: deBridge validation with non-evm from bridge address', async () => { + expect( + await bridge.validateDeBridgeToken({ + fromChainId: 56, + fromChainType: 'evm', + fromTokenSymbol: 'CAKE', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenDecimals: 18, + fromBridgeAddress: 'TTb3A6ASFejJuGcM1UVcRCJA23WGiJKSiY', + toChainId: 42161, + toChainType: 'evm', + toTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67cf57767298b9073d2c1ba2c', + toTokenDecimals: 18, + amount: 1, + deBridgeEndpoint: 'https://deswap.debridge.finance/v1.0', + }) + ).toBe(false); + }); + + it('Test 7: deBridge validation with wrong to chain id', async () => { + expect( + await bridge.validateDeBridgeToken({ + fromChainId: 56, + fromChainType: 'evm', + fromTokenSymbol: 'CAKE', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenDecimals: 18, + fromBridgeAddress: '0x663DC15D3C1aC63ff12E45Ab68FeA3F0a883C251', + toChainId: 11111, + toChainType: 'evm', + toTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67cf57767298b9073d2c1ba2c', + toTokenDecimals: 18, + amount: 1, + deBridgeEndpoint: 'https://deswap.debridge.finance/v1.0', + }) + ).toBe(false); + }); + + it('Test 8: deBridge validation with wrong to chain type', async () => { + expect( + await bridge.validateDeBridgeToken({ + fromChainId: 56, + fromChainType: 'evm', + fromTokenSymbol: 'CAKE', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenDecimals: 18, + fromBridgeAddress: '0x663DC15D3C1aC63ff12E45Ab68FeA3F0a883C251', + toChainId: 42161, + toChainType: 'salana', + toTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67cf57767298b9073d2c1ba2c', + toTokenDecimals: 18, + amount: 1, + deBridgeEndpoint: 'https://deswap.debridge.finance/v1.0', + }) + ).toBe(false); + }); + + it('Test 9: deBridge validation with wrong to token symbol', async () => { + expect( + await bridge.validateDeBridgeToken({ + fromChainId: 56, + fromChainType: 'evm', + fromTokenSymbol: 'CAKE', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenDecimals: 18, + fromBridgeAddress: '0x663DC15D3C1aC63ff12E45Ab68FeA3F0a883C251', + toChainId: 42161, + toChainType: 'evm', + toTokenSymbol: 'MEW', + toTokenAddress: '0x1b896893dfc86bb67cf57767298b9073d2c1ba2c', + toTokenDecimals: 18, + amount: 1, + deBridgeEndpoint: 'https://deswap.debridge.finance/v1.0', + }) + ).toBe(false); + }); + + it('Test 10: deBridge validation with wrong token address', async () => { + expect( + await bridge.validateDeBridgeToken({ + fromChainId: 56, + fromChainType: 'evm', + fromTokenSymbol: 'CAKE', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenDecimals: 18, + fromBridgeAddress: '0x663DC15D3C1aC63ff12E45Ab68FeA3F0a883C251', + toChainId: 42161, + toChainType: 'evm', + toTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67cf57767298b9073d2c1baQQ', + toTokenDecimals: 18, + amount: 1, + deBridgeEndpoint: 'https://deswap.debridge.finance/v1.0', + }) + ).toBe(false); + }); + + it('Test 11: deBridge validation with wrong to token decimals', async () => { + expect( + await bridge.validateDeBridgeToken({ + fromChainId: 56, + fromChainType: 'evm', + fromTokenSymbol: 'CAKE', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenDecimals: 18, + fromBridgeAddress: '0x663DC15D3C1aC63ff12E45Ab68FeA3F0a883C251', + toChainId: 42161, + toChainType: 'evm', + toTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67cf57767298b9073d2c1ba2c', + toTokenDecimals: 11, + amount: 1, + deBridgeEndpoint: 'https://deswap.debridge.finance/v1.0', + }) + ).toBe(false); + }); + + it('Test 12: deBridge validation with invalid amount', async () => { + expect( + await bridge.validateDeBridgeToken({ + fromChainId: 56, + fromChainType: 'evm', + fromTokenSymbol: 'CAKE', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenDecimals: 18, + fromBridgeAddress: '0x663DC15D3C1aC63ff12E45Ab68FeA3F0a883C251', + toChainId: 42161, + toChainType: 'evm', + toTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67cf57767298b9073d2c1ba2c', + toTokenDecimals: 18, + amount: -100, + deBridgeEndpoint: 'https://deswap.debridge.finance/v1.0', + }) + ).toBe(false); + }); + + it('Test 13: deBridge validation with invalid API endpoint', async () => { + expect( + await bridge.validateDeBridgeToken({ + fromChainId: 56, + fromChainType: 'evm', + fromTokenSymbol: 'CAKE', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenDecimals: 18, + fromBridgeAddress: '0x663DC15D3C1aC63ff12E45Ab68FeA3F0a883C251', + toChainId: 42161, + toChainType: 'evm', + toTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67cf57767298b9073d2c1ba2c', + toTokenDecimals: 18, + amount: 1, + deBridgeEndpoint: 'https://deswap.debridge.finance/wrongEndpoint', + }) + ).toBe(false); + }); + + it('Test 14: deBridge validation with correct information', async () => { + expect( + await bridge.validateDeBridgeToken({ + fromChainId: 56, + fromChainType: 'evm', + fromTokenSymbol: 'CAKE', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenDecimals: 18, + fromBridgeAddress: '0x663DC15D3C1aC63ff12E45Ab68FeA3F0a883C251', + toChainId: 42161, + toChainType: 'evm', + toTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67cf57767298b9073d2c1ba2c', + toTokenDecimals: 18, + amount: 1, + deBridgeEndpoint: 'https://deswap.debridge.finance/v1.0', + }) + ).toBe(true); + }); +}); diff --git a/packages/canonical-bridge-sdk/__tests__/layerzero/index.test.ts b/packages/canonical-bridge-sdk/__tests__/layerzero/index.test.ts new file mode 100644 index 00000000..a578042c --- /dev/null +++ b/packages/canonical-bridge-sdk/__tests__/layerzero/index.test.ts @@ -0,0 +1,288 @@ +import { createPublicClient, defineChain, http } from 'viem'; +import { LayerZero } from '../../src/layerZero'; + +describe('LayerZero test cases', () => { + let bridge: LayerZero; + + beforeEach(() => { + bridge = new LayerZero(); + }); + + const bsc = defineChain({ + id: 56, + name: 'BNB Smart Chain', + nativeCurrency: { + name: 'BNB Chain Native Token', + symbol: 'BNB', + decimals: 18, + }, + rpcUrls: { + default: { + http: ['https://bsc-dataseed.bnbchain.org'], + }, + public: { + http: ['https://bsc-dataseed.bnbchain.org'], + }, + }, + blockExplorers: { + default: { + name: 'bscscan', + url: 'https://bscscan.com', + }, + }, + contracts: { + multicall3: { + address: '0xca11bde05977b3631167028862be2a173976ca11', + blockCreated: 15921452, + }, + }, + }); + + const arbitrum = defineChain({ + id: 42161, + name: 'Arbitrum One', + nativeCurrency: { + name: 'Ether', + symbol: 'ETH', + decimals: 18, + }, + rpcUrls: { + default: { + http: ['https://arb1.arbitrum.io/rpc'], + }, + public: { + http: ['https://arb1.arbitrum.io/rpc'], + }, + }, + blockExplorers: { + default: { + name: 'Arbiscan', + url: 'https://arbiscan.io', + }, + }, + contracts: { + multicall3: { + address: '0xca11bde05977b3631167028862be2a173976ca11', + blockCreated: 7654707, + }, + }, + }); + + const fromViemClient = createPublicClient({ + chain: bsc, + transport: http(), + }); + const toViemClient = createPublicClient({ + chain: arbitrum, + transport: http(), + }); + + it('Test 1: LayerZero validation with invalid from token address', async () => { + expect( + await bridge.validateLayerZeroToken({ + fromPublicClient: fromViemClient, + toPublicClient: toViemClient, + bridgeAddress: '0xb274202daBA6AE180c665B4fbE59857b7c3a8091', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81cexx', + fromTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + toBridgeAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + fromTokenDecimals: 18, + toTokenSymbol: 'CAKE', + toTokenDecimals: 18, + dstEndpoint: 110, + amount: 1, + }) + ).toBe(false); + }); + + it('Test 2: LayerZero validation with wrong bridge address', async () => { + expect( + await bridge.validateLayerZeroToken({ + fromPublicClient: fromViemClient, + toPublicClient: toViemClient, + bridgeAddress: '0xb274202daBA6AE180c665B4fbE59857b7c3a80x4', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + toBridgeAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + fromTokenDecimals: 18, + toTokenSymbol: 'CAKE', + toTokenDecimals: 18, + dstEndpoint: 110, + amount: 1, + }) + ).toBe(false); + }); + + it('Test 3: LayerZero validation with wrong from token symbol', async () => { + expect( + await bridge.validateLayerZeroToken({ + fromPublicClient: fromViemClient, + toPublicClient: toViemClient, + bridgeAddress: '0xb274202daBA6AE180c665B4fbE59857b7c3a8091', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenSymbol: 'LOL', + toTokenAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + toBridgeAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + fromTokenDecimals: 18, + toTokenSymbol: 'CAKE', + toTokenDecimals: 18, + dstEndpoint: 110, + amount: 1, + }) + ).toBe(false); + }); + + it('Test 4: LayerZero sendToken with invalid to token address', async () => { + expect( + await bridge.validateLayerZeroToken({ + fromPublicClient: fromViemClient, + toPublicClient: toViemClient, + bridgeAddress: '0xb274202daBA6AE180c665B4fbE59857b7c3a8091', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bAxx', + toBridgeAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + fromTokenDecimals: 18, + toTokenSymbol: 'CAKE', + toTokenDecimals: 18, + dstEndpoint: 110, + amount: 1, + }) + ).toBe(false); + }); + + it('Test 5: LayerZero sendToken with wrong to bridge address', async () => { + expect( + await bridge.validateLayerZeroToken({ + fromPublicClient: fromViemClient, + toPublicClient: toViemClient, + bridgeAddress: '0xb274202daBA6AE180c665B4fbE59857b7c3a8091', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + toBridgeAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bAxx', + fromTokenDecimals: 18, + toTokenSymbol: 'CAKE', + toTokenDecimals: 18, + dstEndpoint: 110, + amount: 1, + }) + ).toBe(false); + }); + + it('Test 6: LayerZero sendToken with invalid destination endpoint', async () => { + expect( + await bridge.validateLayerZeroToken({ + fromPublicClient: fromViemClient, + toPublicClient: toViemClient, + bridgeAddress: '0xb274202daBA6AE180c665B4fbE59857b7c3a8091', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + toBridgeAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + fromTokenDecimals: 18, + toTokenSymbol: 'CAKE', + toTokenDecimals: 18, + dstEndpoint: 202, + amount: 1, + }) + ).toBe(false); + }); + + it('Test 7: LayerZero sendToken with invalid amount', async () => { + expect( + await bridge.validateLayerZeroToken({ + fromPublicClient: fromViemClient, + toPublicClient: toViemClient, + bridgeAddress: '0xb274202daBA6AE180c665B4fbE59857b7c3a8091', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + toBridgeAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + fromTokenDecimals: 18, + toTokenSymbol: 'CAKE', + toTokenDecimals: 18, + dstEndpoint: 110, + amount: -100, + }) + ).toBe(false); + }); + + it('Test 8: LayerZero sendToken with correct information', async () => { + expect( + await bridge.validateLayerZeroToken({ + fromPublicClient: fromViemClient, + toPublicClient: toViemClient, + bridgeAddress: '0xb274202daBA6AE180c665B4fbE59857b7c3a8091', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + toBridgeAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + fromTokenDecimals: 18, + toTokenSymbol: 'CAKE', + toTokenDecimals: 18, + dstEndpoint: 110, + amount: 1, + }) + ).toBe(true); + }); + + it('Test 9: LayerZero sendToken with wrong from token decimals', async () => { + expect( + await bridge.validateLayerZeroToken({ + fromPublicClient: fromViemClient, + toPublicClient: toViemClient, + bridgeAddress: '0xb274202daBA6AE180c665B4fbE59857b7c3a8091', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + toBridgeAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + fromTokenDecimals: 10, + toTokenSymbol: 'CAKE', + toTokenDecimals: 18, + dstEndpoint: 110, + amount: 1, + }) + ).toBe(false); + }); + + it('Test 10: LayerZero sendToken with wrong to token symbol', async () => { + expect( + await bridge.validateLayerZeroToken({ + fromPublicClient: fromViemClient, + toPublicClient: toViemClient, + bridgeAddress: '0xb274202daBA6AE180c665B4fbE59857b7c3a8091', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + toBridgeAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + fromTokenDecimals: 18, + toTokenSymbol: 'ADA', + toTokenDecimals: 18, + dstEndpoint: 110, + amount: 1, + }) + ).toBe(false); + }); + + it('Test 11: LayerZero sendToken with wrong to token decimals', async () => { + expect( + await bridge.validateLayerZeroToken({ + fromPublicClient: fromViemClient, + toPublicClient: toViemClient, + bridgeAddress: '0xb274202daBA6AE180c665B4fbE59857b7c3a8091', + fromTokenAddress: '0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82', + fromTokenSymbol: 'CAKE', + toTokenAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + toBridgeAddress: '0x1b896893dfc86bb67Cf57767298b9073D2c1bA2c', + fromTokenDecimals: 18, + toTokenSymbol: 'CAKE', + toTokenDecimals: 10, + dstEndpoint: 110, + amount: 1, + }) + ).toBe(false); + }); +}); diff --git a/packages/canonical-bridge-sdk/__tests__/meson/index.test.ts b/packages/canonical-bridge-sdk/__tests__/meson/index.test.ts new file mode 100644 index 00000000..1ed1cc60 --- /dev/null +++ b/packages/canonical-bridge-sdk/__tests__/meson/index.test.ts @@ -0,0 +1,260 @@ +import { Meson } from '../../src/meson'; + +describe('Meson SDK validation', () => { + let bridge: Meson; + + beforeEach(() => { + bridge = new Meson({ + endpoint: 'http://localhost:3000', + timeout: 5000, + bridgeType: 'meson', + }); + }); + + it('Test 1: Meson validation with wrong from chain id', async () => { + expect( + await bridge.validateMesonToken({ + fromChainId: 10, + fromTokenAddress: '0x55d398326f99059ff775485246999027b3197955', + fromTokenSymbol: 'usdt', + fromTokenDecimals: 18, + fromChainType: 'evm', + toChainId: 42161, + toTokenAddress: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', + toTokenDecimals: 6, + toChainType: 'evm', + toTokenSymbol: 'usdt', + amount: 5, + mesonEndpoint: 'https://relayer.meson.fi/api/v1', + }) + ).toBe(false); + }); + + it('Test 2: Meson validation with wrong from token address', async () => { + expect( + await bridge.validateMesonToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059ff775485246999027b3197950', + fromTokenSymbol: 'usdt', + fromTokenDecimals: 18, + fromChainType: 'evm', + toChainId: 42161, + toTokenAddress: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', + toTokenDecimals: 6, + toChainType: 'evm', + toTokenSymbol: 'usdt', + amount: 5, + mesonEndpoint: 'https://relayer.meson.fi/api/v1', + }) + ).toBe(false); + }); + + it('Test 3: Meson validation with invalid from token symbol', async () => { + expect( + await bridge.validateMesonToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059ff775485246999027b3197955', + fromTokenSymbol: 'ppz', + fromTokenDecimals: 18, + fromChainType: 'evm', + toChainId: 42161, + toTokenAddress: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', + toTokenDecimals: 6, + toChainType: 'evm', + toTokenSymbol: 'usdt', + amount: 5, + mesonEndpoint: 'https://relayer.meson.fi/api/v1', + }) + ).toBe(false); + }); + + it('Test 4: Meson validation with wrong from token decimal', async () => { + expect( + await bridge.validateMesonToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059ff775485246999027b3197955', + fromTokenSymbol: 'usdt', + fromTokenDecimals: 10, + fromChainType: 'evm', + toChainId: 42161, + toTokenAddress: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', + toTokenDecimals: 6, + toChainType: 'evm', + toTokenSymbol: 'usdt', + amount: 5, + mesonEndpoint: 'https://relayer.meson.fi/api/v1', + }) + ).toBe(false); + }); + + it('Test 5: Meson validation with wrong from chain type', async () => { + expect( + await bridge.validateMesonToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059ff775485246999027b3197955', + fromTokenSymbol: 'usdt', + fromTokenDecimals: 18, + fromChainType: 'tron', + toChainId: 42161, + toTokenAddress: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', + toTokenDecimals: 6, + toChainType: 'evm', + toTokenSymbol: 'usdt', + amount: 5, + mesonEndpoint: 'https://relayer.meson.fi/api/v1', + }) + ).toBe(false); + }); + + it('Test 6: Meson validation with wrong to chain id', async () => { + expect( + await bridge.validateMesonToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059ff775485246999027b3197955', + fromTokenSymbol: 'usdt', + fromTokenDecimals: 18, + fromChainType: 'evm', + toChainId: 40, + toTokenAddress: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', + toTokenDecimals: 6, + toChainType: 'evm', + toTokenSymbol: 'usdt', + amount: 5, + mesonEndpoint: 'https://relayer.meson.fi/api/v1', + }) + ).toBe(false); + }); + + it('Test 7: Meson validation with to token address', async () => { + expect( + await bridge.validateMesonToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059ff775485246999027b3197955', + fromTokenSymbol: 'usdt', + fromTokenDecimals: 18, + fromChainType: 'evm', + toChainId: 42161, + toTokenAddress: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbxQ', + toTokenDecimals: 6, + toChainType: 'evm', + toTokenSymbol: 'usdt', + amount: 5, + mesonEndpoint: 'https://relayer.meson.fi/api/v1', + }) + ).toBe(false); + }); + + it('Test 8: Meson validation with wrong to token decimal', async () => { + expect( + await bridge.validateMesonToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059ff775485246999027b3197955', + fromTokenSymbol: 'usdt', + fromTokenDecimals: 18, + fromChainType: 'evm', + toChainId: 42161, + toTokenAddress: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', + toTokenDecimals: 10, + toChainType: 'evm', + toTokenSymbol: 'usdt', + amount: 5, + mesonEndpoint: 'https://relayer.meson.fi/api/v1', + }) + ).toBe(false); + }); + + it('Test 9: Meson validation with wrong to chain type', async () => { + expect( + await bridge.validateMesonToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059ff775485246999027b3197955', + fromTokenSymbol: 'usdt', + fromTokenDecimals: 18, + fromChainType: 'evm', + toChainId: 42161, + toTokenAddress: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', + toTokenDecimals: 6, + toChainType: 'solana', + toTokenSymbol: 'usdt', + amount: 5, + mesonEndpoint: 'https://relayer.meson.fi/api/v1', + }) + ).toBe(false); + }); + + it('Test 10: Meson validation with invalid to token symbol', async () => { + expect( + await bridge.validateMesonToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059ff775485246999027b3197955', + fromTokenSymbol: 'usdt', + fromTokenDecimals: 18, + fromChainType: 'evm', + toChainId: 42161, + toTokenAddress: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', + toTokenDecimals: 6, + toChainType: 'evm', + toTokenSymbol: 'rpg', + amount: 5, + mesonEndpoint: 'https://relayer.meson.fi/api/v1', + }) + ).toBe(false); + }); + + it('Test 11: Meson validation with invalid amount', async () => { + expect( + await bridge.validateMesonToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059ff775485246999027b3197955', + fromTokenSymbol: 'usdt', + fromTokenDecimals: 18, + fromChainType: 'evm', + toChainId: 42161, + toTokenAddress: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', + toTokenDecimals: 6, + toChainType: 'evm', + toTokenSymbol: 'usdt', + amount: -500, + mesonEndpoint: 'https://relayer.meson.fi/api/v1', + }) + ).toBe(false); + }); + + it('Test 12: Meson validation with invalid API endpoint', async () => { + expect( + await bridge.validateMesonToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059ff775485246999027b3197955', + fromTokenSymbol: 'usdt', + fromTokenDecimals: 18, + fromChainType: 'evm', + toChainId: 42161, + toTokenAddress: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', + toTokenDecimals: 6, + toChainType: 'evm', + toTokenSymbol: 'usdt', + amount: 5, + mesonEndpoint: 'https://relayer.meson.fi/api/wrongEndpoint', + }) + ).toBe(false); + }); + + it('Test 13: Meson validation with correct information', async () => { + expect( + await bridge.validateMesonToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059ff775485246999027b3197955', + fromTokenSymbol: 'usdt', + fromTokenDecimals: 18, + fromChainType: 'evm', + toChainId: 42161, + toTokenAddress: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9', + toTokenDecimals: 6, + toChainType: 'evm', + toTokenSymbol: 'usdt', + amount: 5, + mesonEndpoint: 'https://relayer.meson.fi/api/v1', + }) + ).toBe(true); + }); +}); diff --git a/packages/canonical-bridge-sdk/__tests__/stargate/index.test.ts b/packages/canonical-bridge-sdk/__tests__/stargate/index.test.ts new file mode 100644 index 00000000..e0b710e6 --- /dev/null +++ b/packages/canonical-bridge-sdk/__tests__/stargate/index.test.ts @@ -0,0 +1,380 @@ +import { createPublicClient, defineChain, http } from 'viem'; +import { Stargate } from '../../src/stargate'; + +describe('Meson SDK validation', () => { + let bridge: Stargate; + + beforeEach(() => { + bridge = new Stargate({ + endpoint: 'http://localhost:3000', + timeout: 5000, + bridgeType: 'stargate', + }); + }); + + const bsc = defineChain({ + id: 56, + name: 'BNB Smart Chain', + nativeCurrency: { + name: 'BNB Chain Native Token', + symbol: 'BNB', + decimals: 18, + }, + rpcUrls: { + default: { + http: ['https://bsc-dataseed.bnbchain.org'], + }, + public: { + http: ['https://bsc-dataseed.bnbchain.org'], + }, + }, + blockExplorers: { + default: { + name: 'bscscan', + url: 'https://bscscan.com', + }, + }, + contracts: { + multicall3: { + address: '0xca11bde05977b3631167028862be2a173976ca11', + blockCreated: 15921452, + }, + }, + }); + + const arbitrum = { + id: 42161, + name: 'Arbitrum One', + nativeCurrency: { + name: 'Ether', + symbol: 'ETH', + decimals: 18, + }, + rpcUrls: { + default: { + http: ['https://arb1.arbitrum.io/rpc'], + }, + public: { + http: ['https://arb1.arbitrum.io/rpc'], + }, + }, + blockExplorers: { + default: { + name: 'Arbiscan', + url: 'https://arbiscan.io', + }, + }, + contracts: { + multicall3: { + address: '0xca11bde05977b3631167028862be2a173976ca11' as `0x${string}`, + blockCreated: 7654707, + }, + }, + }; + const fromViemClient = createPublicClient({ + chain: bsc, + transport: http(), + }); + const toViemClient = createPublicClient({ + chain: arbitrum, + transport: http(), + }); + + it('Test 1: Stargate validation with wrong from chain id', async () => { + expect( + await bridge.validateStargateToken({ + fromChainId: 111, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + fromTokenDecimals: 18, + fromBridgeAddress: '0x138EB30f73BC423c6455C53df6D89CB01d9eBc63', + toChainId: 42161, + toTokenAddress: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + toBridgeAddress: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0', + toTokenSymbol: 'USDT', + toTokenDecimals: 6, + amount: 15, + toPublicClient: toViemClient, + fromPublicClient: fromViemClient, + dstEndpointId: 30110, + stargateEndpoint: + 'https://mainnet.stargate-api.com/v1/metadata?version=v2', + }) + ).toBe(false); + }); + + it('Test 2: Stargate validation with wrong from token address', async () => { + expect( + await bridge.validateStargateToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B31979xx', + fromTokenSymbol: 'USDT', + fromTokenDecimals: 18, + fromBridgeAddress: '0x138EB30f73BC423c6455C53df6D89CB01d9eBc63', + toChainId: 42161, + toTokenAddress: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + toBridgeAddress: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0', + toTokenSymbol: 'USDT', + toTokenDecimals: 6, + amount: 15, + toPublicClient: toViemClient, + fromPublicClient: fromViemClient, + dstEndpointId: 30110, + stargateEndpoint: + 'https://mainnet.stargate-api.com/v1/metadata?version=v2', + }) + ).toBe(false); + }); + + it('Test 3: Stargate validation with from token decimals', async () => { + expect( + await bridge.validateStargateToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + fromTokenDecimals: 10, + fromBridgeAddress: '0x138EB30f73BC423c6455C53df6D89CB01d9eBc63', + toChainId: 42161, + toTokenAddress: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + toBridgeAddress: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0', + toTokenSymbol: 'USDT', + toTokenDecimals: 6, + amount: 15, + toPublicClient: toViemClient, + fromPublicClient: fromViemClient, + dstEndpointId: 30110, + stargateEndpoint: + 'https://mainnet.stargate-api.com/v1/metadata?version=v2', + }) + ).toBe(false); + }); + + it('Test 4: Stargate validation with wrong from bridge address', async () => { + expect( + await bridge.validateStargateToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + fromTokenDecimals: 18, + fromBridgeAddress: '0x138EB30f73BC423c6455C53df6D89CB01d9eBcQd', + toChainId: 42161, + toTokenAddress: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + toBridgeAddress: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0', + toTokenSymbol: 'USDT', + toTokenDecimals: 6, + amount: 15, + toPublicClient: toViemClient, + fromPublicClient: fromViemClient, + dstEndpointId: 30110, + stargateEndpoint: + 'https://mainnet.stargate-api.com/v1/metadata?version=v2', + }) + ).toBe(false); + }); + + it('Test 5: Stargate validation with wrong to chain id', async () => { + expect( + await bridge.validateStargateToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + fromTokenDecimals: 18, + fromBridgeAddress: '0x138EB30f73BC423c6455C53df6D89CB01d9eBc63', + toChainId: 155, + toTokenAddress: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + toBridgeAddress: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0', + toTokenSymbol: 'USDT', + toTokenDecimals: 6, + amount: 15, + toPublicClient: toViemClient, + fromPublicClient: fromViemClient, + dstEndpointId: 30110, + stargateEndpoint: + 'https://mainnet.stargate-api.com/v1/metadata?version=v2', + }) + ).toBe(false); + }); + + it('Test 6: Stargate validation with wrong to token address', async () => { + expect( + await bridge.validateStargateToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + fromTokenDecimals: 18, + fromBridgeAddress: '0x138EB30f73BC423c6455C53df6D89CB01d9eBc63', + toChainId: 42161, + toTokenAddress: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcb11', + toBridgeAddress: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0', + toTokenSymbol: 'USDT', + toTokenDecimals: 6, + amount: 15, + toPublicClient: toViemClient, + fromPublicClient: fromViemClient, + dstEndpointId: 30110, + stargateEndpoint: + 'https://mainnet.stargate-api.com/v1/metadata?version=v2', + }) + ).toBe(false); + }); + + it('Test 7: Stargate validation with wrong to bridge address', async () => { + expect( + await bridge.validateStargateToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + fromTokenDecimals: 18, + fromBridgeAddress: '0x138EB30f73BC423c6455C53df6D89CB01d9eBc63', + toChainId: 42161, + toTokenAddress: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + toBridgeAddress: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7cc', + toTokenSymbol: 'USDT', + toTokenDecimals: 6, + amount: 15, + toPublicClient: toViemClient, + fromPublicClient: fromViemClient, + dstEndpointId: 30110, + stargateEndpoint: + 'https://mainnet.stargate-api.com/v1/metadata?version=v2', + }) + ).toBe(false); + }); + + it('Test 8: Stargate validation with wrong to token symbol', async () => { + expect( + await bridge.validateStargateToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + fromTokenDecimals: 18, + fromBridgeAddress: '0x138EB30f73BC423c6455C53df6D89CB01d9eBc63', + toChainId: 42161, + toTokenAddress: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + toBridgeAddress: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0', + toTokenSymbol: 'ATP', + toTokenDecimals: 6, + amount: 15, + toPublicClient: toViemClient, + fromPublicClient: fromViemClient, + dstEndpointId: 30110, + stargateEndpoint: + 'https://mainnet.stargate-api.com/v1/metadata?version=v2', + }) + ).toBe(false); + }); + + it('Test 9: Stargate validation with wrong to decimal', async () => { + expect( + await bridge.validateStargateToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + fromTokenDecimals: 18, + fromBridgeAddress: '0x138EB30f73BC423c6455C53df6D89CB01d9eBc63', + toChainId: 42161, + toTokenAddress: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + toBridgeAddress: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0', + toTokenSymbol: 'USDT', + toTokenDecimals: 12, + amount: 15, + toPublicClient: toViemClient, + fromPublicClient: fromViemClient, + dstEndpointId: 30110, + stargateEndpoint: + 'https://mainnet.stargate-api.com/v1/metadata?version=v2', + }) + ).toBe(false); + }); + + it('Test 10: Stargate validation with invalid amount', async () => { + expect( + await bridge.validateStargateToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + fromTokenDecimals: 18, + fromBridgeAddress: '0x138EB30f73BC423c6455C53df6D89CB01d9eBc63', + toChainId: 42161, + toTokenAddress: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + toBridgeAddress: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0', + toTokenSymbol: 'USDT', + toTokenDecimals: 6, + amount: -500, + toPublicClient: toViemClient, + fromPublicClient: fromViemClient, + dstEndpointId: 30110, + stargateEndpoint: + 'https://mainnet.stargate-api.com/v1/metadata?version=v2', + }) + ).toBe(false); + }); + + it('Test 11: Stargate validation with wrong destination endpoint id', async () => { + expect( + await bridge.validateStargateToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + fromTokenDecimals: 18, + fromBridgeAddress: '0x138EB30f73BC423c6455C53df6D89CB01d9eBc63', + toChainId: 42161, + toTokenAddress: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + toBridgeAddress: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0', + toTokenSymbol: 'USDT', + toTokenDecimals: 6, + amount: 15, + toPublicClient: toViemClient, + fromPublicClient: fromViemClient, + dstEndpointId: 30111, + stargateEndpoint: + 'https://mainnet.stargate-api.com/v1/metadata?version=v2', + }) + ).toBe(false); + }); + + it('Test 12: Stargate validation with correct information', async () => { + expect( + await bridge.validateStargateToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + fromTokenDecimals: 18, + fromBridgeAddress: '0x138EB30f73BC423c6455C53df6D89CB01d9eBc63', + toChainId: 42161, + toTokenAddress: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + toBridgeAddress: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0', + toTokenSymbol: 'USDT', + toTokenDecimals: 6, + amount: 15, + toPublicClient: toViemClient, + fromPublicClient: fromViemClient, + dstEndpointId: 30110, + stargateEndpoint: 'https://mainnet.stargate-api.com/v1/wrongendpoint', + }) + ).toBe(false); + }); + + it('Test 13: Stargate validation with correct information', async () => { + expect( + await bridge.validateStargateToken({ + fromChainId: 56, + fromTokenAddress: '0x55d398326f99059fF775485246999027B3197955', + fromTokenSymbol: 'USDT', + fromTokenDecimals: 18, + fromBridgeAddress: '0x138EB30f73BC423c6455C53df6D89CB01d9eBc63', + toChainId: 42161, + toTokenAddress: '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9', + toBridgeAddress: '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0', + toTokenSymbol: 'USDT', + toTokenDecimals: 6, + amount: 15, + toPublicClient: toViemClient, + fromPublicClient: fromViemClient, + dstEndpointId: 30110, + stargateEndpoint: + 'https://mainnet.stargate-api.com/v1/metadata?version=v2', + }) + ).toBe(true); + }); +}); diff --git a/packages/canonical-bridge-sdk/jest.config.js b/packages/canonical-bridge-sdk/jest.config.js new file mode 100644 index 00000000..3285e26d --- /dev/null +++ b/packages/canonical-bridge-sdk/jest.config.js @@ -0,0 +1,19 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +export default { + preset: 'ts-jest', + testEnvironment: 'node', + roots: [''], + moduleNameMapper: { + '^@/(.*)$': '/src/$1', + }, + transform: { + '^.+\\.ts$': [ + 'ts-jest', + { + tsconfig: 'tsconfig.json', + }, + ], + }, + testMatch: ['**tests/**/*.test.ts', '**/__tests__/**/*.test.ts'], + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], +}; diff --git a/packages/canonical-bridge-sdk/package.json b/packages/canonical-bridge-sdk/package.json index e11573d4..3e4fa486 100644 --- a/packages/canonical-bridge-sdk/package.json +++ b/packages/canonical-bridge-sdk/package.json @@ -26,20 +26,26 @@ "scripts": { "dev": "vite __dev__ --config vite.config.ts --port 3333 --host 0.0.0.0 --open", "watch": "vite build --watch --emptyOutDir=false", - "build": "vite build" + "build": "vite build", + "test": "jest test --silent=true", + "test:console": "jest test", + "test:watch": "jest --watch" }, "peerDependencies": { "axios": "^0", "viem": "^2" }, "devDependencies": { + "@types/jest": "~29.5.14", "@types/react": "^18", "@types/react-dom": "^18", "@vitejs/plugin-react": "^4.2.0", "axios": "~0.27.2", + "jest": "~29.7.0", "react": "~18.3.1", "react-dom": "~18.3.1", "rollup-plugin-peer-deps-external": "^2.2.4", + "ts-jest": "~29.2.5", "typescript": "^5", "viem": "~2.21.14", "vite": "^4.5.0", diff --git a/packages/canonical-bridge-sdk/src/cbridge/index.ts b/packages/canonical-bridge-sdk/src/cbridge/index.ts index e0df24b0..538ed99b 100644 --- a/packages/canonical-bridge-sdk/src/cbridge/index.ts +++ b/packages/canonical-bridge-sdk/src/cbridge/index.ts @@ -3,7 +3,7 @@ import { BaseBridgeConfigOptions, CreateAdapterParameters, } from '@/core/types'; -import { CLIENT_TIME_OUT } from '@/core/constants'; +import { CLIENT_TIME_OUT, VALIDATION_API_TIMEOUT } from '@/core/constants'; import axios, { AxiosInstance } from 'axios'; import { CBridgeChain, @@ -13,6 +13,8 @@ import { CBridgeSendRangeInput, CBridgeTransferConfigs, CBridgeTransferEstimatedTime, + ICBridgeTokenValidateParams, + ICBridgeTransferConfig, IGetCBridgeABI, IGetCBridgeTransferAddressInput, IGetCBridgeTransferFunction, @@ -26,6 +28,7 @@ import { ORIGINAL_TOKEN_VAULT_V2 } from '@/cbridge/abi/originalTokenVaultV2'; import { PEGGED_TOKEN_BRIDGE } from '@/cbridge/abi/peggedTokenBridge'; import { PEGGED_TOKEN_BRIDGE_V2 } from '@/cbridge/abi/peggedTokenBridgeV2'; import { createAdapter } from '@/cbridge/utils/createAdapter'; +import { isEvmAddress } from '@/core/utils/address'; export * from './types'; @@ -364,4 +367,163 @@ export class CBridge { args: args, }; } + + /** + * validate token and contract information + */ + validateCBridgeToken = async ({ + isPegged, + fromChainId, + fromTokenAddress, + fromTokenSymbol, + fromTokenDecimals, + bridgeAddress, + toChainId, + toTokenAddress, + toTokenSymbol, + toTokenDecimals, + amount, + cBridgeEndpoint, + }: ICBridgeTokenValidateParams) => { + try { + if (amount <= 0) { + console.log('Invalid amount', amount); + return false; + } + if ( + !fromChainId || + !toChainId || + !fromTokenAddress || + !bridgeAddress || + !fromTokenSymbol || + !fromTokenDecimals || + !toTokenAddress || + !toTokenSymbol || + !toTokenDecimals || + !amount || + !cBridgeEndpoint + ) { + console.log('Failed to get cBridge token address validation params'); + console.log('isPegged', isPegged); + console.log('fromChainId', fromChainId); + console.log('fromTokenAddress', fromTokenAddress); + console.log('fromTokenSymbol', fromTokenSymbol); + console.log('bridgeAddress', bridgeAddress); + console.log('toChainId', toChainId); + console.log('toTokenAddress', toTokenAddress); + console.log('toTokenSymbol', toTokenSymbol); + console.log('amount', amount); + console.log('fromTokenDecimals', fromTokenDecimals); + console.log('toTokenDecimals', toTokenDecimals); + console.log('cBridgeEndpoint', cBridgeEndpoint); + return false; + } + if (!isEvmAddress(fromTokenAddress) || !isEvmAddress(bridgeAddress)) { + console.log('Invalid evm address', fromTokenAddress, bridgeAddress); + return false; + } + const { data: cBridgeConfig } = await axios.get( + `${cBridgeEndpoint}`, + { timeout: VALIDATION_API_TIMEOUT } + ); + if (!cBridgeConfig) { + console.log('failed to get cBridge API config'); + return false; + } + if (isPegged === true) { + // pegged token + const peggedToken = cBridgeConfig.pegged_pair_configs.filter((pair) => { + const orgToken = pair.org_token?.token; + const peggedToken = pair.pegged_token?.token; + return ( + (pair.pegged_deposit_contract_addr === bridgeAddress && + pair?.org_chain_id === fromChainId && + orgToken?.address === fromTokenAddress && + orgToken?.symbol === fromTokenSymbol && + orgToken?.decimal === fromTokenDecimals && + peggedToken?.address === toTokenAddress && + peggedToken?.symbol === toTokenSymbol && + peggedToken?.decimal === toTokenDecimals && + pair?.pegged_chain_id === toChainId) || + (pair?.pegged_burn_contract_addr === bridgeAddress && + pair?.pegged_chain_id === fromChainId && + peggedToken?.address === fromTokenAddress && + peggedToken?.symbol === fromTokenSymbol && + peggedToken?.decimal === fromTokenDecimals && + orgToken?.address === toTokenAddress && + orgToken?.symbol === toTokenSymbol && + orgToken?.decimal === toTokenDecimals && + pair?.org_chain_id === toChainId) + ); + }); + if (!!peggedToken && peggedToken.length > 0) { + console.log('cBridge pegged token info matched', peggedToken); + return true; + } + console.log('Can not find cBridge pegged info'); + console.log('-- isPegged', isPegged); + console.log('-- fromChainId', fromChainId); + console.log('-- fromTokenAddress', fromTokenAddress); + console.log('-- fromTokenSymbol', fromTokenSymbol); + console.log('-- toChainId', toChainId); + console.log('-- toTokenAddress', toTokenAddress); + console.log('-- toTokenSymbol', toTokenSymbol); + console.log('-- bridgeAddress', bridgeAddress); + return false; + } else { + // bridge contract address + const addressInfo = cBridgeConfig.chains.filter((chain) => { + return ( + chain.id === fromChainId && + chain.contract_addr.toLowerCase() === bridgeAddress.toLowerCase() + ); + }); + // token info + const fromTokenInfo = cBridgeConfig.chain_token[ + fromChainId + ]?.token.filter((t) => { + return ( + t?.token.address.toLowerCase() === fromTokenAddress.toLowerCase() && + t?.token.decimal === fromTokenDecimals && + t?.token.symbol === fromTokenSymbol + ); + }); + const toTokenInfo = cBridgeConfig.chain_token[toChainId]?.token.filter( + (t) => { + return ( + t?.token.address.toLowerCase() === toTokenAddress.toLowerCase() && + t?.token.decimal === toTokenDecimals && + t?.token.symbol === toTokenSymbol + ); + } + ); + if ( + addressInfo?.length > 0 && + fromTokenInfo?.length > 0 && + toTokenInfo?.length > 0 + ) { + console.log('cBridge pool info matched'); + console.log('bridge contract address info', addressInfo); + console.log('bridge from token info', fromTokenInfo); + console.log('bridge to token info', toTokenInfo); + return true; + } else { + console.log('Can not find cBridge pool info'); + console.log('-- isPegged', isPegged); + console.log('-- fromChainId', fromChainId); + console.log('-- fromTokenAddress', fromTokenAddress); + console.log('-- fromTokenSymbol', fromTokenSymbol); + console.log('-- toChainId', toChainId); + console.log('-- toTokenAddress', toTokenAddress); + console.log('-- toTokenSymbol', toTokenSymbol); + console.log('-- bridgeAddress', bridgeAddress); + return false; + } + } + } catch (error) { + // eslint-disable-next-line no-console + console.log('cBridge token address validation error', error); + return false; + } + }; } diff --git a/packages/canonical-bridge-sdk/src/cbridge/types/index.ts b/packages/canonical-bridge-sdk/src/cbridge/types/index.ts index ba06584a..53c95aef 100644 --- a/packages/canonical-bridge-sdk/src/cbridge/types/index.ts +++ b/packages/canonical-bridge-sdk/src/cbridge/types/index.ts @@ -228,3 +228,92 @@ export interface IGetCBridgeTransferFunction { isPegged: boolean; transferType?: 'deposit' | 'withdraw'; } + +export interface ICBridgeToken { + token: { + symbol: string; + address: string; + decimal: number; + xfer_disabled: boolean; + display_symbol?: string; /// FOR ETH <=====> WETH + }; + name: string; + icon: string; + inbound_lmt: string; + inbound_epoch_cap: string; + transfer_disabled: boolean; + liq_add_disabled: boolean; + liq_rm_disabled: boolean; + liq_agg_rm_src_disabled: boolean; + delay_threshold: string; + delay_period: number; + method?: string; + bridgeAddress?: string; //bridge address for transfer +} + +export interface ICBridgeChain { + id: number; + name: string; + icon: string; + block_delay: number; + gas_token_symbol: string; + explore_url: string; + contract_addr: string; + drop_gas_amt: string; + drop_gas_cost_amt: string; + drop_gas_balance_alert: string; + suggested_gas_cost: string; + flat_usd_fee: number; + farming_reward_contract_addr: string; + transfer_agent_contract_addr: string; + disabled: boolean; +} + +export interface ICBridgePeggedPairConfig { + org_chain_id: number; + org_token: ICBridgeToken; + pegged_chain_id: number; + pegged_token: ICBridgeToken; + pegged_deposit_contract_addr: string; + pegged_burn_contract_addr: string; + canonical_token_contract_addr: string; + vault_version: number; + bridge_version: number; + migration_peg_burn_contract_addr: string; +} + +export interface ICBridgeTransferConfig { + chains: ICBridgeChain[]; + chain_token: { + [k: number]: { + token: ICBridgeToken[]; + }; + }; + farming_reward_contract_addr: string; + pegged_pair_configs: ICBridgePeggedPairConfig[]; + blocked_bridge_direct: { + symbol: string; + src_chain_id: string; + dst_chain_id: string; + }[]; + redirect_to_aggregators_config: { + symbol: string; + src_chain_id: string; + dst_chain_id: string; + }[]; +} + +export interface ICBridgeTokenValidateParams { + isPegged: boolean; + fromChainId?: number; + fromTokenAddress: `0x${string}`; + fromTokenSymbol: string; + fromTokenDecimals: number; + bridgeAddress: `0x${string}`; + toChainId?: number; + toTokenAddress?: `0x${string}`; + toTokenSymbol?: string; + toTokenDecimals: number; + amount: number; + cBridgeEndpoint: string; +} diff --git a/packages/canonical-bridge-sdk/src/core/constants/index.ts b/packages/canonical-bridge-sdk/src/core/constants/index.ts index ad959ee2..26212033 100644 --- a/packages/canonical-bridge-sdk/src/core/constants/index.ts +++ b/packages/canonical-bridge-sdk/src/core/constants/index.ts @@ -8,3 +8,5 @@ export const EXPLORER_URL: Record<(typeof ExplorerList)[number], string> = { cBridge: 'https://celerscan.com/tx/', deBridge: 'https://app.debridge.finance/orders?s=', }; + +export const VALIDATION_API_TIMEOUT = 10 * 1000; diff --git a/packages/canonical-bridge-sdk/src/core/utils/address.ts b/packages/canonical-bridge-sdk/src/core/utils/address.ts index f69f6324..46e27b6b 100644 --- a/packages/canonical-bridge-sdk/src/core/utils/address.ts +++ b/packages/canonical-bridge-sdk/src/core/utils/address.ts @@ -9,3 +9,46 @@ export function isSameAddress(A?: string, B?: string) { export function isEvmAddress(address?: string) { return !!address && /^0x[a-f0-9]{40}$/i.test(address); } + +export function isSolanaAddress(address?: string) { + return !!address && /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(address); +} + +export function isTronAddress(address?: string) { + return !!address && /^T[a-zA-Z0-9]{33}$/.test(address); +} + +export const isValidTokenAddress = ({ + contractAddress, + chainType, + isSourceChain, +}: { + contractAddress: string; + chainType: string; + isSourceChain: boolean; +}) => { + const fromOrTo = isSourceChain ? 'from' : 'to'; + if (chainType === 'evm') { + if (!isEvmAddress(contractAddress)) { + console.log( + `Invalid evm ${fromOrTo} contract address`, + chainType, + contractAddress + ); + return false; + } + } else if (chainType === 'solana') { + if (!isSolanaAddress(contractAddress)) { + console.log( + `Invalid solana ${fromOrTo} contract address`, + chainType, + contractAddress + ); + return false; + } + } else { + console.log(`Invalid ${fromOrTo} chain type`, chainType, contractAddress); + return false; + } + return true; +}; diff --git a/packages/canonical-bridge-sdk/src/debridge/index.ts b/packages/canonical-bridge-sdk/src/debridge/index.ts index b643bd58..47ea3f6e 100644 --- a/packages/canonical-bridge-sdk/src/debridge/index.ts +++ b/packages/canonical-bridge-sdk/src/debridge/index.ts @@ -1,5 +1,5 @@ import { createAdapter } from '@/debridge/utils/createAdapter'; -import { CLIENT_TIME_OUT } from '@/core/constants'; +import { CLIENT_TIME_OUT, VALIDATION_API_TIMEOUT } from '@/core/constants'; import { BaseBridgeConfigOptions, BaseBridgeConfig, @@ -9,10 +9,13 @@ import { DeBridgeCreateQuoteResponse, DeBridgeTransferConfigs, IDeBridgeEstimatedFeesInput, + IDeBridgeToken, + IDeBridgeTokenValidateParams, ISendDebridgeTokenInput, } from '@/debridge/types'; import axios, { AxiosInstance } from 'axios'; import { Hash } from 'viem'; +import { isValidTokenAddress } from '@/core/utils/address'; export * from './types'; @@ -177,6 +180,158 @@ export class DeBridge { } } + validateDeBridgeToken = async ({ + fromChainId, + fromChainType, + toChainId, + toChainType, + fromTokenAddress, + fromTokenSymbol, + fromTokenDecimals, + fromBridgeAddress, + toTokenAddress, + toTokenSymbol, + toTokenDecimals, + amount, + deBridgeEndpoint, + }: IDeBridgeTokenValidateParams) => { + try { + // Check amount + if (Number(amount) <= 0) { + console.log('Invalid deBridge amount', amount); + return false; + } + if ( + !fromChainId || + !fromChainType || + !fromTokenAddress || + !toTokenAddress || + !fromTokenSymbol || + !toTokenSymbol || + !toChainId || + !toChainType || + !amount || + !fromTokenDecimals || + (!fromBridgeAddress && fromChainType === 'evm') || + !toTokenDecimals || + !deBridgeEndpoint + ) { + console.log('Invalid deBridge token validation params'); + console.log('-- fromChainId', fromChainId); + console.log('-- fromChainType', fromChainType); + console.log('-- fromTokenSymbol', fromTokenSymbol); + console.log('-- fromTokenAddress', fromTokenAddress); + console.log('-- fromTokenDecimals', fromTokenDecimals); + console.log('-- fromBridgeAddress', fromBridgeAddress); + console.log('-- toChainId', toChainId); + console.log('-- toChainType', toChainType); + console.log('-- toTokenSymbol', toTokenSymbol); + console.log('-- toTokenAddress', toTokenAddress); + console.log('-- toTokenDecimals', toTokenDecimals); + console.log('-- amount', amount); + console.log('-- deBridgeEndpoint', deBridgeEndpoint); + return false; + } + // Check from token address + const isValidFromToken = isValidTokenAddress({ + contractAddress: fromTokenAddress, + chainType: fromChainType, + isSourceChain: true, + }); + // Check to token address + const isValidToToken = isValidTokenAddress({ + contractAddress: toTokenAddress, + chainType: toChainType, + isSourceChain: true, + }); + if (!isValidFromToken || !isValidToToken) { + console.log( + 'Invalid deBridge bridge token address', + fromTokenAddress, + toTokenAddress + ); + return false; + } + // Check bridge contract address + if (fromChainType !== 'solana') { + const isValidBridgeContractAddress = isValidTokenAddress({ + contractAddress: fromBridgeAddress, + chainType: fromChainType, + isSourceChain: true, + }); + if (!isValidBridgeContractAddress) { + console.log( + 'Invalid deBridge bridge contract address', + fromBridgeAddress + ); + return false; + } + } + // Check token info on API + const fromRequest = axios.get<{ + tokens: { [key: string]: IDeBridgeToken }; + }>(`${deBridgeEndpoint}/token-list?chainId=${fromChainId}`, { + timeout: VALIDATION_API_TIMEOUT, + }); + const toRequest = axios.get<{ + tokens: { [key: string]: IDeBridgeToken }; + }>(`${deBridgeEndpoint}/token-list?chainId=${toChainId}`, { + timeout: VALIDATION_API_TIMEOUT, + }); + const [fromTokenList, toTokenList] = await Promise.allSettled([ + fromRequest, + toRequest, + ]); + if ( + fromTokenList.status === 'fulfilled' && + toTokenList.status === 'fulfilled' + ) { + const fromToken = + fromTokenList?.value?.data.tokens[fromTokenAddress.toLowerCase()]; + const toToken = + toTokenList?.value?.data.tokens[toTokenAddress.toLowerCase()]; + if ( + !!fromToken && + fromToken?.address.toLowerCase() === fromTokenAddress.toLowerCase() && + fromToken?.symbol === fromTokenSymbol && + fromToken?.decimals === fromTokenDecimals && + !!toToken && + toToken?.address.toLowerCase() === toTokenAddress.toLowerCase() && + toToken?.symbol === toTokenSymbol && + toToken?.decimals === toTokenDecimals + ) { + console.log('deBridge token info matched', fromToken); + return true; + } + } else { + console.log( + 'Failed to get deBridge API token info', + fromTokenList, + toTokenList + ); + return false; + } + console.log('Could not find deBridge token info'); + console.log('-- fromChainId', fromChainId); + console.log('-- from fromChainType', fromChainType); + console.log('-- from tokenSymbol', fromTokenSymbol); + console.log('-- from tokenAddress', fromTokenAddress); + console.log('-- from TokenDecimals', fromTokenDecimals); + console.log('-- to ChainId', toChainId); + console.log('-- to ChainType', toChainType); + console.log('-- to tokenSymbol', toTokenSymbol); + console.log('-- to tokenAddress', toTokenAddress); + console.log('-- to TokenDecimals', toTokenDecimals); + console.log('-- amount', amount); + return false; + // eslint-disable-next-line + } catch (error: any) { + // eslint-disable-next-line no-console + console.log('deBridge token validation error', error); + return false; + } + }; + /** @see createAdapter for implementation details */ createAdapter(params: CreateAdapterParameters) { return createAdapter(params); diff --git a/packages/canonical-bridge-sdk/src/debridge/types/index.ts b/packages/canonical-bridge-sdk/src/debridge/types/index.ts index c85b9c32..84f6fdbb 100644 --- a/packages/canonical-bridge-sdk/src/debridge/types/index.ts +++ b/packages/canonical-bridge-sdk/src/debridge/types/index.ts @@ -99,3 +99,30 @@ export interface TokenQueryParams { chainId: number; address: string; } + +export interface IDeBridgeToken { + address: string; + symbol: string; + decimals: number; + name: string; + logoURI: string | null; + eip2612?: boolean; + tags: string[]; + domainVersion?: string; +} + +export interface IDeBridgeTokenValidateParams { + fromTokenAddress: string; + fromBridgeAddress: string; + fromTokenSymbol: string; + fromChainId?: number; + fromChainType?: string; + toTokenAddress: string; + toTokenSymbol?: string; + toChainId?: number; + toChainType?: string; + amount: number; + fromTokenDecimals?: number; + toTokenDecimals?: number; + deBridgeEndpoint: string; +} diff --git a/packages/canonical-bridge-sdk/src/layerZero/index.ts b/packages/canonical-bridge-sdk/src/layerZero/index.ts index e250cbbd..f14e6170 100644 --- a/packages/canonical-bridge-sdk/src/layerZero/index.ts +++ b/packages/canonical-bridge-sdk/src/layerZero/index.ts @@ -1,9 +1,12 @@ import { CreateAdapterParameters } from '@/core'; +import { ERC20_TOKEN } from '@/core/abi/erc20Token'; +import { isEvmAddress } from '@/core/utils/address'; import { formatNumber } from '@/core/utils/number'; import { CAKE_PROXY_OFT_ABI } from '@/layerZero/abi/cakeProxyOFT'; import { IGetEstimateFeeInput, ISendCakeTokenInput, + LayerZeroTokenValidateParams, LayerZeroTransferConfigs, } from '@/layerZero/types'; import { createAdapter } from '@/layerZero/utils/createAdapter'; @@ -166,6 +169,159 @@ export class LayerZero { } } + validateLayerZeroToken = async ({ + fromPublicClient, + toPublicClient, + bridgeAddress, + fromTokenAddress, + fromTokenSymbol, + fromTokenDecimals, + toTokenAddress, + toTokenSymbol, + toTokenDecimals, + toBridgeAddress, + dstEndpoint, + amount, + }: LayerZeroTokenValidateParams) => { + // Check amount + if (Number(amount) <= 0) { + console.log('Invalid send amount'); + return false; + } + if ( + !fromPublicClient || + !bridgeAddress || + !fromTokenAddress || + !fromTokenDecimals || + !dstEndpoint || + !toTokenAddress || + !toBridgeAddress || + !toTokenSymbol || + !toTokenDecimals || + !toPublicClient + ) { + console.log('Missing required parameters'); + console.log('-- publicClient', fromPublicClient); + console.log('-- toPublicClient', toPublicClient); + console.log('-- bridgeAddress', bridgeAddress); + console.log('-- fromTokenAddress', fromTokenAddress); + console.log('-- fromTokenSymbol', fromTokenSymbol); + console.log('-- fromTokenDecimals', fromTokenDecimals); + console.log('-- toTokenAddress', toTokenAddress); + console.log('-- toBridgeAddress', toBridgeAddress); + console.log('-- toTokenSymbol', toTokenSymbol); + console.log('-- toTokenDecimals', toTokenDecimals); + console.log('-- dstEndpoint', dstEndpoint); + console.log('-- amount', amount); + return false; + } + // Check evm contract address + if ( + !isEvmAddress(fromTokenAddress) || + !isEvmAddress(toTokenAddress) || + !isEvmAddress(toBridgeAddress) || + !isEvmAddress(bridgeAddress) + ) { + console.log('Invalid contract address'); + console.log('-- fromTokenAddress', fromTokenAddress); + console.log('-- toTokenAddress', toTokenAddress); + console.log('-- toBridgeAddress', toBridgeAddress); + console.log('-- bridgeAddress', bridgeAddress); + return false; + } + + // Check symbol from token contract address + const contractSymbol = await fromPublicClient.readContract({ + address: fromTokenAddress as `0x${string}`, + abi: ERC20_TOKEN, + functionName: 'symbol', + }); + if (contractSymbol.toLowerCase() !== fromTokenSymbol.toLowerCase()) { + console.log( + 'Failed to match from token symbol', + fromTokenSymbol, + contractSymbol + ); + return false; + } + const contractDecimals = await fromPublicClient.readContract({ + address: fromTokenAddress as `0x${string}`, + abi: ERC20_TOKEN, + functionName: 'decimals', + }); + if (fromTokenDecimals !== contractDecimals) { + console.log('Failed to match from token decimals'); + return false; + } + // Remote contract address validation + const trustedRemoteAddress = await fromPublicClient.readContract({ + address: bridgeAddress as `0x${string}`, + abi: CAKE_PROXY_OFT_ABI, + functionName: 'getTrustedRemoteAddress', + args: [dstEndpoint], + }); + if (trustedRemoteAddress.toLowerCase() !== toBridgeAddress.toLowerCase()) { + console.log( + 'Failed to match layerZero remote contract address', + trustedRemoteAddress, + toBridgeAddress + ); + return false; + } + // Check to token contract address + const toTokenContractSymbol = await toPublicClient.readContract({ + address: toTokenAddress as `0x${string}`, + abi: ERC20_TOKEN, + functionName: 'symbol', + }); + if (toTokenContractSymbol.toLowerCase() !== toTokenSymbol.toLowerCase()) { + console.log( + 'Failed to match to token symbol', + toTokenSymbol, + toTokenContractSymbol + ); + return false; + } + const toTokenContractDecimals = await toPublicClient.readContract({ + address: toTokenAddress as `0x${string}`, + abi: ERC20_TOKEN, + functionName: 'decimals', + }); + if (toTokenDecimals !== toTokenContractDecimals) { + console.log('Failed to match to token decimals'); + return false; + } + // Supported token validation + const supportedFromToken = await fromPublicClient.readContract({ + address: bridgeAddress as `0x${string}`, + abi: CAKE_PROXY_OFT_ABI, + functionName: 'token', + }); + const supportedToToken = await toPublicClient.readContract({ + address: toBridgeAddress as `0x${string}`, + abi: CAKE_PROXY_OFT_ABI, + functionName: 'token', + }); + if ( + supportedFromToken.toLowerCase() === fromTokenAddress.toLowerCase() && + supportedToToken.toLowerCase() === toTokenAddress.toLowerCase() + ) { + console.log('LayerZero token information matched'); + console.log('From token address', fromTokenAddress, supportedFromToken); + console.log('To token address', toTokenAddress, supportedToToken); + return true; + } + console.log('Failed to match layerZero token information'); + console.log('-- publicClient', fromPublicClient); + console.log('-- bridgeAddress', bridgeAddress); + console.log('-- fromTokenAddress', fromTokenAddress); + console.log('-- fromTokenSymbol', fromTokenSymbol); + console.log('-- toTokenAddress', toTokenAddress); + console.log('-- toBridgeAddress', toBridgeAddress); + console.log('-- dstEndpoint', dstEndpoint); + return false; + }; + /** @see createAdapter for implementation details */ createAdapter(params: CreateAdapterParameters) { return createAdapter(params); diff --git a/packages/canonical-bridge-sdk/src/layerZero/types/index.ts b/packages/canonical-bridge-sdk/src/layerZero/types/index.ts index 915e3672..2a4901d8 100644 --- a/packages/canonical-bridge-sdk/src/layerZero/types/index.ts +++ b/packages/canonical-bridge-sdk/src/layerZero/types/index.ts @@ -46,3 +46,18 @@ export interface LayerZeroTransferConfigs { chains: LayerZeroChain[]; tokens: Record; } + +export interface LayerZeroTokenValidateParams { + fromPublicClient: PublicClient; + toPublicClient: PublicClient; + bridgeAddress: `0x${string}`; + fromTokenAddress: `0x${string}`; + fromTokenSymbol: string; + fromTokenDecimals: number; + toTokenAddress: `0x${string}`; + toTokenSymbol: string; + toTokenDecimals: number; + toBridgeAddress: `0x${string}`; + dstEndpoint?: number; + amount: number; +} diff --git a/packages/canonical-bridge-sdk/src/meson/index.ts b/packages/canonical-bridge-sdk/src/meson/index.ts index 01b7385f..44749cf8 100644 --- a/packages/canonical-bridge-sdk/src/meson/index.ts +++ b/packages/canonical-bridge-sdk/src/meson/index.ts @@ -5,6 +5,12 @@ import { IMesonSendTokenInput, } from '@/meson/types'; import { BaseBridgeConfig } from '@/core'; +import { isEvmAddress, isTronAddress } from '@/core/utils/address'; +import { + IMesonTokenList, + IMesonTokenValidateParams, +} from '@/meson/types/index'; +import { VALIDATION_API_TIMEOUT } from '@/core/constants'; export class Meson { private client?: AxiosInstance; @@ -98,4 +104,158 @@ export class Meson { } } } + + validateMesonToken = async ({ + fromChainId, + fromChainType, + fromTokenSymbol, + fromTokenAddress, + fromTokenDecimals, + toTokenAddress, + toChainId, + toChainType, + toTokenSymbol, + toTokenDecimals, + amount, + mesonEndpoint, + }: IMesonTokenValidateParams) => { + try { + if (Number(amount) <= 0) { + console.log('Invalid token amount'); + return false; + } + if ( + !fromChainId || + !fromTokenAddress || + !fromTokenSymbol || + !fromTokenDecimals || + !fromChainType || + !toChainId || + !toTokenAddress || + !toTokenDecimals || + !toChainType || + !toTokenSymbol || + !amount || + !mesonEndpoint + ) { + console.log('Missing Meson required params'); + console.log('-- fromChainId', fromChainId); + console.log('-- fromTokenAddress', fromTokenAddress); + console.log('-- fromTokenSymbol', fromTokenSymbol); + console.log('-- fromTokenDecimals', fromTokenDecimals); + console.log('-- fromChainType', fromChainType); + console.log('-- toChainId', toChainId); + console.log('-- toTokenAddress', toTokenAddress); + console.log('-- toTokenDecimals', toTokenDecimals); + console.log('-- toChainType', toChainType); + console.log('-- toTokenSymbol', toTokenSymbol); + console.log('-- amount', amount); + console.log('-- mesonEndpoint', mesonEndpoint); + return false; + } + if (fromTokenSymbol.toLowerCase() !== toTokenSymbol.toLowerCase()) { + console.log('Invalid token symbol', fromTokenSymbol, toTokenSymbol); + return false; + } + // from token address + if (fromChainType === 'evm') { + if (!isEvmAddress(fromTokenAddress)) { + console.log('Invalid from token address', fromTokenAddress); + + return false; + } + } else if (fromChainType === 'tron') { + if (!isTronAddress(fromTokenAddress)) { + console.log('Invalid from token address', fromTokenAddress); + return false; + } + } else { + console.log('Invalid from chain type', fromChainType); + return false; + } + // to token address + if (toChainType === 'evm') { + if (!isEvmAddress(toTokenAddress)) { + console.log('Invalid to token address', toTokenAddress); + return false; + } + } else if (toChainType === 'tron') { + if (!isTronAddress(toTokenAddress)) { + console.log('Invalid to token address', toTokenAddress); + return false; + } + } else { + console.log('Invalid to chain type', toChainType); + return false; + } + // Check token information from Meson API + const { data: mesonConfig } = await axios.get<{ + result: IMesonTokenList[]; + }>(`${mesonEndpoint}/limits`, { timeout: VALIDATION_API_TIMEOUT }); + const fromHexNum = fromChainId?.toString(16); + const toHexNum = toChainId?.toString(16); + // from token validation + const validFromToken = mesonConfig.result.filter((chainInfo) => { + const fromTokenInfo = chainInfo.tokens.filter( + (token) => + (token?.addr?.toLowerCase() === fromTokenAddress.toLowerCase() && + token.decimals === fromTokenDecimals && + token.id === fromTokenSymbol.toLowerCase()) || + (!token?.addr && + fromTokenAddress === + '0x0000000000000000000000000000000000000000' && + token.decimals === fromTokenDecimals && + token.id === fromTokenSymbol.toLowerCase()) + ); + if (!!fromTokenInfo && fromTokenInfo.length > 0) { + console.log('Meson from token info', fromTokenInfo); + } + return ( + chainInfo.chainId === `0x${fromHexNum}` && + fromTokenInfo?.length > 0 && + !!fromTokenInfo + ); + }); + // to token validation + const validToToken = mesonConfig.result.filter((chainInfo) => { + const toTokenInfo = chainInfo.tokens.filter( + (token) => + (token?.addr?.toLowerCase() === toTokenAddress.toLowerCase() && + token.decimals === toTokenDecimals && + token.id === toTokenSymbol.toLowerCase()) || + (!token?.addr && + toTokenAddress === '0x0000000000000000000000000000000000000000' && + token.decimals === toTokenDecimals && + token.id === toTokenSymbol.toLowerCase()) + ); + if (!!toTokenInfo && toTokenInfo.length > 0) { + console.log('Meson to token info', toTokenInfo); + } + return ( + chainInfo.chainId === `0x${toHexNum}` && + toTokenInfo?.length > 0 && + !!toTokenInfo + ); + }); + if (validToToken?.length > 0 && validFromToken?.length > 0) { + console.log('Meson token info matched', validToToken, validFromToken); + return true; + } + console.log('Could not find Meson token'); + console.log('-- fromChainId', fromChainId); + console.log('-- fromTokenAddress', fromTokenAddress); + console.log('-- fromTokenSymbol', fromTokenSymbol); + console.log('-- fromChainType', fromChainType); + console.log('-- toChainId', toChainId); + console.log('-- toTokenAddress', toTokenAddress); + console.log('-- toChainType', toChainType); + console.log('-- toTokenSymbol', toTokenSymbol); + console.log('-- amount', amount); + return false; + // eslint-disable-next-line + } catch (error: any) { + console.log('Meson token validation error', error); + return false; + } + }; } diff --git a/packages/canonical-bridge-sdk/src/meson/types/index.ts b/packages/canonical-bridge-sdk/src/meson/types/index.ts index 8be3f09e..9789a982 100644 --- a/packages/canonical-bridge-sdk/src/meson/types/index.ts +++ b/packages/canonical-bridge-sdk/src/meson/types/index.ts @@ -4,3 +4,34 @@ export interface IGetMesonEstimateFeeInput { fromAddr: string; amount: string; } + +export interface IMesonTokenLimits { + id: string; + decimals: number; + addr?: `0x${string}`; + min: string; + max: string; +} + +export interface IMesonTokenList { + id: string; + name: string; + chainId: `0x${string}`; + address: `0x${string}`; + tokens: IMesonTokenLimits[]; +} + +export interface IMesonTokenValidateParams { + fromChainId?: number; + toChainId?: number; + fromTokenSymbol: string; + fromTokenAddress: `0x${string}`; + fromTokenDecimals: number; + fromChainType?: string; + toTokenAddress?: `0x${string}`; + toTokenDecimals?: number; + toChainType?: string; + toTokenSymbol?: string; + amount: number; + mesonEndpoint: string; +} diff --git a/packages/canonical-bridge-sdk/src/stargate/const/index.ts b/packages/canonical-bridge-sdk/src/stargate/const/index.ts new file mode 100644 index 00000000..d1ae31e5 --- /dev/null +++ b/packages/canonical-bridge-sdk/src/stargate/const/index.ts @@ -0,0 +1,24 @@ +export const stargateChainKey: { [key: number]: string } = { + 1: 'ethereum', + 10: 'optimism', + 14: 'flare', + 56: 'bsc', + 137: 'polygon', + 250: 'fantom', + 1088: 'metis', + 1116: 'coredao', + 1329: 'sei', + 1625: 'gravity', + 2222: 'kava', + 5000: 'mantle', + 8217: 'klaytn', + 8453: 'base', + 8822: 'iota', + 42161: 'arbitrum', + 43114: 'avalanche', + 59144: 'linea', + 167000: 'taiko', + 534352: 'scroll', + 1313161554: 'aurora', + 1380012617: 'rarible', +}; diff --git a/packages/canonical-bridge-sdk/src/stargate/index.ts b/packages/canonical-bridge-sdk/src/stargate/index.ts index 8c31d68e..d4a7f20a 100644 --- a/packages/canonical-bridge-sdk/src/stargate/index.ts +++ b/packages/canonical-bridge-sdk/src/stargate/index.ts @@ -1,15 +1,19 @@ -import { CLIENT_TIME_OUT } from '@/core/constants'; +import { CLIENT_TIME_OUT, VALIDATION_API_TIMEOUT } from '@/core/constants'; import { BaseBridgeConfig, BaseBridgeConfigOptions, CreateAdapterParameters, } from '@/core/types'; +import { isEvmAddress } from '@/core/utils/address'; import { STARGATE_POOL } from '@/stargate/abi/stargatePool'; +import { stargateChainKey } from '@/stargate/const'; import { ISendTokenInput, IStarGateBusDriveSettings, IStargateOFTQuote, IStargateQuoteOFT, + IStargateTokenList, + IStargateTokenValidateParams, StarGateTransferConfigs, } from '@/stargate/types'; import { createAdapter } from '@/stargate/utils/createAdapter'; @@ -186,6 +190,202 @@ export class Stargate { } } + /** + * Validate token information + * @param {fromBridgeAddress} from chain bridge contract address + * @param {fromTokenAddress} from token address + * @param {fromTokenSymbol} from token symbol + * @param {fromChainId} from chain id + * @param {toTokenAddress} to token address + * @param {toTokenSymbol} to token symbol + * @param {toChainId} to chain id + * @param {toBridgeAddress} to chain bridge contract address + * @param {amount} send token amount + * @param {toPublicClient} to chain public client + * @param {fromPublicClient} from chain public client + * @param {dstEndpointId} Stargate destination endpoint id + * @param {stargateEndpoint} Stargate API endpoint + * @returns {boolean} is token information valid or not + */ + async validateStargateToken({ + fromBridgeAddress, + fromTokenAddress, + fromTokenDecimals, + fromTokenSymbol, + fromChainId, + toTokenAddress, + toTokenSymbol, + toTokenDecimals, + toChainId, + toBridgeAddress, + amount, + toPublicClient, + fromPublicClient, + dstEndpointId, + stargateEndpoint, + }: IStargateTokenValidateParams) { + try { + if (amount <= 0) { + console.log('Invalid amount', amount); + return false; + } + // Check params exist + if ( + !fromChainId || + !fromTokenAddress || + !fromTokenSymbol || + !fromTokenDecimals || + !fromBridgeAddress || + !toBridgeAddress || + !toTokenAddress || + !toTokenSymbol || + !toTokenDecimals || + !toChainId || + !amount || + !toPublicClient || + !fromPublicClient || + !dstEndpointId + ) { + console.log('Missing Stargate params'); + console.log('-- from ChainId', fromChainId); + console.log('-- from TokenAddress', fromTokenAddress); + console.log('-- from TokenSymbol', fromTokenSymbol); + console.log('-- from TokenDecimals', fromTokenDecimals); + console.log('-- from bridgeAddress', fromBridgeAddress); + console.log('-- to ChainId', toChainId); + console.log('-- to TokenAddress', toTokenAddress); + console.log('-- to bridgeAddress', toBridgeAddress); + console.log('-- to TokenSymbol', toTokenSymbol); + console.log('-- to TokenDecimals', toTokenDecimals); + console.log('-- amount', amount); + console.log('-- to PublicClient', toPublicClient); + console.log('-- from PublicClient', fromPublicClient); + console.log('-- dstEndpointId', dstEndpointId); + console.log('-- stargateEndpoint', stargateEndpoint); + return false; + } + // Check token address and bridge address + if ( + !isEvmAddress(fromTokenAddress) || + !isEvmAddress(fromBridgeAddress) || + !isEvmAddress(toBridgeAddress) || + !isEvmAddress(toTokenAddress) + ) { + console.log( + 'Invalid Stargate Evm Address', + fromTokenAddress, + fromBridgeAddress, + toBridgeAddress, + toTokenAddress + ); + return false; + } + const fromChainKey = stargateChainKey[fromChainId] ?? ''; + const toChainKey = stargateChainKey[toChainId] ?? ''; + + if (!fromChainKey || !toChainKey) { + console.log('Failed to get chain key'); + console.log('From chain key', fromChainKey, fromChainId); + console.log('To chain key', toChainKey, toChainId); + return false; + } + // Check Stargate from chain information + const fromApiTokenAddr = await fromPublicClient.readContract({ + address: fromBridgeAddress as `0x${string}`, + abi: STARGATE_POOL, + functionName: 'token', + }); + if (fromApiTokenAddr.toLowerCase() !== fromTokenAddress.toLowerCase()) { + console.log('Stargate from token address not matched'); + console.log('fromBridgeAddress', fromBridgeAddress); + console.log('from token address in API', fromApiTokenAddr); + return false; + } + // Check Stargate to chain information + const dstId = await toPublicClient.readContract({ + address: toBridgeAddress as `0x${string}`, + abi: STARGATE_POOL, + functionName: 'localEid', + }); + if (dstId !== dstEndpointId) { + console.log('Stargate endpoint Id not matched', dstId, dstEndpointId); + return false; + } + const toApiTokenAddr = await toPublicClient.readContract({ + address: toBridgeAddress as `0x${string}`, + abi: STARGATE_POOL, + functionName: 'token', + }); + if (toApiTokenAddr.toLowerCase() !== toTokenAddress.toLowerCase()) { + console.log( + 'Stargate to token address not matched', + toApiTokenAddr, + toTokenAddress + ); + return false; + } + // Check token information from API + const { data: stargateConfig } = await axios.get<{ + data: IStargateTokenList; + }>(`${stargateEndpoint}`, { timeout: VALIDATION_API_TIMEOUT }); + if (!stargateConfig) { + console.log('Failed to get Stargate API config'); + return false; + } + // From token info + const fromTokenInfo = stargateConfig.data?.v2?.filter((fromToken) => { + return ( + fromToken.chainKey.toLowerCase() === fromChainKey.toLowerCase() && + fromToken.address.toLowerCase() === fromBridgeAddress.toLowerCase() && // bridge contract address + fromToken.token.decimals === fromTokenDecimals && + fromToken.token.symbol.toLowerCase() === + fromTokenSymbol.toLowerCase() && + fromToken.token.address.toLowerCase() === + fromTokenAddress.toLowerCase() + ); + }); + // To token info + const toTokenInfo = stargateConfig.data?.v2?.filter((toToken) => { + return ( + toToken.chainKey.toLowerCase() === toChainKey.toLowerCase() && + toToken.address.toLowerCase() === toBridgeAddress.toLowerCase() && + toToken.token.symbol.toLowerCase() === toTokenSymbol.toLowerCase() && + toToken.token.decimals === toTokenDecimals && + toToken.token.address.toLowerCase() === toTokenAddress.toLowerCase() + ); + }); + + if ( + !!fromTokenInfo && + fromTokenInfo.length > 0 && + !!toTokenInfo && + toTokenInfo.length > 0 + ) { + console.log('Stargate token info matched'); + console.log('fromTokenInfo', fromTokenInfo); + console.log('toTokenInfo', toTokenInfo); + return true; + } + console.log('Could not find Stargate token info'); + console.log('-- from ChainId', fromChainId); + console.log('-- from TokenAddress', fromTokenAddress); + console.log('-- from TokenSymbol', fromTokenSymbol); + console.log('-- from bridgeAddress', fromBridgeAddress); + console.log('-- to ChainId', toChainId); + console.log('-- to TokenAddress', toTokenAddress); + console.log('-- to TokenSymbol', toTokenSymbol); + console.log('-- to PublicClient', toPublicClient); + console.log('-- to bridgeAddress', toBridgeAddress); + console.log('-- amount', amount); + console.log('-- dstEndpointId', dstEndpointId); + return false; + // eslint-disable-next-line + } catch (error: any) { + console.log('Stargate token validation error', error); + return false; + } + } + /** @see createAdapter for implementation details */ createAdapter(params: CreateAdapterParameters) { return createAdapter(params); diff --git a/packages/canonical-bridge-sdk/src/stargate/types/index.ts b/packages/canonical-bridge-sdk/src/stargate/types/index.ts index adb5249b..adb5d62b 100644 --- a/packages/canonical-bridge-sdk/src/stargate/types/index.ts +++ b/packages/canonical-bridge-sdk/src/stargate/types/index.ts @@ -67,3 +67,63 @@ export interface ISendTokenInput { receiver: `0x${string}`; amount: bigint; } + +export interface IStargateTokenValidateParams { + fromBridgeAddress: `0x${string}`; + toBridgeAddress: `0x${string}`; + fromTokenAddress: `0x${string}`; + fromTokenSymbol: string; + fromTokenDecimals: number; + fromChainId?: number; + toTokenAddress: `0x${string}`; + toTokenSymbol: string; + toTokenDecimals: number; + toChainId?: number; + amount: number; + toPublicClient: PublicClient; + fromPublicClient: PublicClient; + dstEndpointId: number; + stargateEndpoint: string; +} + +export interface IStargateBridgeTokenInfo { + stargateType: string; + address: `0x${string}`; + token: { + address: `0x${string}`; + decimals: number; + symbol: string; + }; + lpToken: { + address: `0x${string}`; + decimals: number; + symbol: string; + }; + farm: { + stargateStaking: { + address: `0x${string}`; + rewardTokens: [ + { + address: `0x${string}`; + decimals: number; + symbol: string; + }, + { + address: `0x${string}`; + decimals: number; + symbol: string; + } + ]; + }; + }; + id: string; + assetId: string; + chainKey: string; + chainName: string; + tokenMessaging: `0x${string}`; + sharedDecimals: number; +} +export interface IStargateTokenList { + v1: IStargateBridgeTokenInfo[]; + v2: IStargateBridgeTokenInfo[]; +} diff --git a/packages/canonical-bridge-sdk/tsconfig.json b/packages/canonical-bridge-sdk/tsconfig.json index 4d2effe1..cb9dd48c 100644 --- a/packages/canonical-bridge-sdk/tsconfig.json +++ b/packages/canonical-bridge-sdk/tsconfig.json @@ -5,6 +5,7 @@ "lib": ["ES2020", "DOM", "DOM.Iterable"], "module": "ESNext", "skipLibCheck": true, + "esModuleInterop": true, /* Bundler mode */ "moduleResolution": "bundler", diff --git a/packages/canonical-bridge-widget/src/core/constants/index.ts b/packages/canonical-bridge-widget/src/core/constants/index.ts index f1e3254c..3fcb0064 100644 --- a/packages/canonical-bridge-widget/src/core/constants/index.ts +++ b/packages/canonical-bridge-widget/src/core/constants/index.ts @@ -15,6 +15,11 @@ export const DEFAULT_ADDRESS = '0x6836CbaCbBd1E798cC56802AC7d8BDf6Da0d0980'; export const DEFAULT_TRON_ADDRESS = 'TTb3A6ASFejJuGcM1UVcRCJA23WGiJKSiY'; export const DEFAULT_SOLANA_ADDRESS = 'J7JYXS8PMMBgfFKP1bqUu7mGgWyWUDL9xqfYujznc61r'; +export const CBRIDGE_ENDPOINT = 'https://cbridge-prod2.celer.app/v2'; +export const DEBRIDGE_ENDPOINT = 'https://deswap.debridge.finance/v1.0'; +export const STARGATE_ENDPOINT = 'https://mainnet.stargate-api.com/v1/metadata?version=v2'; +export const MESON_ENDPOINT = 'https://relayer.meson.fi/api/v1'; + export const nativeTokenMap = { 1: 'ETH', 10: 'ETH', diff --git a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/layerZero/components/LayerZeroOption.tsx b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/layerZero/components/LayerZeroOption.tsx index 6068b4a2..301610bc 100644 --- a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/layerZero/components/LayerZeroOption.tsx +++ b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/layerZero/components/LayerZeroOption.tsx @@ -59,7 +59,7 @@ export const LayerZeroOption = () => { return ( diff --git a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/meson/types.ts b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/meson/types.ts index eaa25eb3..fc107639 100644 --- a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/meson/types.ts +++ b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/meson/types.ts @@ -13,3 +13,19 @@ export interface IMesonChain { address: string; // bridge address tokens: IMesonToken[]; } + +interface IMesonTokenLimits { + id: string; + decimals: number; + addr?: `0x${string}`; + min: string; + max: string; +} + +export interface IMesonTokenList { + id: string; + name: string; + chainId: `0x${string}`; + address: `0x${string}`; + tokens: IMesonTokenLimits[]; +} diff --git a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/const/index.ts b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/const/index.ts new file mode 100644 index 00000000..d1ae31e5 --- /dev/null +++ b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/const/index.ts @@ -0,0 +1,24 @@ +export const stargateChainKey: { [key: number]: string } = { + 1: 'ethereum', + 10: 'optimism', + 14: 'flare', + 56: 'bsc', + 137: 'polygon', + 250: 'fantom', + 1088: 'metis', + 1116: 'coredao', + 1329: 'sei', + 1625: 'gravity', + 2222: 'kava', + 5000: 'mantle', + 8217: 'klaytn', + 8453: 'base', + 8822: 'iota', + 42161: 'arbitrum', + 43114: 'avalanche', + 59144: 'linea', + 167000: 'taiko', + 534352: 'scroll', + 1313161554: 'aurora', + 1380012617: 'rarible', +}; diff --git a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/types.ts b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/types.ts index 95ca11c2..5e90f9de 100644 --- a/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/types.ts +++ b/packages/canonical-bridge-widget/src/modules/aggregator/adapters/stargate/types.ts @@ -39,3 +39,46 @@ export interface IStargateBusDriveSettings { maxWaitTime: number; passengersToDrive: number; } + +export interface IStargateBridgeTokenInfo { + stargateType: string; + address: `0x${string}`; + token: { + address: `0x${string}`; + decimals: number; + symbol: string; + }; + lpToken: { + address: `0x${string}`; + decimals: number; + symbol: string; + }; + farm: { + stargateStaking: { + address: `0x${string}`; + rewardTokens: [ + { + address: `0x${string}`; + decimals: number; + symbol: string; + }, + { + address: `0x${string}`; + decimals: number; + symbol: string; + }, + ]; + }; + }; + id: string; + assetId: string; + chainKey: string; + chainName: string; + tokenMessaging: `0x${string}`; + sharedDecimals: number; +} + +export interface IStargateTokenList { + v1: IStargateBridgeTokenInfo[]; + v2: IStargateBridgeTokenInfo[]; +} diff --git a/packages/canonical-bridge-widget/src/modules/transfer/components/Button/TransferButton.tsx b/packages/canonical-bridge-widget/src/modules/transfer/components/Button/TransferButton.tsx index 91876e9f..efd65ea0 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/components/Button/TransferButton.tsx +++ b/packages/canonical-bridge-widget/src/modules/transfer/components/Button/TransferButton.tsx @@ -20,6 +20,12 @@ import { useTronContract } from '@/modules/aggregator/adapters/meson/hooks/useTr import { useSolanaTransferInfo } from '@/modules/transfer/hooks/solana/useSolanaTransferInfo'; import { useTronAccount } from '@/modules/wallet/hooks/useTronAccount'; import { useWaitForTxReceipt } from '@/core/hooks/useWaitForTxReceipt'; +import { + CBRIDGE_ENDPOINT, + DEBRIDGE_ENDPOINT, + MESON_ENDPOINT, + STARGATE_ENDPOINT, +} from '@/core/constants'; export function TransferButton({ onOpenSubmittedModal, @@ -67,6 +73,7 @@ export function TransferButton({ // eslint-disable-next-line @typescript-eslint/no-explicit-any const publicClient = usePublicClient({ chainId: fromChain?.id }) as any; + const toPublicClient = usePublicClient({ chainId: toChain?.id }) as any; const [isLoading, setIsLoading] = useState(false); const { allowance } = useGetAllowance({ @@ -171,6 +178,37 @@ export function TransferButton({ if (transferActionInfo.bridgeType === 'cBridge' && cBridgeArgs && fromChain && address) { try { + const isValidToken = await bridgeSDK.cBridge.validateCBridgeToken({ + isPegged: selectedToken.isPegged, + fromChainId: fromChain.id, + fromTokenAddress: selectedToken?.cBridge?.raw?.token.address as `0x${string}`, + fromTokenSymbol: selectedToken?.cBridge?.raw?.token?.symbol as string, + fromTokenDecimals: selectedToken.cBridge?.raw?.token.decimal as number, + bridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, + toChainId: toChain?.id, + toTokenAddress: toToken?.cBridge?.raw?.token.address as `0x${string}`, + toTokenSymbol: toToken?.cBridge?.raw?.token.symbol, + toTokenDecimals: toToken?.cBridge?.raw?.token.decimal as number, + amount: Number(sendValue), + cBridgeEndpoint: `${CBRIDGE_ENDPOINT}/getTransferConfigsForAll`, + }); + + if (!isValidToken) { + handleFailure({ + fromTokenAddress: selectedToken.address as `0x${string}`, + bridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, + fromChainId: fromChain.id, + isPegged: selectedToken.isPegged, + fromTokenSymbol: selectedToken.symbol, + toChainId: toChain?.id, + toTokenAddress: toToken?.cBridge?.raw?.token.address as `0x${string}`, + toTokenSymbol: toToken?.cBridge?.raw?.token.symbol, + decimals: selectedToken.decimals, + amount: Number(sendValue), + message: `(Token Validation Failed) - Invalid cBridge token!!`, + }); + return; + } const cBridgeHash = await bridgeSDK.cBridge.sendToken({ // eslint-disable-next-line @typescript-eslint/no-explicit-any walletClient: walletClient as any, @@ -212,7 +250,30 @@ export function TransferButton({ } else if (transferActionInfo.bridgeType === 'deBridge') { try { let deBridgeHash: string | undefined; - + const isValidToken = await bridgeSDK.deBridge.validateDeBridgeToken({ + fromChainId: fromChain?.id, + toChainId: toChain?.id, + fromTokenSymbol: selectedToken.symbol, + fromTokenAddress: selectedToken.deBridge?.raw?.address as `0x${string}`, + fromTokenDecimals: selectedToken.deBridge?.raw?.decimals as number, + toTokenSymbol: toToken?.deBridge?.raw?.symbol, + toTokenAddress: toToken?.deBridge?.raw?.address as `0x${string}`, + toTokenDecimals: toToken?.deBridge?.raw?.decimals as number, + amount: Number(sendValue), + fromChainType: fromChain?.chainType, + fromBridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, + toChainType: toChain?.chainType, + deBridgeEndpoint: DEBRIDGE_ENDPOINT, + }); + if (!isValidToken) { + handleFailure({ + message: '(Token Validation Failed) - Invalid deBridge token!!', + fromChainId: fromChain?.id, + tokenSymbol: selectedToken.symbol, + tokenAddress: selectedToken.address as `0x${string}`, + }); + return; + } if (fromChain?.chainType === 'evm' && transferActionInfo.value && address) { deBridgeHash = await bridgeSDK.deBridge.sendToken({ // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -265,6 +326,33 @@ export function TransferButton({ handleFailure(e); } } else if (transferActionInfo.bridgeType === 'stargate' && address) { + const isValidToken = await bridgeSDK.stargate.validateStargateToken({ + fromBridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, + toBridgeAddress: toToken?.stargate?.raw?.bridgeAddress as `0x${string}`, + fromTokenAddress: selectedToken?.stargate?.raw?.address as `0x${string}`, + fromTokenSymbol: selectedToken?.stargate?.raw?.symbol as string, + fromTokenDecimals: selectedToken?.stargate?.raw?.decimals as number, + fromChainId: fromChain?.id, + toTokenAddress: toToken?.stargate?.raw?.address as `0x${string}`, + toTokenSymbol: toToken?.stargate?.raw?.symbol as string, + toTokenDecimals: toToken?.stargate?.raw?.decimals as number, + toChainId: toChain?.id, + amount: Number(sendValue), + dstEndpointId: toToken?.stargate?.raw?.endpointID as number, + toPublicClient, + fromPublicClient: publicClient, + stargateEndpoint: STARGATE_ENDPOINT, + }); + if (!isValidToken) { + handleFailure({ + messages: '(Token Validation Failed) - Invalid Stargate token!!', + fromChainId: fromChain?.id, + tokenAddress: selectedToken.address as `0x${string}`, + bridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, + tokenSymbol: selectedToken.symbol, + }); + return; + } const stargateHash = await bridgeSDK.stargate.sendToken({ // eslint-disable-next-line @typescript-eslint/no-explicit-any walletClient: walletClient as any, @@ -292,6 +380,31 @@ export function TransferButton({ onOpenSubmittedModal(); } } else if (transferActionInfo.bridgeType === 'layerZero' && address) { + // check layerZero token address + const isValidToken = await bridgeSDK.layerZero.validateLayerZeroToken({ + fromPublicClient: publicClient, + toPublicClient, + bridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, + fromTokenAddress: selectedToken.layerZero?.raw?.address as `0x${string}`, + fromTokenSymbol: selectedToken.layerZero?.raw?.symbol as string, + fromTokenDecimals: selectedToken.layerZero?.raw?.decimals as number, + toTokenAddress: toToken?.layerZero?.raw?.address as `0x${string}`, + toTokenDecimals: toToken?.layerZero?.raw?.decimals as number, + toTokenSymbol: toToken?.layerZero?.raw?.symbol as string, + toBridgeAddress: toToken?.layerZero?.raw?.bridgeAddress as `0x${string}`, + dstEndpoint: toToken?.layerZero?.raw?.endpointID as number, + amount: Number(sendValue), + }); + if (!isValidToken) { + handleFailure({ + messages: '(Token Validation Failed) - Invalid LayerZero token!!', + fromChainId: fromChain?.id, + tokenAddress: selectedToken.layerZero?.raw?.address as `0x${string}`, + bridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, + tokenSymbol: selectedToken.symbol, + }); + return; + } const layerZeroHash = await bridgeSDK.layerZero.sendToken({ bridgeAddress: transferActionInfo.bridgeAddress as `0x${string}`, dstEndpoint: toToken?.layerZero?.raw?.endpointID as number, @@ -318,6 +431,29 @@ export function TransferButton({ onOpenSubmittedModal(); } } else if (transferActionInfo.bridgeType === 'meson') { + const isValidToken = await bridgeSDK.meson.validateMesonToken({ + fromChainId: fromChain?.id, + toChainId: toChain?.id, + fromTokenAddress: selectedToken.meson?.raw?.addr as `0x${string}`, + fromTokenSymbol: selectedToken.meson?.raw?.id as string, + fromTokenDecimals: selectedToken.meson?.raw?.decimals as number, + fromChainType: fromChain?.chainType, + toChainType: toChain?.chainType, + toTokenAddress: toToken?.meson?.raw?.addr as `0x${string}`, + toTokenSymbol: toToken?.meson?.raw?.id, + toTokenDecimals: toToken?.meson?.raw?.decimals, + amount: Number(sendValue), + mesonEndpoint: MESON_ENDPOINT, + }); + if (!isValidToken) { + handleFailure({ + message: '(Token Validation Failed) Invalid Meson token!!', + fromChainId: fromChain?.id, + tokenAddress: selectedToken.address as `0x${string}`, + tokenSymbol: selectedToken.symbol, + }); + return; + } let fromAddress = ''; let toAddress = ''; let msg = ''; @@ -377,7 +513,7 @@ export function TransferButton({ }); // eslint-disable-next-line no-console - console.log(swapId); + console.log('Meson swap id', swapId); if (swapId?.result?.swapId) { setChosenBridge('meson'); setHash(swapId?.result?.swapId); @@ -420,6 +556,7 @@ export function TransferButton({ fromChain, walletClient, publicClient, + toPublicClient, address, allowance, isEvmConnected, @@ -445,9 +582,13 @@ export function TransferButton({ onOpenSubmittedModal, connection, sendSolanaTransaction, - toToken?.stargate?.raw?.endpointID, - toToken?.layerZero?.raw?.endpointID, - toToken?.meson?.raw?.id, + toToken?.stargate?.raw, + toToken?.layerZero?.raw, + toToken?.meson?.raw, + toToken?.cBridge?.raw, + toToken?.deBridge?.raw, + toChain?.id, + toChain?.chainType, isTronTransfer, isTronAvailableToAccount, toAccount.address, diff --git a/packages/canonical-bridge-widget/src/modules/transfer/hooks/useLoadingBridgeFees.ts b/packages/canonical-bridge-widget/src/modules/transfer/hooks/useLoadingBridgeFees.ts index b2e55bd8..495d018d 100644 --- a/packages/canonical-bridge-widget/src/modules/transfer/hooks/useLoadingBridgeFees.ts +++ b/packages/canonical-bridge-widget/src/modules/transfer/hooks/useLoadingBridgeFees.ts @@ -157,10 +157,10 @@ export const useLoadingBridgeFees = () => { }, deBridgeOpts: { fromChainId: fromChain.id, - fromTokenAddress: selectedToken.deBridge?.address as `0x${string}`, + fromTokenAddress: selectedToken.deBridge?.raw?.address as `0x${string}`, amount, toChainId: toChain?.id, - toTokenAddress: toToken?.deBridge?.address as `0x${string}`, + toTokenAddress: toToken?.deBridge?.raw?.address as `0x${string}`, accesstoken: deBridgeAccessToken, userAddress: fromChain.chainType === 'solana'