From b010de219e1d8aba61d980ac54431981c0c5d4cc Mon Sep 17 00:00:00 2001 From: Jordan Ribbink <17958158+jribbink@users.noreply.github.com> Date: Fri, 21 Feb 2025 09:28:15 -0800 Subject: [PATCH] Add WalletConnect support (#2133) --- package-lock.json | 542 +++++++++++------- packages/fcl-core/src/current-user/index.js | 5 +- packages/fcl-ethereum-provider/package.json | 7 +- .../src/accounts/account-manager.ts | 12 +- .../src/create-provider.ts | 16 +- packages/fcl-ethereum-provider/src/index.ts | 1 + .../fcl-ethereum-provider/src/wc-provider.ts | 221 +++++++ packages/fcl-rainbowkit-adapter/package.json | 4 +- .../src/create-connector.ts | 44 +- .../src/get-wc-connector.ts | 153 +++++ packages/fcl-rainbowkit-adapter/src/index.ts | 6 +- .../src/{ => wallets}/flow-wallet.ts | 4 +- .../src/wallets/wc-wallet.ts | 63 ++ packages/fcl-wagmi-adapter/package.json | 4 + .../fcl-wagmi-adapter/src/fcl-connector.ts | 213 +++++++ packages/fcl-wagmi-adapter/src/index.ts | 217 +------ .../fcl-wagmi-adapter/src/wc-connector.ts | 500 ++++++++++++++++ packages/fcl-wc/package.json | 2 + packages/fcl-wc/src/fcl-wc.ts | 36 +- packages/fcl-wc/src/index.ts | 2 +- packages/fcl-wc/src/service.ts | 129 ++++- packages/fcl-wc/src/session.ts | 83 ++- packages/fcl-wc/src/store.ts | 24 + .../discovery/rpc/handlers/request-wc-qr.ts | 10 +- .../fcl/src/utils/walletconnect/loader.ts | 11 +- 25 files changed, 1801 insertions(+), 508 deletions(-) create mode 100644 packages/fcl-ethereum-provider/src/wc-provider.ts create mode 100644 packages/fcl-rainbowkit-adapter/src/get-wc-connector.ts rename packages/fcl-rainbowkit-adapter/src/{ => wallets}/flow-wallet.ts (93%) create mode 100644 packages/fcl-rainbowkit-adapter/src/wallets/wc-wallet.ts create mode 100644 packages/fcl-wagmi-adapter/src/fcl-connector.ts create mode 100644 packages/fcl-wagmi-adapter/src/wc-connector.ts create mode 100644 packages/fcl-wc/src/store.ts diff --git a/package-lock.json b/package-lock.json index c4ae5c935..7190656c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2365,11 +2365,10 @@ } }, "node_modules/@coinbase/wallet-sdk": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@coinbase/wallet-sdk/-/wallet-sdk-4.2.3.tgz", - "integrity": "sha512-BcyHZ/Ec84z0emORzqdXDv4P0oV+tV3a0OirfA8Ko1JGBIAVvB+hzLvZzCDvnuZx7MTK+Dd8Y9Tjlo446BpCIg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@coinbase/wallet-sdk/-/wallet-sdk-4.3.0.tgz", + "integrity": "sha512-T3+SNmiCw4HzDm4we9wCHCxlP0pqCiwKe4sOwPH3YAK2KSKjxPRydKu6UQJrdONFVLG7ujXvbd/6ZqmvJb8rkw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@noble/hashes": "^1.4.0", "clsx": "^1.2.1", @@ -2381,8 +2380,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", @@ -2397,7 +2395,6 @@ "resolved": "https://registry.npmjs.org/@ecies/ciphers/-/ciphers-0.2.2.tgz", "integrity": "sha512-ylfGR7PyTd+Rm2PqQowG08BCKA22QuX8NzrL+LxAAvazN10DMwdJ2fWwAzRj05FI/M8vNFGm3cv9Wq/GFWCBLg==", "license": "MIT", - "peer": true, "engines": { "bun": ">=1", "deno": ">=2", @@ -2585,7 +2582,6 @@ "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-3.2.0.tgz", "integrity": "sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA==", "license": "MIT", - "peer": true, "dependencies": { "@ethereumjs/util": "^8.1.0", "crc-32": "^1.2.0" @@ -2596,7 +2592,6 @@ "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", "license": "MPL-2.0", - "peer": true, "bin": { "rlp": "bin/rlp" }, @@ -2609,7 +2604,6 @@ "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-4.2.0.tgz", "integrity": "sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw==", "license": "MPL-2.0", - "peer": true, "dependencies": { "@ethereumjs/common": "^3.2.0", "@ethereumjs/rlp": "^4.0.1", @@ -2625,7 +2619,6 @@ "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", "license": "MPL-2.0", - "peer": true, "dependencies": { "@ethereumjs/rlp": "^4.0.1", "ethereum-cryptography": "^2.0.0", @@ -5778,7 +5771,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@metamask/eth-json-rpc-provider/-/eth-json-rpc-provider-1.0.1.tgz", "integrity": "sha512-whiUMPlAOrVGmX8aKYVPvlKyG4CpQXiNNyt74vE1xb5sPvmx5oA7B/kOi/JdBvhGQq97U1/AVdXEdk2zkP8qyA==", - "peer": true, "dependencies": { "@metamask/json-rpc-engine": "^7.0.0", "@metamask/safe-event-emitter": "^3.0.0", @@ -5793,7 +5785,6 @@ "resolved": "https://registry.npmjs.org/@metamask/json-rpc-engine/-/json-rpc-engine-7.3.3.tgz", "integrity": "sha512-dwZPq8wx9yV3IX2caLi9q9xZBw2XeIoYqdyihDDDpuHVCEiqadJLwqM3zy+uwf6F1QYQ65A8aOMQg1Uw7LMLNg==", "license": "ISC", - "peer": true, "dependencies": { "@metamask/rpc-errors": "^6.2.1", "@metamask/safe-event-emitter": "^3.0.0", @@ -5808,7 +5799,6 @@ "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-8.5.0.tgz", "integrity": "sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ==", "license": "ISC", - "peer": true, "dependencies": { "@ethereumjs/tx": "^4.2.0", "@metamask/superstruct": "^3.0.0", @@ -5829,7 +5819,6 @@ "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-5.0.2.tgz", "integrity": "sha512-yfmE79bRQtnMzarnKfX7AEJBwFTxvTyw3nBQlu/5rmGXrjAeAMltoGxO62TFurxrQAFMNa/fEjIHNvungZp0+g==", "license": "ISC", - "peer": true, "dependencies": { "@ethereumjs/tx": "^4.1.2", "@types/debug": "^4.1.7", @@ -5846,7 +5835,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", - "peer": true, "bin": { "semver": "bin/semver.js" }, @@ -5859,7 +5847,6 @@ "resolved": "https://registry.npmjs.org/@metamask/json-rpc-engine/-/json-rpc-engine-8.0.2.tgz", "integrity": "sha512-IoQPmql8q7ABLruW7i4EYVHWUbF74yrp63bRuXV5Zf9BQwcn5H9Ww1eLtROYvI1bUXwOiHZ6qT5CWTrDc/t/AA==", "license": "ISC", - "peer": true, "dependencies": { "@metamask/rpc-errors": "^6.2.1", "@metamask/safe-event-emitter": "^3.0.0", @@ -5874,7 +5861,6 @@ "resolved": "https://registry.npmjs.org/@metamask/json-rpc-middleware-stream/-/json-rpc-middleware-stream-7.0.2.tgz", "integrity": "sha512-yUdzsJK04Ev98Ck4D7lmRNQ8FPioXYhEUZOMS01LXW8qTvPGiRVXmVltj2p4wrLkh0vW7u6nv0mNl5xzC5Qmfg==", "license": "ISC", - "peer": true, "dependencies": { "@metamask/json-rpc-engine": "^8.0.2", "@metamask/safe-event-emitter": "^3.0.0", @@ -5890,7 +5876,6 @@ "resolved": "https://registry.npmjs.org/@metamask/object-multiplex/-/object-multiplex-2.1.0.tgz", "integrity": "sha512-4vKIiv0DQxljcXwfpnbsXcfa5glMj5Zg9mqn4xpIWqkv6uJ2ma5/GtUfLFSxhlxnR8asRMv8dDmWya1Tc1sDFA==", "license": "ISC", - "peer": true, "dependencies": { "once": "^1.4.0", "readable-stream": "^3.6.2" @@ -5904,7 +5889,6 @@ "resolved": "https://registry.npmjs.org/@metamask/onboarding/-/onboarding-1.0.1.tgz", "integrity": "sha512-FqHhAsCI+Vacx2qa5mAFcWNSrTcVGMNjzxVgaX8ECSny/BJ9/vgXP9V7WF/8vb9DltPeQkxr+Fnfmm6GHfmdTQ==", "license": "MIT", - "peer": true, "dependencies": { "bowser": "^2.9.0" } @@ -5914,7 +5898,6 @@ "resolved": "https://registry.npmjs.org/@metamask/providers/-/providers-16.1.0.tgz", "integrity": "sha512-znVCvux30+3SaUwcUGaSf+pUckzT5ukPRpcBmy+muBLC0yaWnBcvDqGfcsw6CBIenUdFrVoAFa8B6jsuCY/a+g==", "license": "MIT", - "peer": true, "dependencies": { "@metamask/json-rpc-engine": "^8.0.1", "@metamask/json-rpc-middleware-stream": "^7.0.1", @@ -5938,7 +5921,6 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" }, @@ -5951,7 +5933,6 @@ "resolved": "https://registry.npmjs.org/@metamask/rpc-errors/-/rpc-errors-6.4.0.tgz", "integrity": "sha512-1ugFO1UoirU2esS3juZanS/Fo8C8XYocCuBpfZI5N7ECtoG+zu0wF+uWZASik6CkO6w9n/Iebt4iI4pT0vptpg==", "license": "MIT", - "peer": true, "dependencies": { "@metamask/utils": "^9.0.0", "fast-safe-stringify": "^2.0.6" @@ -5965,7 +5946,6 @@ "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-9.3.0.tgz", "integrity": "sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==", "license": "ISC", - "peer": true, "dependencies": { "@ethereumjs/tx": "^4.2.0", "@metamask/superstruct": "^3.1.0", @@ -5986,7 +5966,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", - "peer": true, "bin": { "semver": "bin/semver.js" }, @@ -5999,22 +5978,20 @@ "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-3.1.2.tgz", "integrity": "sha512-5yb2gMI1BDm0JybZezeoX/3XhPDOtTbcFvpTXM9kxsoZjPZFh4XciqRbpD6N86HYZqWDhEaKUDuOyR0sQHEjMA==", "license": "ISC", - "peer": true, "engines": { "node": ">=12.0.0" } }, "node_modules/@metamask/sdk": { - "version": "0.31.5", - "resolved": "https://registry.npmjs.org/@metamask/sdk/-/sdk-0.31.5.tgz", - "integrity": "sha512-i7wteqO/fU2JWQrMZz+addHokYThHYznp4nYXviv+QysdxGVgAYvcW/PBA+wpeP3veX7QGfNqMPgSsZbBrASYw==", - "peer": true, + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/@metamask/sdk/-/sdk-0.32.0.tgz", + "integrity": "sha512-WmGAlP1oBuD9hk4CsdlG1WJFuPtYJY+dnTHJMeCyohTWD2GgkcLMUUuvu9lO1/NVzuOoSi1OrnjbuY1O/1NZ1g==", "dependencies": { "@babel/runtime": "^7.26.0", "@metamask/onboarding": "^1.0.1", "@metamask/providers": "16.1.0", - "@metamask/sdk-communication-layer": "0.31.0", - "@metamask/sdk-install-modal-web": "0.31.5", + "@metamask/sdk-communication-layer": "0.32.0", + "@metamask/sdk-install-modal-web": "0.32.0", "@paulmillr/qr": "^0.2.1", "bowser": "^2.9.0", "cross-fetch": "^4.0.0", @@ -6032,19 +6009,17 @@ } }, "node_modules/@metamask/sdk-install-modal-web": { - "version": "0.31.5", - "resolved": "https://registry.npmjs.org/@metamask/sdk-install-modal-web/-/sdk-install-modal-web-0.31.5.tgz", - "integrity": "sha512-ZfrVkPAabfH4AIxcTlxQN5oyyzzVXFTLZrm1/BJ+X632d9MiyAVHNtiqa9EZpZYkZGk2icmDVP+xCpvJmVOVpQ==", - "peer": true, + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/@metamask/sdk-install-modal-web/-/sdk-install-modal-web-0.32.0.tgz", + "integrity": "sha512-TFoktj0JgfWnQaL3yFkApqNwcaqJ+dw4xcnrJueMP3aXkSNev2Ido+WVNOg4IIMxnmOrfAC9t0UJ0u/dC9MjOQ==", "dependencies": { "@paulmillr/qr": "^0.2.1" } }, "node_modules/@metamask/sdk/node_modules/@metamask/sdk-communication-layer": { - "version": "0.31.0", - "resolved": "https://registry.npmjs.org/@metamask/sdk-communication-layer/-/sdk-communication-layer-0.31.0.tgz", - "integrity": "sha512-V9CxdzabDPjQVgmKGHsyU3SYt4Af27g+4DbGCx0fLoHqN/i1RBDZqs/LYbJX3ykJCANzE+llz/MolMCMrzM2RA==", - "peer": true, + "version": "0.32.0", + "resolved": "https://registry.npmjs.org/@metamask/sdk-communication-layer/-/sdk-communication-layer-0.32.0.tgz", + "integrity": "sha512-dmj/KFjMi1fsdZGIOtbhxdg3amxhKL/A5BqSU4uh/SyDKPub/OT+x5pX8bGjpTL1WPWY/Q0OIlvFyX3VWnT06Q==", "dependencies": { "bufferutil": "^4.0.8", "date-fns": "^2.29.3", @@ -6065,7 +6040,6 @@ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", "license": "MIT", - "peer": true, "dependencies": { "node-fetch": "^2.7.0" } @@ -6074,15 +6048,13 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/@metamask/sdk/node_modules/util": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", "license": "MIT", - "peer": true, "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", @@ -6096,7 +6068,6 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "license": "MIT", - "peer": true, "bin": { "uuid": "dist/bin/uuid" } @@ -6106,7 +6077,6 @@ "resolved": "https://registry.npmjs.org/@metamask/superstruct/-/superstruct-3.1.0.tgz", "integrity": "sha512-N08M56HdOgBfRKkrgCMZvQppkZGcArEop3kixNEtVbJKm6P9Cfg0YkI6X0s1g78sNrj2fWUwvJADdZuzJgFttA==", "license": "MIT", - "peer": true, "engines": { "node": ">=16.0.0" } @@ -6116,7 +6086,6 @@ "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-8.5.0.tgz", "integrity": "sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ==", "license": "ISC", - "peer": true, "dependencies": { "@ethereumjs/tx": "^4.2.0", "@metamask/superstruct": "^3.0.0", @@ -6137,7 +6106,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", - "peer": true, "bin": { "semver": "bin/semver.js" }, @@ -6256,7 +6224,6 @@ "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.1.tgz", "integrity": "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==", "license": "MIT", - "peer": true, "engines": { "node": "^14.21.3 || >=16" }, @@ -7401,7 +7368,6 @@ "resolved": "https://registry.npmjs.org/@paulmillr/qr/-/qr-0.2.1.tgz", "integrity": "sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==", "license": "(MIT OR Apache-2.0)", - "peer": true, "funding": { "url": "https://paulmillr.com/funding/" } @@ -9554,7 +9520,6 @@ "resolved": "https://registry.npmjs.org/@safe-global/safe-apps-provider/-/safe-apps-provider-0.18.5.tgz", "integrity": "sha512-9v9wjBi3TwLsEJ3C2ujYoexp3pFJ0omDLH/GX91e2QB+uwCKTBYyhxFSrTQ9qzoyQd+bfsk4gjOGW87QcJhf7g==", "license": "MIT", - "peer": true, "dependencies": { "@safe-global/safe-apps-sdk": "^9.1.0", "events": "^3.3.0" @@ -9565,7 +9530,6 @@ "resolved": "https://registry.npmjs.org/@safe-global/safe-apps-sdk/-/safe-apps-sdk-9.1.0.tgz", "integrity": "sha512-N5p/ulfnnA2Pi2M3YeWjULeWbjo7ei22JwU/IXnhoHzKq3pYCN6ynL9mJBOlvDVv892EgLPCWCOwQk/uBT2v0Q==", "license": "MIT", - "peer": true, "dependencies": { "@safe-global/safe-gateway-typescript-sdk": "^3.5.3", "viem": "^2.1.1" @@ -9576,7 +9540,6 @@ "resolved": "https://registry.npmjs.org/@safe-global/safe-gateway-typescript-sdk/-/safe-gateway-typescript-sdk-3.22.9.tgz", "integrity": "sha512-7ojVK/crhOaGowEO8uYWaopZzcr5rR76emgllGIfjCLR70aY4PbASpi9Pbs+7jIRzPDBBkM0RBo+zYx5UduX8Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=16" } @@ -9744,15 +9707,18 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@stablelib/aead": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/aead/-/aead-1.0.1.tgz", + "integrity": "sha512-q39ik6sxGHewqtO0nP4BuSe3db5G1fEJE8ukvngS2gLkBXyy6E7pLubhbYgnkDFv6V8cWaxcE4Xn0t6LWcJkyg==", "license": "MIT" }, "node_modules/@stablelib/binary": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", + "integrity": "sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==", "license": "MIT", "dependencies": { "@stablelib/int": "^1.0.1" @@ -9760,10 +9726,14 @@ }, "node_modules/@stablelib/bytes": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/bytes/-/bytes-1.0.1.tgz", + "integrity": "sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==", "license": "MIT" }, "node_modules/@stablelib/chacha": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/chacha/-/chacha-1.0.1.tgz", + "integrity": "sha512-Pmlrswzr0pBzDofdFuVe1q7KdsHKhhU24e8gkEwnTGOmlC7PADzLVxGdn2PoNVBBabdg0l/IfLKg6sHAbTQugg==", "license": "MIT", "dependencies": { "@stablelib/binary": "^1.0.1", @@ -9772,6 +9742,8 @@ }, "node_modules/@stablelib/chacha20poly1305": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/chacha20poly1305/-/chacha20poly1305-1.0.1.tgz", + "integrity": "sha512-MmViqnqHd1ymwjOQfghRKw2R/jMIGT3wySN7cthjXCBdO+qErNPUBnRzqNpnvIwg7JBCg3LdeCZZO4de/yEhVA==", "license": "MIT", "dependencies": { "@stablelib/aead": "^1.0.1", @@ -9784,10 +9756,14 @@ }, "node_modules/@stablelib/constant-time": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/constant-time/-/constant-time-1.0.1.tgz", + "integrity": "sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==", "license": "MIT" }, "node_modules/@stablelib/ed25519": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stablelib/ed25519/-/ed25519-1.0.3.tgz", + "integrity": "sha512-puIMWaX9QlRsbhxfDc5i+mNPMY+0TmQEskunY1rZEBPi1acBCVQAhnsk/1Hk50DGPtVsZtAWQg4NHGlVaO9Hqg==", "license": "MIT", "dependencies": { "@stablelib/random": "^1.0.2", @@ -9797,10 +9773,14 @@ }, "node_modules/@stablelib/hash": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hash/-/hash-1.0.1.tgz", + "integrity": "sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==", "license": "MIT" }, "node_modules/@stablelib/hkdf": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hkdf/-/hkdf-1.0.1.tgz", + "integrity": "sha512-SBEHYE16ZXlHuaW5RcGk533YlBj4grMeg5TooN80W3NpcHRtLZLLXvKyX0qcRFxf+BGDobJLnwkvgEwHIDBR6g==", "license": "MIT", "dependencies": { "@stablelib/hash": "^1.0.1", @@ -9810,6 +9790,8 @@ }, "node_modules/@stablelib/hmac": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hmac/-/hmac-1.0.1.tgz", + "integrity": "sha512-V2APD9NSnhVpV/QMYgCVMIYKiYG6LSqw1S65wxVoirhU/51ACio6D4yDVSwMzuTJXWZoVHbDdINioBwKy5kVmA==", "license": "MIT", "dependencies": { "@stablelib/constant-time": "^1.0.1", @@ -9819,10 +9801,14 @@ }, "node_modules/@stablelib/int": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz", + "integrity": "sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==", "license": "MIT" }, "node_modules/@stablelib/keyagreement": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/keyagreement/-/keyagreement-1.0.1.tgz", + "integrity": "sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==", "license": "MIT", "dependencies": { "@stablelib/bytes": "^1.0.1" @@ -9830,6 +9816,8 @@ }, "node_modules/@stablelib/poly1305": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/poly1305/-/poly1305-1.0.1.tgz", + "integrity": "sha512-1HlG3oTSuQDOhSnLwJRKeTRSAdFNVB/1djy2ZbS35rBSJ/PFqx9cf9qatinWghC2UbfOYD8AcrtbUQl8WoxabA==", "license": "MIT", "dependencies": { "@stablelib/constant-time": "^1.0.1", @@ -9838,6 +9826,8 @@ }, "node_modules/@stablelib/random": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.2.tgz", + "integrity": "sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==", "license": "MIT", "dependencies": { "@stablelib/binary": "^1.0.1", @@ -9846,6 +9836,8 @@ }, "node_modules/@stablelib/sha256": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/sha256/-/sha256-1.0.1.tgz", + "integrity": "sha512-GIIH3e6KH+91FqGV42Kcj71Uefd/QEe7Dy42sBTeqppXV95ggCcxLTk39bEr+lZfJmp+ghsR07J++ORkRELsBQ==", "license": "MIT", "dependencies": { "@stablelib/binary": "^1.0.1", @@ -9855,6 +9847,8 @@ }, "node_modules/@stablelib/sha512": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/sha512/-/sha512-1.0.1.tgz", + "integrity": "sha512-13gl/iawHV9zvDKciLo1fQ8Bgn2Pvf7OV6amaRVKiq3pjQ3UmEpXxWiAfV8tYjUpeZroBxtyrwtdooQT/i3hzw==", "license": "MIT", "dependencies": { "@stablelib/binary": "^1.0.1", @@ -9864,10 +9858,14 @@ }, "node_modules/@stablelib/wipe": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz", + "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==", "license": "MIT" }, "node_modules/@stablelib/x25519": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.3.tgz", + "integrity": "sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw==", "license": "MIT", "dependencies": { "@stablelib/keyagreement": "^1.0.1", @@ -10008,7 +10006,6 @@ "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", "license": "MIT", - "peer": true, "dependencies": { "@types/ms": "*" } @@ -10081,8 +10078,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/node": { "version": "18.19.57", @@ -10447,14 +10443,13 @@ } }, "node_modules/@wagmi/connectors": { - "version": "5.7.5", - "resolved": "https://registry.npmjs.org/@wagmi/connectors/-/connectors-5.7.5.tgz", - "integrity": "sha512-btqHHUSTzg4BZe9at/7SnRPv4cz8O3pisbeZBh0qxKz7PVm+9vRxY0bSala3xQPDcS0PRTB30Vn/+lM73GCjbw==", + "version": "5.7.7", + "resolved": "https://registry.npmjs.org/@wagmi/connectors/-/connectors-5.7.7.tgz", + "integrity": "sha512-hveKxuR35ZQQyteLo7aiN/TBVECYKVbLNTYGGgqzTNHJ8vVoblTP9PwPrRPGOPi5ji8raYSFWShxNK7QpGL+Kg==", "license": "MIT", - "peer": true, "dependencies": { - "@coinbase/wallet-sdk": "4.2.3", - "@metamask/sdk": "0.31.5", + "@coinbase/wallet-sdk": "4.3.0", + "@metamask/sdk": "0.32.0", "@safe-global/safe-apps-provider": "0.18.5", "@safe-global/safe-apps-sdk": "9.1.0", "@walletconnect/ethereum-provider": "2.17.0", @@ -10464,7 +10459,7 @@ "url": "https://github.com/sponsors/wevm" }, "peerDependencies": { - "@wagmi/core": "2.16.3", + "@wagmi/core": "2.16.4", "typescript": ">=5.0.4", "viem": "2.x" }, @@ -10475,9 +10470,9 @@ } }, "node_modules/@wagmi/core": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/@wagmi/core/-/core-2.16.3.tgz", - "integrity": "sha512-SVovoWHaQ2AIkmGf+ucNijT6AHXcTMffFcLmcFF6++y21x+ge7Gkh3UoJiU91SDDv8n08eTQ9jbyia3GEgU5jQ==", + "version": "2.16.4", + "resolved": "https://registry.npmjs.org/@wagmi/core/-/core-2.16.4.tgz", + "integrity": "sha512-E4jY4A98gwuHCjzuEajHIG/WhNDY5BChVHMjflV9Bx5CO7COqYRG2dcRLuF6Bo0LQNvVvXDAFUwR2JShJnT5pA==", "license": "MIT", "dependencies": { "eventemitter3": "5.0.1", @@ -10508,22 +10503,24 @@ "license": "MIT" }, "node_modules/@walletconnect/core": { - "version": "2.17.1", + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.18.0.tgz", + "integrity": "sha512-i/olu/IwYtBiWYqyfNUMxq4b6QS5dv+ZVVGmLT2buRwdH6MGETN0Bx3/z6rXJzd1sNd+QL07fxhSFxCekL57tA==", "license": "Apache-2.0", "dependencies": { "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-provider": "1.0.14", "@walletconnect/jsonrpc-types": "1.0.4", "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/jsonrpc-ws-connection": "1.0.14", + "@walletconnect/jsonrpc-ws-connection": "1.0.16", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/logger": "2.1.2", "@walletconnect/relay-api": "1.0.11", - "@walletconnect/relay-auth": "1.0.4", + "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.17.1", - "@walletconnect/utils": "2.17.1", + "@walletconnect/types": "2.18.0", + "@walletconnect/utils": "2.18.0", "@walletconnect/window-getters": "1.0.1", "events": "3.3.0", "lodash.isequal": "4.5.0", @@ -10533,6 +10530,79 @@ "node": ">=18" } }, + "node_modules/@walletconnect/core/node_modules/@noble/curves": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.0.tgz", + "integrity": "sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/core/node_modules/@noble/hashes": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.0.tgz", + "integrity": "sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/core/node_modules/@walletconnect/jsonrpc-ws-connection": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.16.tgz", + "integrity": "sha512-G81JmsMqh5nJheE1mPst1W0WfVv0SG3N7JggwLLGnI7iuDZJq8cRJvQwLGKHn5H1WTW7DEPCo00zz5w62AbL3Q==", + "license": "MIT", + "dependencies": { + "@walletconnect/jsonrpc-utils": "^1.0.6", + "@walletconnect/safe-json": "^1.0.2", + "events": "^3.3.0", + "ws": "^7.5.1" + } + }, + "node_modules/@walletconnect/core/node_modules/@walletconnect/relay-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@walletconnect/relay-auth/-/relay-auth-1.1.0.tgz", + "integrity": "sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ==", + "license": "MIT", + "dependencies": { + "@noble/curves": "1.8.0", + "@noble/hashes": "1.7.0", + "@walletconnect/safe-json": "^1.0.1", + "@walletconnect/time": "^1.0.2", + "uint8arrays": "^3.0.0" + } + }, + "node_modules/@walletconnect/core/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/@walletconnect/environment": { "version": "1.0.1", "license": "MIT", @@ -10545,7 +10615,6 @@ "resolved": "https://registry.npmjs.org/@walletconnect/ethereum-provider/-/ethereum-provider-2.17.0.tgz", "integrity": "sha512-b+KTAXOb6JjoxkwpgYQQKPUcTwENGmdEdZoIDLeRicUmZTn/IQKfkMoC2frClB4YxkyoVMtj1oMV2JAax+yu9A==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@walletconnect/jsonrpc-http-connection": "1.0.8", "@walletconnect/jsonrpc-provider": "1.0.14", @@ -10564,7 +10633,6 @@ "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.17.0.tgz", "integrity": "sha512-On+uSaCfWdsMIQsECwWHZBmUXfrnqmv6B8SXRRuTJgd8tUpEvBkLQH4X7XkSm3zW6ozEkQTCagZ2ox2YPn3kbw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-provider": "1.0.14", @@ -10592,7 +10660,6 @@ "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.17.0.tgz", "integrity": "sha512-sErYwvSSHQolNXni47L3Bm10ptJc1s1YoJvJd34s5E9h9+d3rj7PrhbiW9X82deN+Dm5oA8X9tC4xty1yIBrVg==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@walletconnect/core": "2.17.0", "@walletconnect/events": "1.0.1", @@ -10610,7 +10677,6 @@ "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.17.0.tgz", "integrity": "sha512-i1pn9URpvt9bcjRDkabuAmpA9K7mzyKoLJlbsAujRVX7pfaG7wur7u9Jz0bk1HxvuABL5LHNncTnVKSXKQ5jZA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", @@ -10625,7 +10691,6 @@ "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.17.0.tgz", "integrity": "sha512-1aeQvjwsXy4Yh9G6g2eGmXrEl+BzkNjHRdCrGdMYqFTFa8ROEJfTGsSH3pLsNDlOY94CoBUvJvM55q/PMoN/FQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@stablelib/chacha20poly1305": "1.0.1", "@stablelib/hkdf": "1.0.1", @@ -10650,7 +10715,6 @@ "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", "license": "MIT", - "peer": true, "dependencies": { "decode-uri-component": "^0.2.2", "filter-obj": "^1.1.0", @@ -10669,7 +10733,6 @@ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=4" } @@ -10733,6 +10796,8 @@ }, "node_modules/@walletconnect/jsonrpc-ws-connection": { "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.14.tgz", + "integrity": "sha512-Jsl6fC55AYcbkNVkwNM6Jo+ufsuCQRqViOQ8ZBPH9pRREHH9welbBiszuTLqEJiQcO/6XfFDl6bzCJIkrEi8XA==", "license": "MIT", "dependencies": { "@walletconnect/jsonrpc-utils": "^1.0.6", @@ -10743,6 +10808,8 @@ }, "node_modules/@walletconnect/jsonrpc-ws-connection/node_modules/ws": { "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "license": "MIT", "engines": { "node": ">=8.3.0" @@ -10787,6 +10854,8 @@ }, "node_modules/@walletconnect/modal": { "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@walletconnect/modal/-/modal-2.7.0.tgz", + "integrity": "sha512-RQVt58oJ+rwqnPcIvRFeMGKuXb9qkgSmwz4noF8JZGUym3gUAzVs+uW2NQ1Owm9XOJAV+sANrtJ+VoVq1ftElw==", "license": "Apache-2.0", "dependencies": { "@walletconnect/modal-core": "2.7.0", @@ -10819,6 +10888,8 @@ }, "node_modules/@walletconnect/relay-auth": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@walletconnect/relay-auth/-/relay-auth-1.0.4.tgz", + "integrity": "sha512-kKJcS6+WxYq5kshpPaxGHdwf5y98ZwbfuS4EE/NkQzqrDFm5Cj+dP8LofzWvjrrLkZq7Afy7WrQMXdLy8Sx7HQ==", "license": "MIT", "dependencies": { "@stablelib/ed25519": "^1.0.2", @@ -10837,17 +10908,19 @@ } }, "node_modules/@walletconnect/sign-client": { - "version": "2.17.1", + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.18.0.tgz", + "integrity": "sha512-oUjlRIsbHxMSRif2WvMRdvm6tMsQjMj07rl7YVcKVvZ1gF1/9GcbJPjzL/U87fv8qAQkVhIlbEg2vHaVYf6J/g==", "license": "Apache-2.0", "dependencies": { - "@walletconnect/core": "2.17.1", + "@walletconnect/core": "2.18.0", "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/logger": "2.1.2", "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.17.1", - "@walletconnect/utils": "2.17.1", + "@walletconnect/types": "2.18.0", + "@walletconnect/utils": "2.18.0", "events": "3.3.0" } }, @@ -10859,7 +10932,9 @@ } }, "node_modules/@walletconnect/types": { - "version": "2.17.1", + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.18.0.tgz", + "integrity": "sha512-g0jU+6LUuw3E/EPAQfHNK2xK/95IpRfz68tdNAFckLmefZU6kzoE1mIM1SrPJq8rT9kUPp6/APMQE+ReH2OdBA==", "license": "Apache-2.0", "dependencies": { "@walletconnect/events": "1.0.1", @@ -10875,7 +10950,6 @@ "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.17.0.tgz", "integrity": "sha512-d3V5Be7AqLrvzcdMZSBS8DmGDRdqnyLk1DWmRKAGgR6ieUWykhhUKlvfeoZtvJrIXrY7rUGYpH1X41UtFkW5Pw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@walletconnect/jsonrpc-http-connection": "1.0.8", "@walletconnect/jsonrpc-provider": "1.0.14", @@ -10893,7 +10967,6 @@ "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.17.0.tgz", "integrity": "sha512-On+uSaCfWdsMIQsECwWHZBmUXfrnqmv6B8SXRRuTJgd8tUpEvBkLQH4X7XkSm3zW6ozEkQTCagZ2ox2YPn3kbw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@walletconnect/heartbeat": "1.2.2", "@walletconnect/jsonrpc-provider": "1.0.14", @@ -10921,7 +10994,6 @@ "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.17.0.tgz", "integrity": "sha512-sErYwvSSHQolNXni47L3Bm10ptJc1s1YoJvJd34s5E9h9+d3rj7PrhbiW9X82deN+Dm5oA8X9tC4xty1yIBrVg==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@walletconnect/core": "2.17.0", "@walletconnect/events": "1.0.1", @@ -10939,7 +11011,6 @@ "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.17.0.tgz", "integrity": "sha512-i1pn9URpvt9bcjRDkabuAmpA9K7mzyKoLJlbsAujRVX7pfaG7wur7u9Jz0bk1HxvuABL5LHNncTnVKSXKQ5jZA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@walletconnect/events": "1.0.1", "@walletconnect/heartbeat": "1.2.2", @@ -10954,7 +11025,6 @@ "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.17.0.tgz", "integrity": "sha512-1aeQvjwsXy4Yh9G6g2eGmXrEl+BzkNjHRdCrGdMYqFTFa8ROEJfTGsSH3pLsNDlOY94CoBUvJvM55q/PMoN/FQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@stablelib/chacha20poly1305": "1.0.1", "@stablelib/hkdf": "1.0.1", @@ -10979,7 +11049,6 @@ "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", "license": "MIT", - "peer": true, "dependencies": { "decode-uri-component": "^0.2.2", "filter-obj": "^1.1.0", @@ -10998,37 +11067,75 @@ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=4" } }, "node_modules/@walletconnect/utils": { - "version": "2.17.1", + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.18.0.tgz", + "integrity": "sha512-6AUXIcjSxTHGRsTtmUP/oqudtwRILrQqrJsH3jS5T28FFDzZt7+On6fR4mXzi64k4nNYeWg1wMCGLEdtxmGbZQ==", "license": "Apache-2.0", "dependencies": { - "@ethersproject/hash": "5.7.0", "@ethersproject/transactions": "5.7.0", - "@stablelib/chacha20poly1305": "1.0.1", - "@stablelib/hkdf": "1.0.1", - "@stablelib/random": "1.0.2", - "@stablelib/sha256": "1.0.1", - "@stablelib/x25519": "1.0.3", + "@noble/ciphers": "1.2.1", + "@noble/curves": "1.8.1", + "@noble/hashes": "1.7.1", "@walletconnect/jsonrpc-utils": "1.0.8", "@walletconnect/keyvaluestorage": "1.1.1", "@walletconnect/relay-api": "1.0.11", - "@walletconnect/relay-auth": "1.0.4", + "@walletconnect/relay-auth": "1.1.0", "@walletconnect/safe-json": "1.0.2", "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.17.1", + "@walletconnect/types": "2.18.0", "@walletconnect/window-getters": "1.0.1", "@walletconnect/window-metadata": "1.0.1", "detect-browser": "5.3.0", - "elliptic": "6.5.7", + "elliptic": "6.6.1", "query-string": "7.1.3", "uint8arrays": "3.1.0" } }, + "node_modules/@walletconnect/utils/node_modules/@walletconnect/relay-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@walletconnect/relay-auth/-/relay-auth-1.1.0.tgz", + "integrity": "sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ==", + "license": "MIT", + "dependencies": { + "@noble/curves": "1.8.0", + "@noble/hashes": "1.7.0", + "@walletconnect/safe-json": "^1.0.1", + "@walletconnect/time": "^1.0.2", + "uint8arrays": "^3.0.0" + } + }, + "node_modules/@walletconnect/utils/node_modules/@walletconnect/relay-auth/node_modules/@noble/curves": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.0.tgz", + "integrity": "sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/utils/node_modules/@walletconnect/relay-auth/node_modules/@noble/hashes": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.0.tgz", + "integrity": "sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@walletconnect/utils/node_modules/query-string": { "version": "7.1.3", "license": "MIT", @@ -11690,7 +11797,6 @@ "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.2.6.tgz", "integrity": "sha512-Hs4R+4SPgamu6rSGW8C7cV9gaWUKEHykfzCCvIRuaVv636Ju10ZdeUbvb4TBEW0INuq2DHZqXbK4Nd3yG4RaRw==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.0.0" } @@ -11699,8 +11805,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/asynckit": { "version": "0.4.0", @@ -11761,7 +11866,6 @@ "node_modules/available-typed-arrays": { "version": "1.0.7", "license": "MIT", - "peer": true, "dependencies": { "possible-typed-array-names": "^1.0.0" }, @@ -12391,8 +12495,7 @@ "version": "2.11.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/bplist-creator": { "version": "0.0.7", @@ -12537,7 +12640,6 @@ "integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==", "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "node-gyp-build": "^4.3.0" }, @@ -12636,7 +12738,6 @@ "node_modules/call-bind": { "version": "1.0.7", "license": "MIT", - "peer": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -12656,7 +12757,6 @@ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" @@ -12670,7 +12770,6 @@ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", "license": "MIT", - "peer": true, "dependencies": { "call-bind-apply-helpers": "^1.0.1", "get-intrinsic": "^1.2.6" @@ -12786,7 +12885,6 @@ "resolved": "https://registry.npmjs.org/@coinbase/wallet-sdk/-/wallet-sdk-3.9.3.tgz", "integrity": "sha512-N/A2DRIf0Y3PHc1XAMvbBUu4zisna6qAdqABMZwBMNEfWrXpAwx16pZGkYCLGE+Rvv1edbcB2LYDRnACNcmCiw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "bn.js": "^5.2.1", "buffer": "^6.0.3", @@ -12803,15 +12901,13 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/cbw-sdk/node_modules/eventemitter3": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/chalk": { "version": "2.4.2", @@ -13161,7 +13257,6 @@ "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -13649,7 +13744,6 @@ "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", "license": "Apache-2.0", - "peer": true, "bin": { "crc32": "bin/crc32.njs" }, @@ -14056,7 +14150,6 @@ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.21.0" }, @@ -14209,7 +14302,6 @@ "node_modules/define-data-property": { "version": "1.1.4", "license": "MIT", - "peer": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -14529,7 +14621,6 @@ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "license": "MIT", - "peer": true, "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", @@ -14563,7 +14654,6 @@ "resolved": "https://registry.npmjs.org/eciesjs/-/eciesjs-0.4.13.tgz", "integrity": "sha512-zBdtR4K+wbj10bWPpIOF9DW+eFYQu8miU5ypunh0t4Bvt83ZPlEWgT5Dq/0G6uwEXumZKjfb5BZxYUZQ2Hzn/Q==", "license": "MIT", - "peer": true, "dependencies": { "@ecies/ciphers": "^0.2.2", "@noble/ciphers": "^1.0.0", @@ -14600,7 +14690,9 @@ "license": "ISC" }, "node_modules/elliptic": { - "version": "6.5.7", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", "license": "MIT", "dependencies": { "bn.js": "^4.11.9", @@ -14670,7 +14762,6 @@ "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz", "integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==", "license": "MIT", - "peer": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1", @@ -14684,7 +14775,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=10.0.0" }, @@ -14706,7 +14796,6 @@ "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", "license": "MIT", - "peer": true, "engines": { "node": ">=10.0.0" } @@ -14873,7 +14962,6 @@ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" } @@ -14881,7 +14969,6 @@ "node_modules/es-errors": { "version": "1.3.0", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" } @@ -14894,7 +14981,6 @@ "node_modules/es-object-atoms": { "version": "1.0.0", "license": "MIT", - "peer": true, "dependencies": { "es-errors": "^1.3.0" }, @@ -15368,7 +15454,6 @@ "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-7.1.0.tgz", "integrity": "sha512-8YdplnuE1IK4xfqpf4iU7oBxnOYAc35934o083G8ao+8WM8QQtt/mVlAY6yIAdY1eMeLqg4Z//PZjJGmWGPMRg==", "license": "MIT", - "peer": true, "dependencies": { "@metamask/eth-json-rpc-provider": "^1.0.0", "@metamask/safe-event-emitter": "^3.0.0", @@ -15385,7 +15470,6 @@ "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-5.0.2.tgz", "integrity": "sha512-yfmE79bRQtnMzarnKfX7AEJBwFTxvTyw3nBQlu/5rmGXrjAeAMltoGxO62TFurxrQAFMNa/fEjIHNvungZp0+g==", "license": "ISC", - "peer": true, "dependencies": { "@ethereumjs/tx": "^4.1.2", "@types/debug": "^4.1.7", @@ -15402,7 +15486,6 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", "license": "MIT", - "peer": true, "engines": { "node": ">=4" } @@ -15412,7 +15495,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", - "peer": true, "bin": { "semver": "bin/semver.js" }, @@ -15425,7 +15507,6 @@ "resolved": "https://registry.npmjs.org/eth-json-rpc-filters/-/eth-json-rpc-filters-6.0.1.tgz", "integrity": "sha512-ITJTvqoCw6OVMLs7pI8f4gG92n/St6x80ACtHodeS+IXmO0w+t1T5OOzfSt7KLSMLRkVUoexV7tztLgDxg+iig==", "license": "ISC", - "peer": true, "dependencies": { "@metamask/safe-event-emitter": "^3.0.0", "async-mutex": "^0.2.6", @@ -15442,7 +15523,6 @@ "resolved": "https://registry.npmjs.org/eth-query/-/eth-query-2.1.2.tgz", "integrity": "sha512-srES0ZcvwkR/wd5OQBRA1bIJMww1skfGS0s8wlwK3/oNP4+wnds60krvu5R1QbpRQjMmpG5OMIWro5s7gvDPsA==", "license": "ISC", - "peer": true, "dependencies": { "json-rpc-random-id": "^1.0.0", "xtend": "^4.0.1" @@ -15453,7 +15533,6 @@ "resolved": "https://registry.npmjs.org/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz", "integrity": "sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg==", "license": "MIT", - "peer": true, "dependencies": { "fast-safe-stringify": "^2.0.6" } @@ -15463,7 +15542,6 @@ "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", "license": "MIT", - "peer": true, "dependencies": { "@noble/curves": "1.4.2", "@noble/hashes": "1.4.0", @@ -15476,7 +15554,6 @@ "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", "license": "MIT", - "peer": true, "dependencies": { "@noble/hashes": "1.4.0" }, @@ -15489,7 +15566,6 @@ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 16" }, @@ -15502,7 +15578,6 @@ "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", "license": "MIT", - "peer": true, "funding": { "url": "https://paulmillr.com/funding/" } @@ -15512,7 +15587,6 @@ "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", "license": "MIT", - "peer": true, "dependencies": { "@noble/curves": "~1.4.0", "@noble/hashes": "~1.4.0", @@ -15527,7 +15601,6 @@ "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", "license": "MIT", - "peer": true, "dependencies": { "@noble/hashes": "~1.4.0", "@scure/base": "~1.1.6" @@ -15547,8 +15620,7 @@ "version": "6.4.9", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/eventemitter3": { "version": "4.0.7", @@ -16258,7 +16330,6 @@ "resolved": "https://registry.npmjs.org/extension-port-stream/-/extension-port-stream-3.0.0.tgz", "integrity": "sha512-an2S5quJMiy5bnZKEf6AkfH/7r8CzHvhchU40gxN+OM6HPhe7Z9T1FUychcf2M9PpPOO0Hf7BAEfJkw2TDIBDw==", "license": "ISC", - "peer": true, "dependencies": { "readable-stream": "^3.6.2 || ^4.4.2", "webextension-polyfill": ">=0.10.0 <1.0" @@ -16329,8 +16400,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/fast-xml-parser": { "version": "4.5.0", @@ -16689,7 +16759,6 @@ "node_modules/for-each": { "version": "0.3.3", "license": "MIT", - "peer": true, "dependencies": { "is-callable": "^1.1.3" } @@ -16870,7 +16939,6 @@ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", "license": "MIT", - "peer": true, "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-define-property": "^1.0.1", @@ -17004,7 +17072,6 @@ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "license": "MIT", - "peer": true, "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" @@ -17246,7 +17313,6 @@ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -17359,7 +17425,6 @@ "node_modules/has-property-descriptors": { "version": "1.0.2", "license": "MIT", - "peer": true, "dependencies": { "es-define-property": "^1.0.0" }, @@ -17383,7 +17448,6 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -17394,7 +17458,6 @@ "node_modules/has-tostringtag": { "version": "1.0.2", "license": "MIT", - "peer": true, "dependencies": { "has-symbols": "^1.0.3" }, @@ -18030,7 +18093,6 @@ "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" @@ -18119,7 +18181,6 @@ "node_modules/is-callable": { "version": "1.2.7", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -18228,7 +18289,6 @@ "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.3", "get-proto": "^1.0.0", @@ -18417,7 +18477,6 @@ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", @@ -18515,7 +18574,6 @@ "node_modules/is-typed-array": { "version": "1.1.13", "license": "MIT", - "peer": true, "dependencies": { "which-typed-array": "^1.1.14" }, @@ -20799,7 +20857,6 @@ "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz", "integrity": "sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ==", "license": "ISC", - "peer": true, "dependencies": { "@metamask/safe-event-emitter": "^2.0.0", "eth-rpc-errors": "^4.0.2" @@ -20812,15 +20869,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz", "integrity": "sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/json-rpc-random-id": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz", "integrity": "sha512-RJ9YYNCkhVDBuP4zN5BBtYAzEl03yq/jIIsyif0JY9qyJuQQZNeDK7anAPKKlyEtLSj2s8h6hNh2F8zO5q7ScA==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/json-schema-deref-sync": { "version": "0.13.0", @@ -20934,7 +20989,6 @@ "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "node-addon-api": "^2.0.0", "node-gyp-build": "^4.2.0", @@ -20948,8 +21002,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/keyv": { "version": "4.5.4", @@ -22020,7 +22073,6 @@ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" } @@ -23071,8 +23123,7 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", "integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/micromatch": { "version": "4.0.8", @@ -23635,7 +23686,6 @@ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", "license": "MIT", - "peer": true, "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", @@ -24331,7 +24381,6 @@ "resolved": "https://registry.npmjs.org/obj-multiplex/-/obj-multiplex-1.0.0.tgz", "integrity": "sha512-0GNJAOsHoBHeNTvl5Vt6IWnpUEcc3uSRxzBri7EDyIcMgYvnY2JL2qdeV5zTMjWQX5OHcD5amcW2HFfDh0gjIA==", "license": "ISC", - "peer": true, "dependencies": { "end-of-stream": "^1.4.0", "once": "^1.4.0", @@ -24342,15 +24391,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/obj-multiplex/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -24366,7 +24413,6 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "license": "MIT", - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -25152,7 +25198,6 @@ "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.11.tgz", "integrity": "sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==", "license": "0BSD", - "peer": true, "engines": { "node": ">=12.0.0" } @@ -25160,7 +25205,6 @@ "node_modules/possible-typed-array-names": { "version": "1.0.0", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" } @@ -26229,7 +26273,6 @@ "node_modules/pump": { "version": "3.0.2", "license": "MIT", - "peer": true, "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -27770,7 +27813,6 @@ "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "license": "MIT", - "peer": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -28039,7 +28081,6 @@ "node_modules/set-function-length": { "version": "1.2.2", "license": "MIT", - "peer": true, "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -28081,7 +28122,6 @@ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "license": "(MIT AND BSD-3-Clause)", - "peer": true, "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -28248,7 +28288,6 @@ "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz", "integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==", "license": "MIT", - "peer": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.2", @@ -28264,7 +28303,6 @@ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", "license": "MIT", - "peer": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -28849,7 +28887,6 @@ "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.4.tgz", "integrity": "sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=14.0.0" } @@ -30217,7 +30254,6 @@ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", "license": "MIT", - "peer": true, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } @@ -30228,7 +30264,6 @@ "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "node-gyp-build": "^4.3.0" }, @@ -30400,14 +30435,13 @@ } }, "node_modules/wagmi": { - "version": "2.14.9", - "resolved": "https://registry.npmjs.org/wagmi/-/wagmi-2.14.9.tgz", - "integrity": "sha512-nDJ5hwPaiVpn/8Bi82m5K4BCqDiOSnOV976p/jKXt0svQABGdAxUxej0UgDRoVlrp+NutmejN+SyQKmhV477/A==", + "version": "2.14.11", + "resolved": "https://registry.npmjs.org/wagmi/-/wagmi-2.14.11.tgz", + "integrity": "sha512-Qj79cq+9MAcnKict9QLo60Lc4S2IXVVE94HBwCmczDrFtoM31NxfX4uQP73Elj2fV9lXH4/dw3jlb8eDhlm6iQ==", "license": "MIT", - "peer": true, "dependencies": { - "@wagmi/connectors": "5.7.5", - "@wagmi/core": "2.16.3", + "@wagmi/connectors": "5.7.7", + "@wagmi/core": "2.16.4", "use-sync-external-store": "1.4.0" }, "funding": { @@ -30460,8 +30494,7 @@ "version": "0.10.0", "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==", - "license": "MPL-2.0", - "peer": true + "license": "MPL-2.0" }, "node_modules/webidl-conversions": { "version": "7.0.0", @@ -30740,7 +30773,6 @@ "node_modules/which-typed-array": { "version": "1.1.15", "license": "MIT", - "peer": true, "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", @@ -31041,7 +31073,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", - "peer": true, "engines": { "node": ">=0.4.0" } @@ -31331,9 +31362,14 @@ "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", "@noble/hashes": "^1.7.1", + "@onflow/fcl-wc": "^5.5.4", "@onflow/rlp": "^1.2.3", + "@walletconnect/ethereum-provider": "^2.18.0", "@walletconnect/jsonrpc-http-connection": "^1.0.8", - "@walletconnect/jsonrpc-provider": "^1.0.14" + "@walletconnect/jsonrpc-provider": "^1.0.14", + "@walletconnect/types": "^2.18.0", + "@walletconnect/universal-provider": "^2.18.0", + "@walletconnect/utils": "^2.18.0" }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", @@ -31350,6 +31386,45 @@ "@onflow/fcl": "^1.13.4" } }, + "packages/fcl-ethereum-provider/node_modules/@walletconnect/ethereum-provider": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/@walletconnect/ethereum-provider/-/ethereum-provider-2.18.0.tgz", + "integrity": "sha512-YExNYP/z1qNmkLwMutqVxl/rrGX7RS5PCEOVLYCiGsV+vDB9Z6iHP2FgRWh8kZvnmBv5IVvPnQdE7rTzWeUl1Q==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/jsonrpc-http-connection": "1.0.8", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/modal": "2.7.0", + "@walletconnect/sign-client": "2.18.0", + "@walletconnect/types": "2.18.0", + "@walletconnect/universal-provider": "2.18.0", + "@walletconnect/utils": "2.18.0", + "events": "3.3.0" + } + }, + "packages/fcl-ethereum-provider/node_modules/@walletconnect/universal-provider": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.18.0.tgz", + "integrity": "sha512-zF/e1NAipLqYjNNgM+XZTchh94efaxciBmgcDOaLznS97R7S/1bYj5okQCAEDKx9RALhEKqZKoyo9jwn4p3BVA==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/jsonrpc-http-connection": "1.0.8", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/sign-client": "2.18.0", + "@walletconnect/types": "2.18.0", + "@walletconnect/utils": "2.18.0", + "events": "3.3.0", + "lodash": "4.17.21" + } + }, "packages/fcl-rainbowkit-adapter": { "name": "@onflow/fcl-rainbowkit-adapter", "version": "0.0.0", @@ -31364,7 +31439,9 @@ "@wagmi/core": "^2.16.3", "@walletconnect/jsonrpc-http-connection": "^1.0.8", "@walletconnect/jsonrpc-provider": "^1.0.14", - "viem": "^2.22.21" + "mipd": "^0.0.7", + "viem": "^2.22.21", + "wagmi": "^2.14.11" }, "devDependencies": { "@babel/preset-typescript": "^7.25.7", @@ -31655,6 +31732,10 @@ "@onflow/rlp": "^1.2.3", "@walletconnect/jsonrpc-http-connection": "^1.0.8", "@walletconnect/jsonrpc-provider": "^1.0.14", + "@walletconnect/modal": "^2.7.0", + "@walletconnect/types": "^2.18.0", + "@walletconnect/universal-provider": "^2.18.0", + "@walletconnect/utils": "^2.18.0", "viem": "^2.22.21" }, "devDependencies": { @@ -31673,6 +31754,26 @@ "@wagmi/core": "^2.16.3" } }, + "packages/fcl-wagmi-adapter/node_modules/@walletconnect/universal-provider": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.18.0.tgz", + "integrity": "sha512-zF/e1NAipLqYjNNgM+XZTchh94efaxciBmgcDOaLznS97R7S/1bYj5okQCAEDKx9RALhEKqZKoyo9jwn4p3BVA==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/jsonrpc-http-connection": "1.0.8", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/sign-client": "2.18.0", + "@walletconnect/types": "2.18.0", + "@walletconnect/utils": "2.18.0", + "events": "3.3.0", + "lodash": "4.17.21" + } + }, "packages/fcl-wc": { "name": "@onflow/fcl-wc", "version": "5.5.4", @@ -31682,10 +31783,12 @@ "@onflow/config": "1.5.1", "@onflow/util-invariant": "1.2.4", "@onflow/util-logger": "1.3.3", + "@walletconnect/ethereum-provider": "^2.18.0", "@walletconnect/modal": "^2.7.0", "@walletconnect/modal-core": "^2.6.2", "@walletconnect/sign-client": "^2.17.1", "@walletconnect/types": "^2.8.1", + "@walletconnect/universal-provider": "^2.18.0", "@walletconnect/utils": "^2.8.1", "postcss-cli": "^11.0.0", "preact": "^10.24.3", @@ -31706,6 +31809,45 @@ "@onflow/fcl-core": "1.13.4" } }, + "packages/fcl-wc/node_modules/@walletconnect/ethereum-provider": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/@walletconnect/ethereum-provider/-/ethereum-provider-2.18.0.tgz", + "integrity": "sha512-YExNYP/z1qNmkLwMutqVxl/rrGX7RS5PCEOVLYCiGsV+vDB9Z6iHP2FgRWh8kZvnmBv5IVvPnQdE7rTzWeUl1Q==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/jsonrpc-http-connection": "1.0.8", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/modal": "2.7.0", + "@walletconnect/sign-client": "2.18.0", + "@walletconnect/types": "2.18.0", + "@walletconnect/universal-provider": "2.18.0", + "@walletconnect/utils": "2.18.0", + "events": "3.3.0" + } + }, + "packages/fcl-wc/node_modules/@walletconnect/universal-provider": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.18.0.tgz", + "integrity": "sha512-zF/e1NAipLqYjNNgM+XZTchh94efaxciBmgcDOaLznS97R7S/1bYj5okQCAEDKx9RALhEKqZKoyo9jwn4p3BVA==", + "license": "Apache-2.0", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/jsonrpc-http-connection": "1.0.8", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "2.1.2", + "@walletconnect/sign-client": "2.18.0", + "@walletconnect/types": "2.18.0", + "@walletconnect/utils": "2.18.0", + "events": "3.3.0", + "lodash": "4.17.21" + } + }, "packages/fcl/node_modules/cross-fetch": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", diff --git a/packages/fcl-core/src/current-user/index.js b/packages/fcl-core/src/current-user/index.js index 58248ccbc..32d59d048 100644 --- a/packages/fcl-core/src/current-user/index.js +++ b/packages/fcl-core/src/current-user/index.js @@ -165,9 +165,10 @@ const getAuthenticate = * @param {object} [opts] - Options * @param {object} [opts.service] - Optional service to use for authentication * @param {boolean} [opts.redir] - Optional redirect flag + * @param {boolean} [opts.forceReauth] - Optional force re-authentication flag * @returns */ - async ({service, redir = false} = {}) => { + async ({service, redir = false, forceReauth = false} = {}) => { if ( service && !service?.provider?.is_installed && @@ -185,7 +186,7 @@ const getAuthenticate = const refreshService = serviceOfType(user.services, "authn-refresh") let accountProofData - if (user.loggedIn) { + if (user.loggedIn && !forceReauth) { if (refreshService) { try { const response = await execService({ diff --git a/packages/fcl-ethereum-provider/package.json b/packages/fcl-ethereum-provider/package.json index 3cd7ea871..d690cd37f 100644 --- a/packages/fcl-ethereum-provider/package.json +++ b/packages/fcl-ethereum-provider/package.json @@ -40,9 +40,14 @@ "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", "@noble/hashes": "^1.7.1", + "@onflow/fcl-wc": "^5.5.4", "@onflow/rlp": "^1.2.3", + "@walletconnect/ethereum-provider": "^2.18.0", "@walletconnect/jsonrpc-http-connection": "^1.0.8", - "@walletconnect/jsonrpc-provider": "^1.0.14" + "@walletconnect/jsonrpc-provider": "^1.0.14", + "@walletconnect/types": "^2.18.0", + "@walletconnect/universal-provider": "^2.18.0", + "@walletconnect/utils": "^2.18.0" }, "peerDependencies": { "@onflow/fcl": "^1.13.4" diff --git a/packages/fcl-ethereum-provider/src/accounts/account-manager.ts b/packages/fcl-ethereum-provider/src/accounts/account-manager.ts index ee9895ea9..6a2cc1051 100644 --- a/packages/fcl-ethereum-provider/src/accounts/account-manager.ts +++ b/packages/fcl-ethereum-provider/src/accounts/account-manager.ts @@ -70,18 +70,18 @@ export class AccountManager { $user .pipe( - // Only listen bind to users matching the current authz service + // Only listen bind to users matching the current authn service map(snapshot => { const addr = snapshot?.addr || null if (!addr) { return null } - const authzService = snapshot?.services?.find( - service => service.type === "authz" + const authnService = snapshot?.services?.find( + service => service.type === "authn" ) - const matchingAuthzService = authzService?.uid === this.service?.uid - return matchingAuthzService ? addr : null + const matchingAuthnService = authnService?.uid === this.service?.uid + return matchingAuthnService ? addr : null }), distinctUntilChanged(), switchMap(addr => @@ -110,7 +110,7 @@ export class AccountManager { } public async authenticate(): Promise { - await this.user.authenticate({service: this.service}) + await this.user.authenticate({service: this.service, forceReauth: true}) return this.getAccounts() } diff --git a/packages/fcl-ethereum-provider/src/create-provider.ts b/packages/fcl-ethereum-provider/src/create-provider.ts index 1b1fd3ea4..d8eab92f8 100644 --- a/packages/fcl-ethereum-provider/src/create-provider.ts +++ b/packages/fcl-ethereum-provider/src/create-provider.ts @@ -8,7 +8,14 @@ import {AccountManager} from "./accounts/account-manager" import {FLOW_CHAINS} from "./constants" import {Gateway} from "./gateway/gateway" import {NetworkManager} from "./network/network-manager" -import {Subject} from "./util/observable" + +export type FclProviderConfig = { + user: typeof fcl.currentUser + config: typeof fcl.config + service?: Service + gateway?: string + rpcUrls?: {[chainId: string]: number} +} /** * Create a new FCL Ethereum provider @@ -29,12 +36,7 @@ import {Subject} from "./util/observable" * }) * ``` */ -export function createProvider(config: { - user: typeof fcl.currentUser - config: typeof fcl.config - service?: Service - rpcUrls?: {[chainId: string]: number} -}): Eip1193Provider { +export function createProvider(config: FclProviderConfig): Eip1193Provider { const defaultRpcUrls = Object.values(FLOW_CHAINS).reduce( (acc, chain) => { acc[chain.eip155ChainId] = chain.publicRpcUrl diff --git a/packages/fcl-ethereum-provider/src/index.ts b/packages/fcl-ethereum-provider/src/index.ts index 746b52b0a..30fb17946 100644 --- a/packages/fcl-ethereum-provider/src/index.ts +++ b/packages/fcl-ethereum-provider/src/index.ts @@ -1 +1,2 @@ export {createProvider} from "./create-provider" +export {WalletConnectEthereumProvider} from "./wc-provider" diff --git a/packages/fcl-ethereum-provider/src/wc-provider.ts b/packages/fcl-ethereum-provider/src/wc-provider.ts new file mode 100644 index 000000000..9bbbad14f --- /dev/null +++ b/packages/fcl-ethereum-provider/src/wc-provider.ts @@ -0,0 +1,221 @@ +import { + EthereumProvider, + EthereumProviderOptions, + OPTIONAL_EVENTS, + OPTIONAL_METHODS, + REQUIRED_EVENTS, + REQUIRED_METHODS, +} from "@walletconnect/ethereum-provider" +import { + NamespaceConfig, + UniversalProvider, +} from "@walletconnect/universal-provider" +import {SessionTypes} from "@walletconnect/types" +import {FLOW_CHAINS, FlowNetwork} from "./constants" +import {formatChainId} from "./util/eth" +import {getAccountsFromNamespaces} from "@walletconnect/utils" +import {FLOW_METHODS} from "@onflow/fcl-wc" +import * as fcl from "@onflow/fcl" +import {Service} from "@onflow/typedefs" + +const BASE_WC_SERVICE = ( + externalProvider: InstanceType +) => + ({ + f_type: "Service", + f_vsn: "1.0.0", + type: "authn", + method: "WC/RPC", + uid: "cross-vm-walletconnect#authn", + endpoint: "flow_authn", + optIn: true, + provider: { + address: null, + name: "WalletConnect", + icon: "https://avatars.githubusercontent.com/u/37784886", + description: "WalletConnect Base Service", + website: "https://walletconnect.com", + color: null, + supportEmail: null, + }, + params: { + externalProvider, + }, + }) as unknown as Service + +export class WalletConnectEthereumProvider extends EthereumProvider { + static async init( + opts: EthereumProviderOptions + ): Promise { + const provider = new WalletConnectEthereumProvider() + await provider.initialize(opts) + + // Refresh the FCL user to align with the WalletConnect session + async function refreshFclUser() { + const fclUser = fcl.currentUser() + const wcService = BASE_WC_SERVICE(provider.signer) + const snapshot = await fclUser.snapshot() + + // Find the authentication service from the current FCL user snapshot + const authnService = snapshot?.services.find( + service => service.type === "authn" + ) + + // If there’s no auth service or the auth service + if (authnService && authnService.uid !== wcService.uid) { + // Another FCL user is already authenticated, we need to unauthenticate it + if (provider.signer.session) { + await fclUser.authenticate({service: wcService, forceReauth: true}) + } + } else { + // Determine the external provider's topic from the auth service params + const externalProvider = authnService?.params?.externalProvider as + | string + | InstanceType + | undefined + const externalProviderTopic = + typeof externalProvider === "string" + ? externalProvider + : (externalProvider?.session?.topic ?? null) + + // If the provider is already connected with a matching session, re-authenticate the user + if ( + provider.signer.session && + (externalProviderTopic == null || + externalProviderTopic === provider.signer.session.topic) + ) { + await fclUser.authenticate({service: wcService, forceReauth: true}) + } else if (!provider.signer.session) { + // If no session is set but FCL is still authenticated, unauthenticate the user + await fclUser.unauthenticate() + } + } + } + + // Set up event listeners regardless of the current authentication state + provider.on("connect", async () => { + try { + await refreshFclUser() + } catch (error) { + console.error("Error during authentication on connect:", error) + } + }) + + provider.on("disconnect", async () => { + try { + await refreshFclUser() + } catch (error) { + console.error("Error during unauthentication on disconnect:", error) + } + }) + + return provider + } + + async connect( + opts?: Parameters["connect"]>[0] + ) { + if (!this.signer.client) { + throw new Error("Provider not initialized. Call init() first") + } + + this.loadConnectOpts(opts) + + const chains = new Set(opts?.chains ?? []) + const optionalChains = new Set(opts?.optionalChains ?? []) + const chainIds = Array.from(chains).concat(Array.from(optionalChains)) + + const flowNetwork = Object.entries(FLOW_CHAINS).find( + ([, {eip155ChainId}]) => { + if (chainIds.includes(eip155ChainId)) { + return true + } + return false + } + )?.[0] + if (!flowNetwork) { + throw new Error( + `Unsupported chainId: ${chainIds.join(", ")}, expected one of ${Object.values( + FLOW_CHAINS + ) + .map(({eip155ChainId}) => eip155ChainId) + .join(", ")}` + ) + } + + const {required, optional} = buildNamespaces(flowNetwork as FlowNetwork) + try { + const session = await new Promise( + async (resolve, reject) => { + if (this.rpc.showQrModal) { + this.modal?.subscribeModal((state: {open: boolean}) => { + // the modal was closed so reject the promise + if (!state.open && !this.signer.session) { + this.signer.abortPairingAttempt() + reject(new Error("Connection request reset. Please try again.")) + } + }) + } + await this.signer + .connect({ + namespaces: required, + optionalNamespaces: optional, + pairingTopic: opts?.pairingTopic, + }) + .then((session?: SessionTypes.Struct) => { + resolve(session) + }) + .catch((error: unknown) => { + var newErr = new Error("Failed to connect") + if (error instanceof Error) + newErr.stack += "\nCaused by: " + error.stack + throw newErr + }) + } + ) + if (!session) return + + const accounts = getAccountsFromNamespaces(session.namespaces, [ + this.namespace, + ]) + // if no required chains are set, use the approved accounts to fetch chainIds + this.setChainIds(this.rpc.chains.length ? this.rpc.chains : accounts) + this.setAccounts(accounts) + this.events.emit("connect", {chainId: formatChainId(this.chainId)}) + } catch (error) { + this.signer.logger.error(error) + throw error + } finally { + if (this.modal) this.modal.closeModal() + } + } +} + +function buildNamespaces(network: FlowNetwork): { + required: NamespaceConfig + optional: NamespaceConfig +} { + const {eip155ChainId} = FLOW_CHAINS[network] + + return { + required: { + eip155: { + methods: REQUIRED_METHODS, + chains: [`eip155:${eip155ChainId}`], + events: REQUIRED_EVENTS, + }, + }, + optional: { + eip155: { + methods: OPTIONAL_METHODS, + chains: [`eip155:${eip155ChainId}`], + events: OPTIONAL_EVENTS, + }, + flow: { + methods: Object.values(FLOW_METHODS), + events: ["chainChanged", "accountsChanged"], + chains: [`flow:${network}`], + }, + }, + } +} diff --git a/packages/fcl-rainbowkit-adapter/package.json b/packages/fcl-rainbowkit-adapter/package.json index 8998b5a3a..ef4ea572a 100644 --- a/packages/fcl-rainbowkit-adapter/package.json +++ b/packages/fcl-rainbowkit-adapter/package.json @@ -45,7 +45,9 @@ "@wagmi/core": "^2.16.3", "@walletconnect/jsonrpc-http-connection": "^1.0.8", "@walletconnect/jsonrpc-provider": "^1.0.14", - "viem": "^2.22.21" + "mipd": "^0.0.7", + "viem": "^2.22.21", + "wagmi": "^2.14.11" }, "peerDependencies": { "@onflow/fcl": "^1.13.4", diff --git a/packages/fcl-rainbowkit-adapter/src/create-connector.ts b/packages/fcl-rainbowkit-adapter/src/create-connector.ts index 00ad8b1bc..96bcad645 100644 --- a/packages/fcl-rainbowkit-adapter/src/create-connector.ts +++ b/packages/fcl-rainbowkit-adapter/src/create-connector.ts @@ -1,8 +1,11 @@ import {fclWagmiAdapter} from "@onflow/fcl-wagmi-adapter" -import {Wallet} from "@rainbow-me/rainbowkit" +import {RainbowKitWalletConnectParameters, Wallet} from "@rainbow-me/rainbowkit" import {createConnector} from "@wagmi/core" -type FclConnectorOptions = Parameters[0] +type FclConnectorOptions = Parameters[0] & { + supportsWc?: boolean + walletConnectParams?: RainbowKitWalletConnectParameters +} type DefaultWalletOptions = { projectId: string @@ -14,19 +17,46 @@ const FALLBACK_ICON = export const createFclConnector = (options: FclConnectorOptions) => { const uid = options.service?.uid const name = options.service?.provider?.name - const iconUrl = options.service?.provider?.icon! + const iconUrl = options.service?.provider?.icon ?? "" + const rdns = (options.service?.provider as any)?.rdns as string | undefined + + const getUri = (uri: string) => { + return uri + } return ({projectId}: DefaultWalletOptions): Wallet => ({ id: uid ? `fcl-${uid}` : "fcl", name: name || "Cadence Wallet", iconUrl: iconUrl || FALLBACK_ICON, iconBackground: "#FFFFFF", + installed: true, + downloadUrls: { + browserExtension: + "https://chrome.google.com/webstore/detail/flow-wallet/hpclkefagolihohboafpheddmmgdffjm", + mobile: "https://core.flow.com", + }, + // Do not list RDNS here since Rainbowkit will discard the wallet + // when conflicting with an injected wallet + rdns: undefined, createConnector: walletDetails => { - const connector = fclWagmiAdapter(options) - return createConnector(config => ({ - ...connector(config), + // TODO, we need to check whether the wallet is installed + // and use the WalletConnect connector if it is not installed + const newDetails = { ...walletDetails, - })) + rkDetails: { + ...walletDetails.rkDetails, + groupIndex: -1, + groupName: "Installed", + }, + } + + const connector = fclWagmiAdapter(options) + return createConnector(config => { + return { + ...connector(config), + ...newDetails, + } + }) }, }) } diff --git a/packages/fcl-rainbowkit-adapter/src/get-wc-connector.ts b/packages/fcl-rainbowkit-adapter/src/get-wc-connector.ts new file mode 100644 index 000000000..ff1df663e --- /dev/null +++ b/packages/fcl-rainbowkit-adapter/src/get-wc-connector.ts @@ -0,0 +1,153 @@ +/* + * This file is mostly a copy of Rainbowkit's internal get wc connector utility, + * meant to cache and reuse walletConnect connector instances. + * + * The caveat is that we are substituting the original connector with a multi-scoped + * version that is able to be used in a cross-VM context. + * + * See: https://github.com/rainbow-me/rainbowkit/blob/0c9679812123e17b45e1330d5e3b665b48c82864/packages/rainbowkit/src/wallets/getWalletConnectConnector.ts + */ + +/*! + * MIT License + * + * Copyright (c) 2024 Rainbow + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import {createConnector} from "wagmi" +import type {CreateConnectorFn} from "wagmi" +import {walletConnect, WalletConnectParameters} from "@onflow/fcl-wagmi-adapter" +import type { + RainbowKitWalletConnectParameters, + WalletDetailsParams, +} from "@rainbow-me/rainbowkit" + +type RainbowKitDetails = any +type CreateConnector = (walletDetails: WalletDetailsParams) => CreateConnectorFn + +interface GetWalletConnectConnectorParams { + projectId: string + walletConnectParameters?: RainbowKitWalletConnectParameters +} + +interface CreateWalletConnectConnectorParams { + projectId: string + walletDetails: WalletDetailsParams + walletConnectParameters?: RainbowKitWalletConnectParameters +} + +interface GetOrCreateWalletConnectInstanceParams { + projectId: string + walletConnectParameters?: RainbowKitWalletConnectParameters + rkDetailsShowQrModal?: RainbowKitDetails["showQrModal"] +} + +const walletConnectInstances = new Map< + string, + ReturnType +>() + +// Function to get or create a walletConnect instance +const getOrCreateWalletConnectInstance = ({ + projectId, + walletConnectParameters, + rkDetailsShowQrModal, +}: GetOrCreateWalletConnectInstanceParams): ReturnType< + typeof walletConnect +> => { + let config: WalletConnectParameters = { + ...(walletConnectParameters ? walletConnectParameters : {}), + projectId, + showQrModal: false, // Required. Otherwise WalletConnect modal (Web3Modal) will popup during time of connection for a wallet + } as any + + // `rkDetailsShowQrModal` should always be `true` + if (rkDetailsShowQrModal) { + config = {...config, showQrModal: true} + } + + const serializedConfig = JSON.stringify( + Object.keys(config) + .sort() + .reduce((obj: any, key) => { + obj[key] = config[key as keyof WalletConnectParameters] + return obj + }, {} as WalletConnectParameters) + ) + + const sharedWalletConnector = walletConnectInstances.get(serializedConfig) + + if (sharedWalletConnector) { + return sharedWalletConnector + } + + // Create a new walletConnect instance and store it + const newWalletConnectInstance = walletConnect(config) + + walletConnectInstances.set(serializedConfig, newWalletConnectInstance) + + return newWalletConnectInstance +} + +// Creates a WalletConnect connector with the given project ID and additional options. +function createWalletConnectConnector({ + projectId, + walletDetails, + walletConnectParameters, +}: CreateWalletConnectConnectorParams): CreateConnectorFn { + // Create and configure the WalletConnect connector with project ID and options. + return createConnector(config => ({ + ...getOrCreateWalletConnectInstance({ + projectId, + walletConnectParameters, + // Used in `connectorsForWallets` to add another + // walletConnect wallet into rainbowkit with modal popup option + rkDetailsShowQrModal: walletDetails.rkDetails.showQrModal, + })(config), + ...walletDetails, + })) +} + +// Factory function to obtain a configured WalletConnect connector. +export function getWalletConnectConnector({ + projectId, + walletConnectParameters, +}: GetWalletConnectConnectorParams): CreateConnector { + // We use this projectId in place of YOUR_PROJECT_ID for our examples. + // This allows us our examples and templates to be functional with WalletConnect v2. + // We warn developers against using this projectId in their dApp in production. + const exampleProjectId = "21fef48091f12692cad574a6f7753643" + + if (!projectId || projectId === "") { + throw new Error( + "No projectId found. Every dApp must now provide a WalletConnect Cloud projectId to enable WalletConnect v2 https://www.rainbowkit.com/docs/installation#configure" + ) + } + + if (projectId === "YOUR_PROJECT_ID") { + projectId = exampleProjectId + } + + // Return a function that merges additional wallet details with `CreateConnectorFn`. + return (walletDetails: WalletDetailsParams) => + createWalletConnectConnector({ + projectId, + walletDetails, + walletConnectParameters, + }) +} diff --git a/packages/fcl-rainbowkit-adapter/src/index.ts b/packages/fcl-rainbowkit-adapter/src/index.ts index 7c9d28a7c..c7607699a 100644 --- a/packages/fcl-rainbowkit-adapter/src/index.ts +++ b/packages/fcl-rainbowkit-adapter/src/index.ts @@ -1,2 +1,6 @@ +export {flowWallet} from "./wallets/flow-wallet" export {createFclConnector} from "./create-connector" -export {flowWallet} from "./flow-wallet" +export { + type WalletConnectWalletOptions, + walletConnectWallet, +} from "./wallets/wc-wallet" diff --git a/packages/fcl-rainbowkit-adapter/src/flow-wallet.ts b/packages/fcl-rainbowkit-adapter/src/wallets/flow-wallet.ts similarity index 93% rename from packages/fcl-rainbowkit-adapter/src/flow-wallet.ts rename to packages/fcl-rainbowkit-adapter/src/wallets/flow-wallet.ts index 55c544476..64ed23a92 100644 --- a/packages/fcl-rainbowkit-adapter/src/flow-wallet.ts +++ b/packages/fcl-rainbowkit-adapter/src/wallets/flow-wallet.ts @@ -1,5 +1,5 @@ import {Service} from "@onflow/typedefs" -import {createFclConnector} from "./create-connector" +import {createFclConnector} from "../create-connector" import * as fcl from "@onflow/fcl" /** @@ -18,7 +18,7 @@ export const flowWallet = (params: { f_type: "Service", f_vsn: "1.0.0", type: "authn", - uid: "Flow Wallet", + uid: "fcw#authn", endpoint: "chrome-extension://hpclkefagolihohboafpheddmmgdffjm/popup.html", method: "EXT/RPC", diff --git a/packages/fcl-rainbowkit-adapter/src/wallets/wc-wallet.ts b/packages/fcl-rainbowkit-adapter/src/wallets/wc-wallet.ts new file mode 100644 index 000000000..64680ed33 --- /dev/null +++ b/packages/fcl-rainbowkit-adapter/src/wallets/wc-wallet.ts @@ -0,0 +1,63 @@ +/* + * This file is mostly a copy of Rainbowkit's internal WalletConnect wallet implementation. + * The purpose is to substitute the original connector with a multi-scoped vesion that is + * able to be used in a cross-VM context. + * + * See: https://github.com/rainbow-me/rainbowkit/blob/0c9679812123e17b45e1330d5e3b665b48c82864/packages/rainbowkit/src/wallets/walletConnectors/walletConnectWallet/walletConnectWallet.ts#L9 + */ + +/*! + * MIT License + * + * Copyright (c) 2024 Rainbow + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import { + type RainbowKitWalletConnectParameters, + type Wallet, +} from "@rainbow-me/rainbowkit" +import {getWalletConnectConnector} from "../get-wc-connector" + +const WALLETCONNECT_ICON = `data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjgiIGhlaWdodD0iMjgiIHZpZXdCb3g9IjAgMCAyOCAyOCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjI4IiBoZWlnaHQ9IjI4IiBmaWxsPSIjM0I5OUZDIi8+CjxwYXRoIGQ9Ik04LjM4OTY5IDEwLjM3MzlDMTEuNDg4MiA3LjI3NTM4IDE2LjUxMTggNy4yNzUzOCAxOS42MTAzIDEwLjM3MzlMMTkuOTgzMiAxMC43NDY4QzIwLjEzODIgMTAuOTAxNyAyMC4xMzgyIDExLjE1MjkgMTkuOTgzMiAxMS4zMDc4TDE4LjcwNzYgMTIuNTgzNUMxOC42MzAxIDEyLjY2MDkgMTguNTA0NSAxMi42NjA5IDE4LjQyNzEgMTIuNTgzNUwxNy45MTM5IDEyLjA3MDNDMTUuNzUyMyA5LjkwODcgMTIuMjQ3NyA5LjkwODcgMTAuMDg2MSAxMi4wNzAzTDkuNTM2NTUgMTIuNjE5OEM5LjQ1OTA5IDEyLjY5NzMgOS4zMzM1IDEyLjY5NzMgOS4yNTYwNCAxMi42MTk4TDcuOTgwMzkgMTEuMzQ0MkM3LjgyNTQ3IDExLjE4OTMgNy44MjU0NyAxMC45MzgxIDcuOTgwMzkgMTAuNzgzMkw4LjM4OTY5IDEwLjM3MzlaTTIyLjI0ODUgMTMuMDEyTDIzLjM4MzggMTQuMTQ3NEMyMy41Mzg3IDE0LjMwMjMgMjMuNTM4NyAxNC41NTM1IDIzLjM4MzggMTQuNzA4NEwxOC4yNjQ1IDE5LjgyNzdDMTguMTA5NiAxOS45ODI3IDE3Ljg1ODQgMTkuOTgyNyAxNy43MDM1IDE5LjgyNzdDMTcuNzAzNSAxOS44Mjc3IDE3LjcwMzUgMTkuODI3NyAxNy43MDM1IDE5LjgyNzdMMTQuMDcwMiAxNi4xOTQ0QzE0LjAzMTQgMTYuMTU1NyAxMy45Njg2IDE2LjE1NTcgMTMuOTI5OSAxNi4xOTQ0QzEzLjkyOTkgMTYuMTk0NCAxMy45Mjk5IDE2LjE5NDQgMTMuOTI5OSAxNi4xOTQ0TDEwLjI5NjYgMTkuODI3N0MxMC4xNDE3IDE5Ljk4MjcgOS44OTA1MyAxOS45ODI3IDkuNzM1NjEgMTkuODI3OEM5LjczNTYgMTkuODI3OCA5LjczNTYgMTkuODI3NyA5LjczNTYgMTkuODI3N0w0LjYxNjE5IDE0LjcwODNDNC40NjEyNyAxNC41NTM0IDQuNDYxMjcgMTQuMzAyMiA0LjYxNjE5IDE0LjE0NzNMNS43NTE1MiAxMy4wMTJDNS45MDY0NSAxMi44NTcgNi4xNTc2MyAxMi44NTcgNi4zMTI1NSAxMy4wMTJMOS45NDU5NSAxNi42NDU0QzkuOTg0NjggMTYuNjg0MSAxMC4wNDc1IDE2LjY4NDEgMTAuMDg2MiAxNi42NDU0QzEwLjA4NjIgMTYuNjQ1NCAxMC4wODYyIDE2LjY0NTQgMTAuMDg2MiAxNi42NDU0TDEzLjcxOTQgMTMuMDEyQzEzLjg3NDMgMTIuODU3IDE0LjEyNTUgMTIuODU3IDE0LjI4MDUgMTMuMDEyQzE0LjI4MDUgMTMuMDEyIDE0LjI4MDUgMTMuMDEyIDE0LjI4MDUgMTMuMDEyTDE3LjkxMzkgMTYuNjQ1NEMxNy45NTI2IDE2LjY4NDEgMTguMDE1NCAxNi42ODQxIDE4LjA1NDEgMTYuNjQ1NEwyMS42ODc0IDEzLjAxMkMyMS44NDI0IDEyLjg1NzEgMjIuMDkzNiAxMi44NTcxIDIyLjI0ODUgMTMuMDEyWiIgZmlsbD0id2hpdGUiLz4KPC9zdmc+Cg==` + +export interface WalletConnectWalletOptions { + projectId: string + options?: RainbowKitWalletConnectParameters +} + +export const walletConnectWallet = ({ + projectId, + options, +}: WalletConnectWalletOptions): Wallet => { + const getUri = (uri: string) => { + return uri + } + + return { + id: "walletConnect", + name: "WalletConnect", + installed: undefined, + iconUrl: WALLETCONNECT_ICON, + iconBackground: "#3b99fc", + qrCode: {getUri}, + createConnector: getWalletConnectConnector({ + projectId, + walletConnectParameters: options, + }), + } +} diff --git a/packages/fcl-wagmi-adapter/package.json b/packages/fcl-wagmi-adapter/package.json index 27dcc5ce2..43022de41 100644 --- a/packages/fcl-wagmi-adapter/package.json +++ b/packages/fcl-wagmi-adapter/package.json @@ -43,6 +43,10 @@ "@onflow/rlp": "^1.2.3", "@walletconnect/jsonrpc-http-connection": "^1.0.8", "@walletconnect/jsonrpc-provider": "^1.0.14", + "@walletconnect/modal": "^2.7.0", + "@walletconnect/types": "^2.18.0", + "@walletconnect/universal-provider": "^2.18.0", + "@walletconnect/utils": "^2.18.0", "viem": "^2.22.21" }, "peerDependencies": { diff --git a/packages/fcl-wagmi-adapter/src/fcl-connector.ts b/packages/fcl-wagmi-adapter/src/fcl-connector.ts new file mode 100644 index 000000000..911a1f826 --- /dev/null +++ b/packages/fcl-wagmi-adapter/src/fcl-connector.ts @@ -0,0 +1,213 @@ +import { + ChainNotConfiguredError, + type Connector, + createConnector, +} from "@wagmi/core" +import { + type Address, + type ProviderConnectInfo, + ProviderDisconnectedError, + SwitchChainError, + getAddress, + numberToHex, +} from "viem" +import {createProvider} from "@onflow/fcl-ethereum-provider" + +type FclWagmiAdapterParams = Parameters[0] + +export function fclWagmiAdapter(params: FclWagmiAdapterParams) { + type Provider = ReturnType + type Properties = { + onConnect(connectInfo: ProviderConnectInfo): void + onDisplayUri(uri: string): void + } + let provider: Provider | undefined + + let accountsChanged: Connector["onAccountsChanged"] | undefined + let chainChanged: Connector["onChainChanged"] | undefined + let connect: Connector["onConnect"] | undefined + let disconnect: ((error: Error) => void) | undefined + + // Parse and validate service parameters + const id = params.service?.uid || "fcl" + const name = params.service?.provider?.name || "Cadence Wallet" + + // TODO: we need to surface this through FCL service configuration + const rdns = (params.service?.provider as any)?.rdns + + return createConnector(config => ({ + id: id, + name: name, + type: "fcl-wagmi-adapter", + rdns: rdns, + async setup() { + const provider = await this.getProvider() + + if (connect) provider.removeListener("connect", connect) + connect = this.onConnect.bind(this) + provider.on("connect", connect) + + // We shouldn't need to listen for `'accountsChanged'` here since the `'connect'` event should suffice (and wallet shouldn't be connected yet). + // Some wallets, like MetaMask, do not implement the `'connect'` event and overload `'accountsChanged'` instead. + if (!accountsChanged) { + accountsChanged = this.onAccountsChanged.bind(this) + provider.on("accountsChanged", accountsChanged) + } + }, + async connect({isReconnecting}: any = {}) { + const provider = await this.getProvider() + + let accounts: readonly Address[] + if (isReconnecting) { + accounts = await this.getAccounts() + } else { + accounts = ( + (await provider.request({ + method: "eth_requestAccounts", + })) as string[] + ).map(x => getAddress(x)) + } + + // Manage EIP-1193 event listeners + // https://eips.ethereum.org/EIPS/eip-1193#events + if (connect) provider.removeListener("connect", connect) + connect = this.onConnect.bind(this) + provider.on("connect", connect) + + if (accountsChanged) + provider.removeListener("accountsChanged", accountsChanged) + accountsChanged = this.onAccountsChanged.bind(this) + provider.on("accountsChanged", accountsChanged) + + if (chainChanged) provider.removeListener("chainChanged", chainChanged) + chainChanged = this.onChainChanged.bind(this) + provider.on("chainChanged", chainChanged) + + if (disconnect) provider.removeListener("disconnect", disconnect) + disconnect = (error: Error) => { + throw new ProviderDisconnectedError(error) + } + provider.on("disconnect", disconnect) + + return {accounts, chainId: await this.getChainId()} + }, + async disconnect() { + const provider = await this.getProvider() + + // Manage EIP-1193 event listeners + if (chainChanged) provider.removeListener("chainChanged", chainChanged) + chainChanged = undefined + + if (disconnect) provider.removeListener("disconnect", disconnect) + disconnect = undefined + + if (connect) provider.removeListener("connect", connect) + connect = this.onConnect.bind(this) + provider.on("connect", connect) + + await provider.disconnect() + }, + async getAccounts() { + const provider = await this.getProvider() + const accounts = (await provider.request({ + method: "eth_accounts", + })) as string[] + return accounts.map(x => getAddress(x)) + }, + async getChainId() { + const provider = await this.getProvider() + const chainId = await provider.request({method: "eth_chainId"}) + return Number(chainId) + }, + async getProvider() { + return provider ?? (provider = createProvider(params)) + }, + async isAuthorized() { + // TODO: There may be an issue here if a user without a COA refreshes the page + // We should instead be checking whether FCL itself is authorized + const accounts = await this.getAccounts() + return accounts.length > 0 + }, + async switchChain({addEthereumChainParameter, chainId}: any) { + const provider = await this.getProvider() + + const chain = config.chains.find(x => x.id === chainId) + if (!chain) throw new SwitchChainError(new ChainNotConfiguredError()) + + try { + await provider.request({ + method: "wallet_switchEthereumChain", + params: [{chainId: numberToHex(chainId)}], + }) + + return chain + } catch (err) { + // TODO: Error handling + throw new SwitchChainError(err as Error) + } + }, + onAccountsChanged(accounts) { + if (accounts.length === 0) this.onDisconnect() + else + config.emitter.emit("change", { + accounts: accounts.map((x: any) => getAddress(x)), + }) + }, + onChainChanged(chain) { + const chainId = Number(chain) + config.emitter.emit("change", {chainId}) + }, + async onConnect(connectInfo) { + const accounts = await this.getAccounts() + + // TODO: What to do if accounts is empty? not sure this is accurate + if (accounts.length === 0) return + + const chainId = Number(connectInfo.chainId) + config.emitter.emit("connect", {accounts, chainId}) + + const provider = await this.getProvider() + + if (connect) provider.removeListener("connect", connect) + connect = undefined + + if (accountsChanged) + provider.removeListener("accountsChanged", accountsChanged) + accountsChanged = this.onAccountsChanged.bind(this) + provider.on("accountsChanged", accountsChanged) + + if (chainChanged) provider.removeListener("chainChanged", chainChanged) + chainChanged = this.onChainChanged.bind(this) + provider.on("chainChanged", chainChanged) + + if (disconnect) provider.removeListener("disconnect", disconnect) + disconnect = (error: Error) => { + throw new ProviderDisconnectedError(error) + } + provider.on("disconnect", disconnect) + }, + // TODO: waht to do with error? + async onDisconnect(error) { + const provider = await this.getProvider() + + config.emitter.emit("disconnect") + + // Manage EIP-1193 event listeners + if (chainChanged) { + provider.removeListener("chainChanged", chainChanged) + chainChanged = undefined + } + if (disconnect) { + provider.removeListener("disconnect", disconnect) + disconnect = undefined + } + if (!connect) { + connect = this.onConnect.bind(this) + provider.on("connect", connect) + } + }, + onDisplayUri(uri: string) { + config.emitter.emit("message", {type: "display_uri", data: uri}) + }, + })) +} diff --git a/packages/fcl-wagmi-adapter/src/index.ts b/packages/fcl-wagmi-adapter/src/index.ts index 5fffa43bb..6cea6ebfa 100644 --- a/packages/fcl-wagmi-adapter/src/index.ts +++ b/packages/fcl-wagmi-adapter/src/index.ts @@ -1,215 +1,2 @@ -import { - ChainNotConfiguredError, - type Connector, - createConnector, -} from "@wagmi/core" -import { - type Address, - type ProviderConnectInfo, - ProviderDisconnectedError, - SwitchChainError, - getAddress, - numberToHex, -} from "viem" -import {createProvider} from "@onflow/fcl-ethereum-provider" - -type FclWagmiAdapterParams = Parameters[0] - -export function fclWagmiAdapter(params: FclWagmiAdapterParams) { - type Provider = ReturnType - type Properties = { - onConnect(connectInfo: ProviderConnectInfo): void - onDisplayUri(uri: string): void - } - let provider: Provider | undefined - - let accountsChanged: Connector["onAccountsChanged"] | undefined - let chainChanged: Connector["onChainChanged"] | undefined - let connect: Connector["onConnect"] | undefined - let disconnect: ((error: Error) => void) | undefined - - // Parse and validate service parameters - const id = params.service?.uid || "fcl" - const name = params.service?.provider?.name || "Cadence Wallet" - - // TODO: we need to surface this through FCL service configuration - const rdns = (params.service?.provider as any)?.rdns - - return createConnector(config => ({ - id: id, - name: name, - type: "fcl-wagmi-adapter", - rdns: rdns, - async setup() { - const provider = await this.getProvider() - - if (connect) provider.removeListener("connect", connect) - connect = this.onConnect.bind(this) - provider.on("connect", connect) - - // We shouldn't need to listen for `'accountsChanged'` here since the `'connect'` event should suffice (and wallet shouldn't be connected yet). - // Some wallets, like MetaMask, do not implement the `'connect'` event and overload `'accountsChanged'` instead. - if (!accountsChanged) { - accountsChanged = this.onAccountsChanged.bind(this) - provider.on("accountsChanged", accountsChanged) - } - }, - async connect({isReconnecting}: any = {}) { - const provider = await this.getProvider() - - let accounts: readonly Address[] - if (isReconnecting) { - accounts = await this.getAccounts() - } else { - accounts = ( - (await provider.request({ - method: "eth_requestAccounts", - })) as string[] - ).map(x => getAddress(x)) - } - - // Manage EIP-1193 event listeners - // https://eips.ethereum.org/EIPS/eip-1193#events - if (connect) provider.removeListener("connect", connect) - connect = this.onConnect.bind(this) - provider.on("connect", connect) - - if (accountsChanged) - provider.removeListener("accountsChanged", accountsChanged) - accountsChanged = this.onAccountsChanged.bind(this) - provider.on("accountsChanged", accountsChanged) - - if (chainChanged) provider.removeListener("chainChanged", chainChanged) - chainChanged = this.onChainChanged.bind(this) - provider.on("chainChanged", chainChanged) - - if (disconnect) provider.removeListener("disconnect", disconnect) - disconnect = (error: Error) => { - throw new ProviderDisconnectedError(error) - } - provider.on("disconnect", disconnect) - - return {accounts, chainId: await this.getChainId()} - }, - async disconnect() { - const provider = await this.getProvider() - - // Manage EIP-1193 event listeners - if (chainChanged) provider.removeListener("chainChanged", chainChanged) - chainChanged = undefined - - if (disconnect) provider.removeListener("disconnect", disconnect) - disconnect = undefined - - if (connect) provider.removeListener("connect", connect) - connect = this.onConnect.bind(this) - provider.on("connect", connect) - - await provider.disconnect() - }, - async getAccounts() { - const provider = await this.getProvider() - const accounts = (await provider.request({ - method: "eth_accounts", - })) as string[] - return accounts.map(x => getAddress(x)) - }, - async getChainId() { - const provider = await this.getProvider() - const chainId = await provider.request({method: "eth_chainId"}) - console.log("CHAIN ID", chainId) - return Number(chainId) - }, - async getProvider() { - return provider ?? (provider = createProvider(params)) - }, - async isAuthorized() { - // TODO: There may be an issue here if a user without a COA refreshes the page - // We should instead be checking whether FCL itself is authorized - const accounts = await this.getAccounts() - return accounts.length > 0 - }, - async switchChain({addEthereumChainParameter, chainId}: any) { - console.log("HEY") - const provider = await this.getProvider() - - const chain = config.chains.find(x => x.id === chainId) - if (!chain) throw new SwitchChainError(new ChainNotConfiguredError()) - - try { - await provider.request({ - method: "wallet_switchEthereumChain", - params: [{chainId: numberToHex(chainId)}], - }) - - return chain - } catch (err) { - // TODO: Error handling - throw new SwitchChainError(err as Error) - } - }, - onAccountsChanged(accounts) { - if (accounts.length === 0) this.onDisconnect() - else - config.emitter.emit("change", { - accounts: accounts.map((x: any) => getAddress(x)), - }) - }, - onChainChanged(chain) { - const chainId = Number(chain) - config.emitter.emit("change", {chainId}) - }, - async onConnect(connectInfo) { - const accounts = await this.getAccounts() - - // TODO: What to do if accounts is empty? not sure this is accurate - if (accounts.length === 0) return - - const chainId = Number(connectInfo.chainId) - config.emitter.emit("connect", {accounts, chainId}) - - const provider = await this.getProvider() - - if (connect) provider.removeListener("connect", connect) - connect = undefined - - if (accountsChanged) - provider.removeListener("accountsChanged", accountsChanged) - accountsChanged = this.onAccountsChanged.bind(this) - provider.on("accountsChanged", accountsChanged) - - if (chainChanged) provider.removeListener("chainChanged", chainChanged) - chainChanged = this.onChainChanged.bind(this) - provider.on("chainChanged", chainChanged) - - if (disconnect) provider.removeListener("disconnect", disconnect) - disconnect = (error: Error) => { - throw new ProviderDisconnectedError(error) - } - provider.on("disconnect", disconnect) - }, - // TODO: waht to do with error? - async onDisconnect(error) { - const provider = await this.getProvider() - - config.emitter.emit("disconnect") - - // Manage EIP-1193 event listeners - if (chainChanged) { - provider.removeListener("chainChanged", chainChanged) - chainChanged = undefined - } - if (disconnect) { - provider.removeListener("disconnect", disconnect) - disconnect = undefined - } - if (!connect) { - connect = this.onConnect.bind(this) - provider.on("connect", connect) - } - }, - onDisplayUri(uri: string) { - config.emitter.emit("message", {type: "display_uri", data: uri}) - }, - })) -} +export * from "./wc-connector" +export * from "./fcl-connector" diff --git a/packages/fcl-wagmi-adapter/src/wc-connector.ts b/packages/fcl-wagmi-adapter/src/wc-connector.ts new file mode 100644 index 000000000..f93c9dc5e --- /dev/null +++ b/packages/fcl-wagmi-adapter/src/wc-connector.ts @@ -0,0 +1,500 @@ +/** + * This file is a modified version of the original WalletConnect connector from wagmi. + * The purpose is to substitute the original WalletConnect EthereumProvider with an extended + * version that is able to be used in a cross-VM context (authenticating multiple VMs). + * + * See: https://github.com/wevm/wagmi/blob/2ca5742840f0c3be99cd61095650400aee514913/packages/connectors/src/walletConnect.ts + */ + +/*! + * MIT License + * + * Copyright (c) 2022-present weth, LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { + ChainNotConfiguredError, + type Connector, + ProviderNotFoundError, + createConnector, + extractRpcUrls, +} from "@wagmi/core" +import type {Compute, ExactPartial, Omit} from "@wagmi/core/internal" +import {WalletConnectEthereumProvider as EthereumProvider} from "@onflow/fcl-ethereum-provider" +import { + type AddEthereumChainParameter, + type Address, + type ProviderConnectInfo, + type ProviderRpcError, + type RpcError, + SwitchChainError, + UserRejectedRequestError, + getAddress, + numberToHex, +} from "viem" + +type WalletConnectConnector = Connector & { + onDisplayUri(uri: string): void + onSessionDelete(data: {topic: string}): void +} + +type EthereumProviderOptions = Parameters<(typeof EthereumProvider)["init"]>[0] + +export type WalletConnectParameters = Compute< + { + /** + * If a new chain is added to a previously existing configured connector `chains`, this flag + * will determine if that chain should be considered as stale. A stale chain is a chain that + * WalletConnect has yet to establish a relationship with (e.g. the user has not approved or + * rejected the chain). + * + * This flag mainly affects the behavior when a wallet does not support dynamic chain authorization + * with WalletConnect v2. + * + * If `true` (default), the new chain will be treated as a stale chain. If the user + * has yet to establish a relationship (approved/rejected) with this chain in their WalletConnect + * session, the connector will disconnect upon the dapp auto-connecting, and the user will have to + * reconnect to the dapp (revalidate the chain) in order to approve the newly added chain. + * This is the default behavior to avoid an unexpected error upon switching chains which may + * be a confusing user experience (e.g. the user will not know they have to reconnect + * unless the dapp handles these types of errors). + * + * If `false`, the new chain will be treated as a potentially valid chain. This means that if the user + * has yet to establish a relationship with the chain in their WalletConnect session, wagmi will successfully + * auto-connect the user. This comes with the trade-off that the connector will throw an error + * when attempting to switch to the unapproved chain if the wallet does not support dynamic session updates. + * This may be useful in cases where a dapp constantly + * modifies their configured chains, and they do not want to disconnect the user upon + * auto-connecting. If the user decides to switch to the unapproved chain, it is important that the + * dapp handles this error and prompts the user to reconnect to the dapp in order to approve + * the newly added chain. + * + * @default true + */ + isNewChainsStale?: boolean + } & Omit< + EthereumProviderOptions, + | "chains" + | "events" + | "optionalChains" + | "optionalEvents" + | "optionalMethods" + | "methods" + | "rpcMap" + | "showQrModal" + > & + ExactPartial> +> + +walletConnect.type = "walletConnect" as const +export function walletConnect(parameters: WalletConnectParameters) { + const isNewChainsStale = parameters.isNewChainsStale ?? true + + type Provider = Awaited> + type Properties = { + connect(parameters?: { + chainId?: number | undefined + isReconnecting?: boolean | undefined + pairingTopic?: string | undefined + }): Promise<{ + accounts: readonly Address[] + chainId: number + }> + getNamespaceChainsIds(): number[] + getRequestedChainsIds(): Promise + isChainsStale(): Promise + onConnect(connectInfo: ProviderConnectInfo): void + onDisplayUri(uri: string): void + onSessionDelete(data: {topic: string}): void + setRequestedChainsIds(chains: number[]): void + requestedChainsStorageKey: `${string}.requestedChains` + } + type StorageItem = { + [_ in Properties["requestedChainsStorageKey"]]: number[] + } + + let provider_: Provider | undefined + let providerPromise: Promise + const NAMESPACE = "eip155" + + let accountsChanged: WalletConnectConnector["onAccountsChanged"] | undefined + let chainChanged: WalletConnectConnector["onChainChanged"] | undefined + let connect: WalletConnectConnector["onConnect"] | undefined + let displayUri: WalletConnectConnector["onDisplayUri"] | undefined + let sessionDelete: WalletConnectConnector["onSessionDelete"] | undefined + let disconnect: WalletConnectConnector["onDisconnect"] | undefined + + return createConnector(config => ({ + id: "walletConnect", + name: "WalletConnect", + type: walletConnect.type, + async setup() { + const provider = await this.getProvider().catch(() => null) + if (!provider) return + if (!connect) { + connect = this.onConnect.bind(this) + provider.on("connect", connect) + } + if (!sessionDelete) { + sessionDelete = this.onSessionDelete.bind(this) + provider.on("session_delete", sessionDelete) + } + }, + async connect({chainId, ...rest} = {}) { + try { + const provider = await this.getProvider() + if (!provider) throw new ProviderNotFoundError() + if (!displayUri) { + displayUri = this.onDisplayUri + provider.on("display_uri", displayUri) + } + + let targetChainId = chainId + if (!targetChainId) { + const state = (await config.storage?.getItem("state")) ?? {} + const isChainSupported = config.chains.some( + x => x.id === state.chainId + ) + if (isChainSupported) targetChainId = state.chainId + else targetChainId = config.chains[0]?.id + } + if (!targetChainId) throw new Error("No chains found on connector.") + + const isChainsStale = await this.isChainsStale() + // If there is an active session with stale chains, disconnect current session. + if (provider.session && isChainsStale) await provider.disconnect() + + // If there isn't an active session or chains are stale, connect. + if (!provider.session || isChainsStale) { + const optionalChains = config.chains + .filter(chain => chain.id !== targetChainId) + .map(optionalChain => optionalChain.id) + await provider.connect({ + optionalChains: [targetChainId, ...optionalChains], + ...("pairingTopic" in rest + ? {pairingTopic: rest.pairingTopic} + : {}), + }) + + this.setRequestedChainsIds(config.chains.map(x => x.id)) + } + + // If session exists and chains are authorized, enable provider for required chain + const accounts = (await provider.enable()).map(x => getAddress(x)) + const currentChainId = await this.getChainId() + + if (displayUri) { + provider.removeListener("display_uri", displayUri) + displayUri = undefined + } + if (connect) { + provider.removeListener("connect", connect) + connect = undefined + } + if (!accountsChanged) { + accountsChanged = this.onAccountsChanged.bind(this) + provider.on("accountsChanged", accountsChanged) + } + if (!chainChanged) { + chainChanged = this.onChainChanged.bind(this) + provider.on("chainChanged", chainChanged) + } + if (!disconnect) { + disconnect = this.onDisconnect.bind(this) + provider.on("disconnect", disconnect) + } + if (!sessionDelete) { + sessionDelete = this.onSessionDelete.bind(this) + provider.on("session_delete", sessionDelete) + } + + return {accounts, chainId: currentChainId} + } catch (error) { + if ( + /(user rejected|connection request reset)/i.test( + (error as ProviderRpcError)?.message + ) + ) { + throw new UserRejectedRequestError(error as Error) + } + throw error + } + }, + async disconnect() { + const provider = await this.getProvider() + try { + await provider?.disconnect() + } catch (error) { + if (!/No matching key/i.test((error as Error).message)) throw error + } finally { + if (chainChanged) { + provider?.removeListener("chainChanged", chainChanged) + chainChanged = undefined + } + if (disconnect) { + provider?.removeListener("disconnect", disconnect) + disconnect = undefined + } + if (!connect) { + connect = this.onConnect.bind(this) + provider?.on("connect", connect) + } + if (accountsChanged) { + provider?.removeListener("accountsChanged", accountsChanged) + accountsChanged = undefined + } + if (sessionDelete) { + provider?.removeListener("session_delete", sessionDelete) + sessionDelete = undefined + } + + this.setRequestedChainsIds([]) + } + }, + async getAccounts() { + const provider = await this.getProvider() + return provider.accounts.map(x => getAddress(x)) + }, + async getProvider({chainId} = {}) { + async function initProvider() { + const optionalChains = config.chains.map(x => x.id) as [number] + if (!optionalChains.length) return + return await EthereumProvider.init({ + ...parameters, + disableProviderPing: true, + optionalChains, + projectId: parameters.projectId, + rpcMap: Object.fromEntries( + config.chains.map(chain => { + const [url] = extractRpcUrls({ + chain, + transports: config.transports, + }) + return [chain.id, url] + }) + ), + showQrModal: parameters.showQrModal ?? true, + customStoragePrefix: "cross-vm-walletconnect", + }) + } + + if (!provider_) { + if (!providerPromise) providerPromise = initProvider() as any + provider_ = await providerPromise + provider_?.events.setMaxListeners(Number.POSITIVE_INFINITY) + } + if (chainId) await this.switchChain?.({chainId}) + return provider_! + }, + async getChainId() { + const provider = await this.getProvider() + return provider.chainId + }, + async isAuthorized() { + try { + const [accounts, provider] = await Promise.all([ + this.getAccounts(), + this.getProvider(), + ]) + + // If an account does not exist on the session, then the connector is unauthorized. + if (!accounts.length) return false + + // If the chains are stale on the session, then the connector is unauthorized. + const isChainsStale = await this.isChainsStale() + if (isChainsStale && provider.session) { + await provider.disconnect().catch(() => {}) + return false + } + return true + } catch { + return false + } + }, + async switchChain({addEthereumChainParameter, chainId}) { + const provider = await this.getProvider() + if (!provider) throw new ProviderNotFoundError() + + const chain = config.chains.find(x => x.id === chainId) + if (!chain) throw new SwitchChainError(new ChainNotConfiguredError()) + + try { + await Promise.all([ + new Promise(resolve => { + const listener = ({ + chainId: currentChainId, + }: { + chainId?: number | undefined + }) => { + if (currentChainId === chainId) { + config.emitter.off("change", listener) + resolve() + } + } + config.emitter.on("change", listener) + }), + provider.request({ + method: "wallet_switchEthereumChain", + params: [{chainId: numberToHex(chainId)}], + }), + ]) + + const requestedChains = await this.getRequestedChainsIds() + this.setRequestedChainsIds([...requestedChains, chainId]) + + return chain + } catch (err) { + const error = err as RpcError + + if (/(user rejected)/i.test(error.message)) + throw new UserRejectedRequestError(error) + + // Indicates chain is not added to provider + try { + let blockExplorerUrls: string[] | undefined + if (addEthereumChainParameter?.blockExplorerUrls) + blockExplorerUrls = addEthereumChainParameter.blockExplorerUrls + else + blockExplorerUrls = chain.blockExplorers?.default.url + ? [chain.blockExplorers?.default.url] + : [] + + let rpcUrls: readonly string[] + if (addEthereumChainParameter?.rpcUrls?.length) + rpcUrls = addEthereumChainParameter.rpcUrls + else rpcUrls = [...chain.rpcUrls.default.http] + + const addEthereumChain = { + blockExplorerUrls, + chainId: numberToHex(chainId), + chainName: addEthereumChainParameter?.chainName ?? chain.name, + iconUrls: addEthereumChainParameter?.iconUrls, + nativeCurrency: + addEthereumChainParameter?.nativeCurrency ?? chain.nativeCurrency, + rpcUrls, + } satisfies AddEthereumChainParameter + + await provider.request({ + method: "wallet_addEthereumChain", + params: [addEthereumChain], + }) + + const requestedChains = await this.getRequestedChainsIds() + this.setRequestedChainsIds([...requestedChains, chainId]) + return chain + } catch (error) { + throw new UserRejectedRequestError(error as Error) + } + } + }, + onAccountsChanged(accounts) { + if (accounts.length === 0) this.onDisconnect() + else + config.emitter.emit("change", { + accounts: accounts.map(x => getAddress(x)), + }) + }, + onChainChanged(chain) { + const chainId = Number(chain) + config.emitter.emit("change", {chainId}) + }, + async onConnect(connectInfo) { + const chainId = Number(connectInfo.chainId) + const accounts = await this.getAccounts() + config.emitter.emit("connect", {accounts, chainId}) + }, + async onDisconnect(_error) { + this.setRequestedChainsIds([]) + config.emitter.emit("disconnect") + + const provider = await this.getProvider() + if (accountsChanged) { + provider.removeListener("accountsChanged", accountsChanged) + accountsChanged = undefined + } + if (chainChanged) { + provider.removeListener("chainChanged", chainChanged) + chainChanged = undefined + } + if (disconnect) { + provider.removeListener("disconnect", disconnect) + disconnect = undefined + } + if (sessionDelete) { + provider.removeListener("session_delete", sessionDelete) + sessionDelete = undefined + } + if (!connect) { + connect = this.onConnect.bind(this) + provider.on("connect", connect) + } + }, + onDisplayUri(uri) { + config.emitter.emit("message", {type: "display_uri", data: uri}) + }, + onSessionDelete() { + this.onDisconnect() + }, + getNamespaceChainsIds() { + if (!provider_) return [] + const chainIds = provider_.session?.namespaces[NAMESPACE]?.accounts?.map( + account => Number.parseInt(account.split(":")[1] || "") + ) + return chainIds ?? [] + }, + async getRequestedChainsIds() { + return ( + (await config.storage?.getItem(this.requestedChainsStorageKey)) ?? [] + ) + }, + /** + * Checks if the target chains match the chains that were + * initially requested by the connector for the WalletConnect session. + * If there is a mismatch, this means that the chains on the connector + * are considered stale, and need to be revalidated at a later point (via + * connection). + * + * There may be a scenario where a dapp adds a chain to the + * connector later on, however, this chain will not have been approved or rejected + * by the wallet. In this case, the chain is considered stale. + */ + async isChainsStale() { + if (!isNewChainsStale) return false + + const connectorChains = config.chains.map(x => x.id) + const namespaceChains = this.getNamespaceChainsIds() + if ( + namespaceChains.length && + !namespaceChains.some(id => connectorChains.includes(id)) + ) + return false + + const requestedChains = await this.getRequestedChainsIds() + return !connectorChains.every(id => requestedChains.includes(id)) + }, + async setRequestedChainsIds(chains) { + await config.storage?.setItem(this.requestedChainsStorageKey, chains) + }, + get requestedChainsStorageKey() { + return `${this.id}.requestedChains` as Properties["requestedChainsStorageKey"] + }, + })) +} diff --git a/packages/fcl-wc/package.json b/packages/fcl-wc/package.json index e996e0ddb..d7768e53e 100644 --- a/packages/fcl-wc/package.json +++ b/packages/fcl-wc/package.json @@ -43,10 +43,12 @@ "@onflow/config": "1.5.1", "@onflow/util-invariant": "1.2.4", "@onflow/util-logger": "1.3.3", + "@walletconnect/ethereum-provider": "^2.18.0", "@walletconnect/modal": "^2.7.0", "@walletconnect/modal-core": "^2.6.2", "@walletconnect/sign-client": "^2.17.1", "@walletconnect/types": "^2.8.1", + "@walletconnect/universal-provider": "^2.18.0", "@walletconnect/utils": "^2.8.1", "postcss-cli": "^11.0.0", "preact": "^10.24.3", diff --git a/packages/fcl-wc/src/fcl-wc.ts b/packages/fcl-wc/src/fcl-wc.ts index 2a26ed65e..0c69e1634 100644 --- a/packages/fcl-wc/src/fcl-wc.ts +++ b/packages/fcl-wc/src/fcl-wc.ts @@ -1,10 +1,13 @@ import * as fclCore from "@onflow/fcl-core" -import SignClient from "@walletconnect/sign-client" import {invariant} from "@onflow/util-invariant" import {LEVELS, log} from "@onflow/util-logger" export {getSdkError} from "@walletconnect/utils" import {makeServicePlugin} from "./service" import {CoreTypes} from "@walletconnect/types" +import { + UniversalProvider, + UniversalProviderOpts, +} from "@walletconnect/universal-provider" export interface FclWalletConnectConfig { projectId: string @@ -18,7 +21,8 @@ export interface FclWalletConnectConfig { const DEFAULT_RELAY_URL = "wss://relay.walletconnect.com" const DEFAULT_LOGGER = "debug" -let clientPromise: Promise = Promise.resolve(null) +let providerPromise: Promise | null> = + Promise.resolve(null) const initClient = async ({ projectId, @@ -32,7 +36,7 @@ const initClient = async ({ "FCL Wallet Connect Error: WalletConnect projectId is required" ) try { - return SignClient.init({ + return UniversalProvider.init({ logger: DEFAULT_LOGGER, relayUrl: DEFAULT_RELAY_URL, projectId: projectId, @@ -50,19 +54,23 @@ const initClient = async ({ } } +const initUniversalProvider = async (opts: UniversalProviderOpts) => { + return UniversalProvider.init({}) +} + export const initLazy = (config: FclWalletConnectConfig) => { - const {FclWcServicePlugin, clientPromise} = initHelper(config) + const {FclWcServicePlugin, providerPromise} = initHelper(config) fclCore.discovery.authn.update() return { FclWcServicePlugin, - clientPromise, + providerPromise, } } export const init = async (config: FclWalletConnectConfig) => { - const {FclWcServicePlugin, clientPromise} = initLazy(config) - const client = await clientPromise + const {FclWcServicePlugin, providerPromise} = initLazy(config) + const client = await providerPromise fclCore.discovery.authn.update() return { @@ -82,7 +90,7 @@ const initHelper = (config: FclWalletConnectConfig) => { // - Initialize the client if it doesn't exist // - If it does exist, return existing client // - If existing client fails to initialize, reinitialize - clientPromise = Promise.resolve(clientPromise) + providerPromise = providerPromise .catch(() => null) .then(_client => { if (_client) { @@ -103,22 +111,22 @@ const initHelper = (config: FclWalletConnectConfig) => { throw e }) - const FclWcServicePlugin = makeServicePlugin(clientPromise, config) + const FclWcServicePlugin = makeServicePlugin(providerPromise, config) return { FclWcServicePlugin, - clientPromise, + providerPromise, } } // Returns the SignClient instance used by this plugin if it has been initialized -export async function getSignClient() { - return clientPromise.then(client => { - if (!client) { +export async function getProvider() { + return providerPromise.then(provider => { + if (!provider) { throw new Error("WalletConnect client not initialized") } - return client + return provider }) } diff --git a/packages/fcl-wc/src/index.ts b/packages/fcl-wc/src/index.ts index 5bf8e4d34..e5b6e5548 100644 --- a/packages/fcl-wc/src/index.ts +++ b/packages/fcl-wc/src/index.ts @@ -1,3 +1,3 @@ -export {init, initLazy, getSignClient} from "./fcl-wc" +export {init, initLazy, getProvider} from "./fcl-wc" export {createSessionProposal, request} from "./session" export {FLOW_METHODS, SERVICE_PLUGIN_NAME, WC_SERVICE_METHOD} from "./constants" diff --git a/packages/fcl-wc/src/service.ts b/packages/fcl-wc/src/service.ts index 3783e46f5..bd17777f1 100644 --- a/packages/fcl-wc/src/service.ts +++ b/packages/fcl-wc/src/service.ts @@ -2,25 +2,31 @@ import {invariant} from "@onflow/util-invariant" import {log, LEVELS} from "@onflow/util-logger" import {isMobile, openDeeplink, preloadImage, shouldDeepLink} from "./utils" import { + FLOW_METHODS, REQUEST_TYPES, SERVICE_PLUGIN_NAME, WC_SERVICE_METHOD, } from "./constants" -import {SignClient} from "@walletconnect/sign-client/dist/types/client" import {createSessionProposal, request} from "./session" -import {ModalCtrlState} from "@walletconnect/modal-core/dist/_types/src/types/controllerTypes" import {showNotification} from "./ui/notifications" import type {FclWalletConnectConfig} from "./fcl-wc" import mobileIcon from "./ui/assets/mobile.svg" import {CurrentUser, Service} from "@onflow/typedefs" import {SessionTypes} from "@walletconnect/types" +import {UniversalProvider} from "@walletconnect/universal-provider" +import {createStore} from "./store" +import {ModalCtrlState} from "@walletconnect/modal-core/dist/_types/src/types/controllerTypes" type WalletConnectModalType = import("@walletconnect/modal").WalletConnectModal type Constructor = new (...args: any[]) => T +let providerStore = createStore<{ + [key: string]: InstanceType +}>({}) + export const makeServicePlugin = ( - client: Promise, + provider: Promise | null>, config: FclWalletConnectConfig = { projectId: "", includeBaseWC: false, @@ -36,7 +42,7 @@ export const makeServicePlugin = ( serviceStrategy: { method: WC_SERVICE_METHOD, exec: makeExec( - client, + provider, config, import("@walletconnect/modal").then(m => m.WalletConnectModal) ), @@ -45,7 +51,7 @@ export const makeServicePlugin = ( }) const makeExec = ( - clientPromise: Promise, + signerPromise: Promise | null>, config: FclWalletConnectConfig, WalletConnectModal: Promise> ) => { @@ -71,22 +77,25 @@ const makeExec = ( disableNotifications: appDisabledNotifications, } = config - const client = await clientPromise - invariant(!!client, "WalletConnect is not initialized") + const resolvedProvider = await resolveProvider({ + provider: signerPromise, + externalProviderOrTopic: service.params?.externalProvider, + }) + invariant(!!resolvedProvider, "WalletConnect is not initialized") + + const {provider: provider, isExternal} = resolvedProvider - let session: SessionTypes.Struct | null = null, + let session: SessionTypes.Struct | null = provider.session ?? null, pairing: any const method = service.endpoint const appLink = validateAppLink(service) - const pairings = client.pairing.getAll({active: true}) - if (pairings.length > 0) { - pairing = pairings?.find(p => p.peerMetadata?.url === service.uid) - } - - if (client.session.length > 0) { - const lastKeyIndex = client.session.keys.length - 1 - session = client.session.get(client.session.keys.at(lastKeyIndex)!) + // If the user is already connected to this session, use it + if ( + session?.topic === service.params?.externalProvider && + method === FLOW_METHODS.FLOW_AUTHN + ) { + return user } if (session == null) { @@ -99,7 +108,7 @@ const makeExec = ( service, onClose, appLink, - client, + provider, method, pairing, wcRequestHook, @@ -143,8 +152,9 @@ const makeExec = ( method, body, session, - client, + provider, abortSignal, + isExternal, }).finally(() => notification?.dismiss()) function validateAppLink({uid}: {uid: string}) { @@ -168,7 +178,7 @@ function connectWc( service, onClose, appLink, - client, + provider, method, pairing, wcRequestHook, @@ -178,14 +188,14 @@ function connectWc( service: any onClose: any appLink: string - client: SignClient + provider: InstanceType method: string pairing: any wcRequestHook: any pairingModalOverride: any abortSignal?: AbortSignal }): Promise => { - const projectId = client.opts?.projectId + const projectId = provider.providerOpts.projectId invariant( !!projectId, "Cannot establish connection, WalletConnect projectId is undefined" @@ -196,10 +206,9 @@ function connectWc( try { const {uri, approval} = await createSessionProposal({ - client, + provider, existingPairing: pairing, }) - _uri = uri if (wcRequestHook && wcRequestHook instanceof Function) { wcRequestHook({ @@ -253,6 +262,11 @@ function connectWc( }) }), ]) + + if (session == null) { + throw new Error("Session request failed") + } + return session } catch (error) { if (error instanceof Error) { @@ -268,7 +282,7 @@ function connectWc( onClose() throw error } finally { - walletConnectModal?.closeModal() + // walletConnectModal?.closeModal() } } } @@ -300,3 +314,70 @@ export function showWcRequestNotification({ debounceDelay: service.type === "pre-authz" ? 500 : 0, }) } + +async function resolveProvider({ + provider, + externalProviderOrTopic, +}: { + provider: Promise | null> + externalProviderOrTopic?: string | InstanceType +}): Promise<{ + provider: InstanceType + isExternal: boolean +} | null> { + if (!externalProviderOrTopic) { + const resolved = await provider + return resolved ? {provider: resolved, isExternal: false} : null + } + + // If it's a UniversalProvider instance, use it directly and store it. + if (typeof externalProviderOrTopic !== "string") { + const topic = externalProviderOrTopic.session?.topic + if (!topic) { + throw new Error( + "Cannot resolve provider: UniversalProvider is not initialized" + ) + } + providerStore.setState({ + [topic]: externalProviderOrTopic, + }) + return {provider: externalProviderOrTopic, isExternal: true} + } + + const externalTopic = externalProviderOrTopic + if (externalTopic) { + // Check if an external provider was passed in the options. + let storedProvider = providerStore.getState()[externalTopic] + if (!storedProvider) { + // No provider from opts and nothing in store yet—wait for it. + let unsubStore: () => void + let timeout: NodeJS.Timeout + + storedProvider = await new Promise((resolve, reject) => { + unsubStore = providerStore.subscribe(() => { + const provider = providerStore.getState()[externalTopic] + if (provider) { + resolve(provider) + } + }) + + // If the provider is not defined after 5 seconds, reject the promise. + timeout = setTimeout(() => { + reject( + new Error( + `Provider for external topic ${externalTopic} not found after 5 seconds` + ) + ) + }, 5000) + }).finally(() => { + clearTimeout(timeout) + unsubStore() + }) + } + + return {provider: storedProvider, isExternal: true} + } + + const resolved = await provider + return resolved ? {provider: resolved, isExternal: false} : null +} diff --git a/packages/fcl-wc/src/session.ts b/packages/fcl-wc/src/session.ts index 06efd2195..07673ca6b 100644 --- a/packages/fcl-wc/src/session.ts +++ b/packages/fcl-wc/src/session.ts @@ -1,14 +1,15 @@ import * as fclCore from "@onflow/fcl-core" import {FLOW_METHODS} from "./constants" -import {SignClient} from "@walletconnect/sign-client/dist/types/client" import {PairingTypes, SessionTypes} from "@walletconnect/types" +import {UniversalProvider} from "@walletconnect/universal-provider" +import {Service} from "@onflow/typedefs" // Create a new session proposal with the WalletConnect client export async function createSessionProposal({ - client, + provider, existingPairing, }: { - client: SignClient + provider: InstanceType existingPairing?: PairingTypes.Struct }) { const network = await fclCore.getChainId() @@ -26,44 +27,59 @@ export async function createSessionProposal({ }, } - const {uri, approval} = await client.connect({ - pairingTopic: existingPairing?.topic, - requiredNamespaces, + let cleanup: () => void + const uri = new Promise((resolve, reject) => { + const onDisplayUri = (uri: string) => { + resolve(uri) + } + provider.on("display_uri", onDisplayUri) + cleanup = () => { + provider.removeListener("display_uri", onDisplayUri) + reject(new Error("WalletConnect Session Request aborted")) + } }) - if (!uri) { - throw new Error( - "FCL-WC: Error creating session proposal. Could not create a proposal URI." - ) - } + const session = await provider + .connect({ + pairingTopic: existingPairing?.topic, + namespaces: requiredNamespaces, + }) + .finally(() => { + cleanup() + }) - return {uri, approval} + return { + uri: await uri, + approval: () => session, + } } export const request = async ({ method, body, session, - client, + provider, + isExternal, abortSignal, }: { method: any body: any session: SessionTypes.Struct - client: SignClient + provider: InstanceType + isExternal?: boolean abortSignal?: AbortSignal }) => { const [chainId, addr, address] = makeSessionData(session) const data = JSON.stringify({...body, addr, address}) const result: any = await Promise.race([ - client.request({ - topic: session.topic, - chainId, + provider.client.request({ request: { method, params: [data], }, + chainId, + topic: provider.session?.topic!, }), new Promise((_, reject) => { if (abortSignal?.aborted) { @@ -79,6 +95,39 @@ export const request = async ({ switch (result.status) { case "APPROVED": + function normalizeService(service: Service) { + if (service.method === "WC/RPC") { + return { + ...service, + params: { + ...service.params, + ...(isExternal ? {externalProvider: session.topic} : {}), + }, + } + } + return service + } + + if (method === FLOW_METHODS.FLOW_AUTHN) { + const services = (result?.data?.services ?? []).map(normalizeService) + + return { + ...(result.data ? result.data : {}), + services, + } + } + + if (method === FLOW_METHODS.FLOW_PRE_AUTHZ) { + return { + ...result.data, + ...(result.data?.proposer + ? {proposer: normalizeService(result.data.proposer)} + : {}), + payer: [...result.data?.payer?.map(normalizeService)], + authorization: [...result.data?.authorization?.map(normalizeService)], + } + } + return result.data case "DECLINED": diff --git a/packages/fcl-wc/src/store.ts b/packages/fcl-wc/src/store.ts new file mode 100644 index 000000000..9d81a813a --- /dev/null +++ b/packages/fcl-wc/src/store.ts @@ -0,0 +1,24 @@ +export function createStore(initialState: T) { + const subscribers = new Set<(state: T) => void>() + let state = initialState + + const subscribe = (subscriber: (state: T) => void) => { + subscribers.add(subscriber) + return () => { + subscribers.delete(subscriber) + } + } + + const setState = (newState: T) => { + state = newState + subscribers.forEach(subscriber => subscriber(state)) + } + + const getState = () => state + + return { + subscribe, + setState, + getState, + } +} diff --git a/packages/fcl/src/discovery/rpc/handlers/request-wc-qr.ts b/packages/fcl/src/discovery/rpc/handlers/request-wc-qr.ts index 4af8dc74a..5e97f119d 100644 --- a/packages/fcl/src/discovery/rpc/handlers/request-wc-qr.ts +++ b/packages/fcl/src/discovery/rpc/handlers/request-wc-qr.ts @@ -1,7 +1,7 @@ import { createSessionProposal, FLOW_METHODS, - getSignClient, + getProvider, request as wcRequest, } from "@onflow/fcl-wc" import {DiscoveryNotification, DiscoveryRpc} from "../requests" @@ -28,11 +28,11 @@ export const wcRequestHandlerFactory = ({ throw new Error("Handler has been terminated") } - const client = await getSignClient() + const provider = await getProvider() // Execute WC bypass if session is approved const {uri, approval} = await createSessionProposal({ - client, + provider, }) // Watch for QR code connection asynchronously @@ -65,7 +65,7 @@ export function watchQrFactory({ // Watch for QR code connection & resolve callback if connected setTimeout(async () => { try { - const client = await getSignClient() + const provider = await getProvider() const session = await approval() rpc.notify(DiscoveryNotification.NOTIFY_QRCODE_CONNECTING, { uri, @@ -75,7 +75,7 @@ export function watchQrFactory({ method: FLOW_METHODS.FLOW_AUTHN, body: authnBody, session, - client, + provider, }) rpc.notify(DiscoveryNotification.NOTIFY_QRCODE_CONNECTED, { diff --git a/packages/fcl/src/utils/walletconnect/loader.ts b/packages/fcl/src/utils/walletconnect/loader.ts index e48bd9e8a..2234c1ac0 100644 --- a/packages/fcl/src/utils/walletconnect/loader.ts +++ b/packages/fcl/src/utils/walletconnect/loader.ts @@ -99,11 +99,12 @@ ${lastConfig}` // We must lazy load the plugin to avoid race conditions // where the developer attempts to use the plugin before // our loader applies the configuration - const {clientPromise: _clientPromise, FclWcServicePlugin} = fclWc.initLazy({ - projectId, - metadata: getMetadata(wcConfig), - disableNotifications: disableNotifications, - }) + const {providerPromise: _clientPromise, FclWcServicePlugin} = + fclWc.initLazy({ + projectId, + metadata: getMetadata(wcConfig), + disableNotifications: disableNotifications, + }) pluginRegistry.add([FclWcServicePlugin]) }) }