chore: delete stale react-wallet-chat sample
No files matched your search
@@ -1,3 +0,0 @@
|
||||
NEXT_PUBLIC_PROJECT_ID=...
|
||||
NEXT_PUBLIC_RELAY_URL=wss://relay.walletconnect.com
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"extends": "next/core-web-vitals",
|
||||
"ignorePatterns": ["next.config.js"]
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
.DS_Store
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"arrowParens": "avoid",
|
||||
"parser": "typescript",
|
||||
"printWidth": 100,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "none",
|
||||
"semi": false
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
# Chat Wallet Example (React, Typescript, Ethers, NextJS)
|
||||
|
||||
This example aims to demonstrate use cases enabled by the WalletConnect Chat Alpha. Please only use this for reference and development purposes, otherwise you are at risk of losing your funds.
|
||||
|
||||
# Useful links
|
||||
|
||||
🔗 Chat Wallet Deployment - https://react-wallet-chat.walletconnect.com/ <br />
|
||||
🔗 Chat Wallet Peer Deployment - https://react-wallet-chat-peer.walletconnect.com/ <br />
|
||||
📚 WalletConnect docs - https://docs.walletconnect.com/2.0
|
||||
|
||||
## Getting started
|
||||
|
||||
The example is built atop of [NextJS](https://nextjs.org/) in order to abstract complexity of setting up bundlers, routing etc. So there are few steps you need to follow in order to set everything up
|
||||
|
||||
1. Go to [WalletConnect Cloud](https://cloud.walletconnect.com/sign-in) and obtain a project id
|
||||
|
||||
2. Install dependencies via `yarn`
|
||||
|
||||
3. Setup your environment variables
|
||||
|
||||
```bash
|
||||
cp .env.local.example .env.local
|
||||
```
|
||||
|
||||
Your `.env.local` now contains the following environment variables:
|
||||
|
||||
- `NEXT_PUBLIC_PROJECT_ID` (placeholder) - You can generate your own ProjectId at https://cloud.walletconnect.com
|
||||
- `NEXT_PUBLIC_RELAY_URL` (already set)
|
||||
|
||||
5. Run `yarn dev` to start local development
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
reactStrictMode: true
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
{
|
||||
"name": "react-wallet-v2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev -p 3001",
|
||||
"dev:peer": "NEXT_PUBLIC_CHAT_ENV=peer next dev -p 3002",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cosmjs/amino": "0.32.0",
|
||||
"@cosmjs/encoding": "0.32.0",
|
||||
"@cosmjs/proto-signing": "0.32.0",
|
||||
"@json-rpc-tools/utils": "1.7.6",
|
||||
"@nextui-org/react": "1.0.8-beta.5",
|
||||
"@solana/web3.js": "1.78.4",
|
||||
"@walletconnect/chat-client": "^0.8.0",
|
||||
"@walletconnect/core": "2.10.0",
|
||||
"@walletconnect/logger": "^2.0.1",
|
||||
"@walletconnect/sign-client": "2.10.0",
|
||||
"@walletconnect/sync-client": "^0.3.4",
|
||||
"@walletconnect/utils": "^2.7.7",
|
||||
"@web3modal/core": "^2.0.0-beta.7",
|
||||
"@web3modal/standalone": "^2.0.0-beta.7",
|
||||
"@web3modal/ui": "^2.0.0-beta.7",
|
||||
"bs58": "5.0.0",
|
||||
"cosmos-wallet": "1.2.0",
|
||||
"ethers": "5.7.2",
|
||||
"framer-motion": "6.5.1",
|
||||
"mnemonic-keyring": "1.4.0",
|
||||
"next": "12.1.5",
|
||||
"react": "17.0.2",
|
||||
"react-code-blocks": "0.0.9-0",
|
||||
"react-dom": "17.0.2",
|
||||
"react-icons": "^4.4.0",
|
||||
"react-qr-reader-es6": "2.2.1-2",
|
||||
"solana-wallet": "1.0.2",
|
||||
"valtio": "1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "17.0.35",
|
||||
"@types/react": "18.0.9",
|
||||
"@walletconnect/types": "2.9.1",
|
||||
"eslint": "8.15.0",
|
||||
"eslint-config-next": "12.1.6",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
"prettier": "2.6.2",
|
||||
"typescript": "4.6.4"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 25 KiB |
@@ -1,24 +0,0 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M160 368H448M160 144H448H160ZM160 256H448H160Z" stroke="url(#paint0_linear_46_13)" stroke-width="48" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M80 160C88.8366 160 96 152.837 96 144C96 135.163 88.8366 128 80 128C71.1634 128 64 135.163 64 144C64 152.837 71.1634 160 80 160Z" stroke="url(#paint1_linear_46_13)" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M80 272C88.8366 272 96 264.837 96 256C96 247.163 88.8366 240 80 240C71.1634 240 64 247.163 64 256C64 264.837 71.1634 272 80 272Z" stroke="url(#paint2_linear_46_13)" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M80 384C88.8366 384 96 376.837 96 368C96 359.163 88.8366 352 80 352C71.1634 352 64 359.163 64 368C64 376.837 71.1634 384 80 384Z" stroke="url(#paint3_linear_46_13)" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_46_13" x1="160" y1="144.018" x2="380.191" y2="421.745" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#A562D5"/>
|
||||
<stop offset="1" stop-color="#306FEB"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_46_13" x1="64" y1="128.003" x2="96.3014" y2="159.69" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#A562D5"/>
|
||||
<stop offset="1" stop-color="#306FEB"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_46_13" x1="64" y1="240.003" x2="96.3014" y2="271.69" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#A562D5"/>
|
||||
<stop offset="1" stop-color="#306FEB"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint3_linear_46_13" x1="64" y1="352.003" x2="96.3014" y2="383.69" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#A562D5"/>
|
||||
<stop offset="1" stop-color="#306FEB"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M112 184L256 328L400 184" stroke="white" stroke-width="48" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 224 B |
@@ -1,3 +0,0 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M184 112L328 256L184 400" stroke="white" stroke-width="48" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 224 B |
@@ -1,16 +0,0 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M431 320.6C430 317 432.2 312 434.3 308.4C434.942 307.329 435.643 306.294 436.4 305.3C454.363 278.608 463.971 247.173 464 215C464.3 122.8 386.5 48 290.3 48C206.4 48 136.4 105.1 120 180.9C117.547 192.135 116.306 203.6 116.3 215.1C116.3 307.4 191.1 384.2 287.3 384.2C302.6 384.2 323.2 379.6 334.5 376.5C345.8 373.4 357 369.3 359.9 368.2C362.873 367.079 366.023 366.503 369.2 366.5C372.666 366.487 376.1 367.167 379.3 368.5L436 388.6C437.243 389.126 438.557 389.463 439.9 389.6C442.022 389.6 444.057 388.757 445.557 387.257C447.057 385.757 447.9 383.722 447.9 381.6C447.83 380.685 447.663 379.78 447.4 378.9L431 320.6Z" stroke="url(#paint0_linear_0_1)" stroke-width="32" stroke-miterlimit="10" stroke-linecap="round"/>
|
||||
<path d="M66.46 232C53.3443 255.562 46.9996 282.293 48.1273 309.236C49.255 336.179 57.8112 362.286 72.85 384.67C75.16 388.16 76.46 390.86 76.06 392.67C75.66 394.48 64.13 454.54 64.13 454.54C63.8527 455.946 63.9579 457.4 64.4346 458.751C64.9113 460.102 65.742 461.3 66.84 462.22C68.3051 463.387 70.1268 464.016 72 464C73.001 464.003 73.9917 463.798 74.91 463.4L131.12 441.4C134.989 439.875 139.304 439.947 143.12 441.6C162.06 448.98 183 453.6 203.95 453.6C232.063 453.63 259.682 446.215 284 432.11" stroke="url(#paint1_linear_0_1)" stroke-width="32" stroke-miterlimit="10" stroke-linecap="round"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_0_1" x1="290.15" y1="48" x2="290.15" y2="389.6" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#A562D5"/>
|
||||
<stop offset="0.0001" stop-color="#A562D5"/>
|
||||
<stop offset="1" stop-color="#306FEB"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_0_1" x1="166" y1="232" x2="166" y2="464" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#A562D5"/>
|
||||
<stop offset="0.0001" stop-color="#A562D5"/>
|
||||
<stop offset="1" stop-color="#306FEB"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.9 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M416 128L192 384L96 288" stroke="white" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 223 B |
@@ -1,4 +0,0 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M336 64H368C380.73 64 392.939 69.0571 401.941 78.0589C410.943 87.0606 416 99.2696 416 112V432C416 444.73 410.943 456.939 401.941 465.941C392.939 474.943 380.73 480 368 480H144C131.27 480 119.061 474.943 110.059 465.941C101.057 456.939 96 444.73 96 432V112C96 99.2696 101.057 87.0606 110.059 78.0589C119.061 69.0571 131.27 64 144 64H176" stroke="white" stroke-width="32" stroke-linejoin="round"/>
|
||||
<path d="M309.87 32H202.13C187.699 32 176 43.6988 176 58.13V69.87C176 84.3012 187.699 96 202.13 96H309.87C324.301 96 336 84.3012 336 69.87V58.13C336 43.6988 324.301 32 309.87 32Z" stroke="white" stroke-width="32" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 751 B |
@@ -1,6 +0,0 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M112 112L132 432C132.95 450.49 146.4 464 164 464H348C365.67 464 378.87 450.49 380 432L400 112" stroke="#F21361" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M80 112H432Z" fill="#F21361"/>
|
||||
<path d="M80 112H432" stroke="#F21361" stroke-width="32" stroke-miterlimit="10" stroke-linecap="round"/>
|
||||
<path d="M328 176L320 400M192 112V72.0001C191.991 68.8458 192.605 65.7208 193.808 62.8048C195.011 59.8888 196.778 57.2394 199.009 55.0089C201.239 52.7785 203.889 51.011 206.805 49.8082C209.721 48.6053 212.846 47.9909 216 48.0001H296C299.154 47.9909 302.279 48.6053 305.195 49.8082C308.111 51.011 310.761 52.7785 312.991 55.0089C315.222 57.2394 316.989 59.8888 318.192 62.8048C319.395 65.7208 320.009 68.8458 320 72.0001V112H192ZM256 176V400V176ZM184 176L192 400L184 176Z" stroke="#F21361" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 996 B |
@@ -1,9 +0,0 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M208 352H144C118.539 352 94.1212 341.886 76.1178 323.882C58.1143 305.879 48 281.461 48 256C48 230.539 58.1143 206.121 76.1178 188.118C94.1212 170.114 118.539 160 144 160H208M304 160H368C393.461 160 417.879 170.114 435.882 188.118C453.886 206.121 464 230.539 464 256C464 281.461 453.886 305.879 435.882 323.882C417.879 341.886 393.461 352 368 352H304M163.29 256H350.71" stroke="url(#paint0_linear_112_7)" stroke-width="36" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_112_7" x1="48.0001" y1="160.015" x2="197.341" y2="477.442" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#A562D5"/>
|
||||
<stop offset="1" stop-color="#306FEB"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 814 B |
@@ -1,13 +0,0 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M408 336H344C339.582 336 336 339.582 336 344V408C336 412.418 339.582 416 344 416H408C412.418 416 416 412.418 416 408V344C416 339.582 412.418 336 408 336Z" fill="#8B8B8B"/>
|
||||
<path d="M328 272H280C275.582 272 272 275.582 272 280V328C272 332.418 275.582 336 280 336H328C332.418 336 336 332.418 336 328V280C336 275.582 332.418 272 328 272Z" fill="#8B8B8B"/>
|
||||
<path d="M472 416H424C419.582 416 416 419.582 416 424V472C416 476.418 419.582 480 424 480H472C476.418 480 480 476.418 480 472V424C480 419.582 476.418 416 472 416Z" fill="#8B8B8B"/>
|
||||
<path d="M472 272H440C435.582 272 432 275.582 432 280V312C432 316.418 435.582 320 440 320H472C476.418 320 480 316.418 480 312V280C480 275.582 476.418 272 472 272Z" fill="#8B8B8B"/>
|
||||
<path d="M312 432H280C275.582 432 272 435.582 272 440V472C272 476.418 275.582 480 280 480H312C316.418 480 320 476.418 320 472V440C320 435.582 316.418 432 312 432Z" fill="#8B8B8B"/>
|
||||
<path d="M408 96H344C339.582 96 336 99.5817 336 104V168C336 172.418 339.582 176 344 176H408C412.418 176 416 172.418 416 168V104C416 99.5817 412.418 96 408 96Z" fill="#8B8B8B"/>
|
||||
<path d="M448 48H304C295.163 48 288 55.1634 288 64V208C288 216.837 295.163 224 304 224H448C456.837 224 464 216.837 464 208V64C464 55.1634 456.837 48 448 48Z" stroke="#8B8B8B" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M168 96H104C99.5817 96 96 99.5817 96 104V168C96 172.418 99.5817 176 104 176H168C172.418 176 176 172.418 176 168V104C176 99.5817 172.418 96 168 96Z" fill="#8B8B8B"/>
|
||||
<path d="M208 48H64C55.1634 48 48 55.1634 48 64V208C48 216.837 55.1634 224 64 224H208C216.837 224 224 216.837 224 208V64C224 55.1634 216.837 48 208 48Z" stroke="#8B8B8B" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M168 336H104C99.5817 336 96 339.582 96 344V408C96 412.418 99.5817 416 104 416H168C172.418 416 176 412.418 176 408V344C176 339.582 172.418 336 168 336Z" fill="#8B8B8B"/>
|
||||
<path d="M208 288H64C55.1634 288 48 295.163 48 304V448C48 456.837 55.1634 464 64 464H208C216.837 464 224 456.837 224 448V304C224 295.163 216.837 288 208 288Z" stroke="#8B8B8B" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.2 KiB |
@@ -1,19 +0,0 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M320 120L368 168L320 216" stroke="url(#paint0_linear_101_17)" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M352 168H144C122.802 168.063 102.491 176.512 87.5014 191.501C72.5122 206.491 64.0633 226.802 64 248V264M192 392L144 344L192 296" stroke="url(#paint1_linear_101_17)" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M160 344H368C389.198 343.937 409.509 335.488 424.499 320.499C439.488 305.509 447.937 285.198 448 264V248" stroke="url(#paint2_linear_101_17)" stroke-width="32" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_101_17" x1="320" y1="120.008" x2="396.642" y2="157.601" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#A562D5"/>
|
||||
<stop offset="1" stop-color="#306FEB"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_101_17" x1="64.0001" y1="168.018" x2="284.191" y2="445.745" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#A562D5"/>
|
||||
<stop offset="1" stop-color="#306FEB"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_101_17" x1="160" y1="248.008" x2="219.048" y2="421.788" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#A562D5"/>
|
||||
<stop offset="1" stop-color="#306FEB"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -1,9 +0,0 @@
|
||||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M464 249.93C463.865 247.435 462.851 245.067 461.138 243.248C459.425 241.429 457.123 240.275 454.64 239.99L429 235.84C427.847 235.651 426.785 235.094 425.975 234.252C425.164 233.411 424.646 232.33 424.5 231.17C424.01 228.02 423.5 224.75 422.8 221.65C422.574 220.522 422.707 219.353 423.178 218.304C423.65 217.255 424.437 216.38 425.43 215.8L448.21 203.15C450.472 201.997 452.231 200.053 453.153 197.687C454.075 195.322 454.095 192.7 453.21 190.32L449.26 179.42C448.394 177.032 446.677 175.048 444.439 173.847C442.201 172.646 439.599 172.312 437.13 172.91L411.58 177.91C410.438 178.114 409.26 177.952 408.215 177.448C407.17 176.943 406.311 176.122 405.76 175.1C404.27 172.31 402.65 169.47 400.96 166.68C400.346 165.686 400.059 164.525 400.138 163.359C400.216 162.194 400.658 161.082 401.4 160.18L418.4 140.54C420.127 138.686 421.119 136.266 421.191 133.734C421.263 131.201 420.409 128.729 418.79 126.78L411.37 117.87C409.756 115.914 407.473 114.627 404.965 114.258C402.456 113.888 399.9 114.463 397.79 115.87L375.42 129.3C374.428 129.894 373.272 130.154 372.121 130.04C370.97 129.927 369.887 129.446 369.03 128.67C366.56 126.5 364.03 124.41 361.66 122.48C360.75 121.762 360.093 120.773 359.784 119.656C359.475 118.54 359.529 117.354 359.94 116.27L369.2 91.87C370.209 89.5419 370.327 86.9244 369.532 84.5149C368.738 82.1053 367.086 80.0716 364.89 78.8L354.8 72.91C352.603 71.6431 350.016 71.2313 347.534 71.7535C345.052 72.2757 342.85 73.6951 341.35 75.74L325 96.28C324.412 97.1728 323.531 97.8328 322.509 98.1467C321.487 98.4606 320.388 98.4087 319.4 98C318.79 97.75 313.63 95.64 309.62 94.3C308.52 93.9415 307.564 93.2405 306.891 92.2995C306.218 91.3584 305.864 90.2268 305.88 89.07L306.27 63C306.409 60.4544 305.616 57.9453 304.038 55.9426C302.461 53.9398 300.207 52.5808 297.7 52.12L286.25 50.12C283.755 49.689 281.189 50.1784 279.028 51.4971C276.867 52.8159 275.258 54.8743 274.5 57.29L266 82.1C265.614 83.2014 264.885 84.15 263.921 84.8069C262.956 85.4638 261.806 85.7943 260.64 85.75H250.89C249.733 85.7738 248.598 85.4318 247.646 84.7729C246.694 84.114 245.975 83.1716 245.59 82.08L237.13 57.41C236.386 54.9767 234.78 52.8981 232.613 51.5636C230.447 50.229 227.868 49.73 225.36 50.16L213.89 52.16C211.399 52.6172 209.158 53.9629 207.584 55.9473C206.009 57.9317 205.209 60.4199 205.33 62.95L205.73 89.11C205.738 90.2841 205.367 91.4294 204.671 92.3754C203.976 93.3214 202.993 94.0175 201.87 94.36C199.58 95.25 194.61 97.15 192.35 97.99C190.35 98.71 188.17 97.92 186.41 95.89L170.15 75.89C168.658 73.8327 166.458 72.3994 163.974 71.866C161.489 71.3325 158.895 71.7364 156.69 73L146.63 78.83C144.41 80.104 142.741 82.1544 141.943 84.5862C141.146 87.0179 141.276 89.6589 142.31 92L151.56 116.34C151.964 117.426 152.017 118.611 151.712 119.728C151.407 120.846 150.759 121.84 149.86 122.57C147.43 124.57 144.94 126.57 142.46 128.79C141.608 129.56 140.533 130.038 139.39 130.153C138.248 130.268 137.098 130.015 136.11 129.43L114 115.74C111.877 114.359 109.323 113.8 106.817 114.168C104.311 114.537 102.026 115.807 100.39 117.74L93 126.63C91.3585 128.566 90.4886 131.039 90.5569 133.576C90.6252 136.113 91.6268 138.535 93.3701 140.38L110.45 160C111.208 160.884 111.661 161.989 111.742 163.151C111.823 164.312 111.528 165.469 110.9 166.45C109.19 169.17 107.56 172.03 106.08 174.89C105.526 175.919 104.661 176.746 103.608 177.252C102.556 177.759 101.369 177.919 100.22 177.71L74.71 172.78C72.2401 172.184 69.6373 172.518 67.3981 173.719C65.159 174.92 63.4403 176.903 62.57 179.29L58.57 190.17C57.6859 192.553 57.7066 195.177 58.6281 197.545C59.5497 199.914 61.3081 201.862 63.57 203.02L86.35 215.67C87.3745 216.235 88.1871 217.119 88.6652 218.187C89.1432 219.255 89.2608 220.449 89 221.59L88.7601 222.86C88.2401 225.65 87.7601 228.29 87.3001 231.1C87.141 232.245 86.624 233.31 85.823 234.144C85.0219 234.977 83.9778 235.536 82.84 235.74L57.1501 239.89C54.6377 240.198 52.3235 241.411 50.6397 243.301C48.9559 245.191 48.0176 247.629 48 250.16V261.74C47.9854 264.281 48.9141 266.737 50.6063 268.632C52.2985 270.528 54.6338 271.728 57.16 272L82.84 276.14C83.994 276.328 85.0561 276.884 85.8674 277.726C86.6786 278.568 87.1953 279.65 87.34 280.81C87.83 283.97 88.3401 287.23 89.0401 290.33C89.2656 291.458 89.1334 292.627 88.6619 293.676C88.1904 294.725 87.4031 295.6 86.4101 296.18L63.64 308.85C61.3781 310.003 59.6188 311.947 58.6969 314.313C57.775 316.678 57.7548 319.3 58.64 321.68L62.64 332.58C63.5083 334.966 65.2251 336.949 67.4626 338.15C69.7001 339.351 72.3015 339.686 74.77 339.09L100.32 334.14C101.463 333.933 102.642 334.093 103.687 334.598C104.733 335.103 105.592 335.926 106.14 336.95C107.64 339.75 109.25 342.58 110.94 345.37C111.557 346.363 111.846 347.525 111.767 348.691C111.688 349.857 111.245 350.969 110.5 351.87L93.5 371.5C91.7529 373.34 90.7378 375.755 90.6458 378.29C90.5537 380.826 91.3909 383.308 93 385.27L100.41 394.18C102.023 396.138 104.305 397.426 106.815 397.796C109.324 398.165 111.881 397.589 113.99 396.18L136.36 382.75C137.352 382.156 138.508 381.896 139.659 382.Line truncated
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_46_10" x1="48" y1="50" x2="464" y2="462" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#A562D5"/>
|
||||
<stop offset="1" stop-color="#306FEB"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 9.8 KiB |
@@ -1,86 +0,0 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.routeTransition {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
height: calc(100% - 220px);
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.qrVideoMask {
|
||||
width: 100%;
|
||||
border-radius: 15px;
|
||||
overflow: hidden !important;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.qrPlaceholder {
|
||||
border: 2px rgba(139, 139, 139, 0.4) dashed;
|
||||
width: 100%;
|
||||
border-radius: 15px;
|
||||
padding: 50px;
|
||||
}
|
||||
|
||||
.qrIcon {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.codeBlock code {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.codeBlock span {
|
||||
background-color: transparent !important;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.navLink {
|
||||
transition: ease-in-out .2s opacity;
|
||||
}
|
||||
|
||||
.navLink:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
select {
|
||||
background-color: rgba(139, 139, 139, 0.2);
|
||||
background-image: url(/icons/arrow-down-icon.svg);
|
||||
background-size: 15px 15px;
|
||||
background-position: right 10px center;
|
||||
background-repeat: no-repeat;
|
||||
padding: 5px 30px 6px 10px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
appearance: none;
|
||||
transition: .2s ease-in-out background-color;
|
||||
font-family: var(--nextui-fonts-sans);
|
||||
font-weight: var(--nextui-fontWeights-light);
|
||||
border: 1px solid rgba(139, 139, 139, 0.25);
|
||||
}
|
||||
|
||||
select:hover {
|
||||
background-color: rgba(139, 139, 139, 0.35);
|
||||
}
|
||||
|
||||
i {
|
||||
margin-top: -5px !important;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="388" height="238" viewBox="0 0 388 238" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M79.4993 46.539C142.716 -15.355 245.209 -15.355 308.426 46.539L316.034 53.988C319.195 57.0827 319.195 62.1002 316.034 65.1949L290.008 90.6766C288.427 92.2239 285.865 92.2239 284.285 90.6766L273.815 80.4258C229.714 37.247 158.211 37.247 114.11 80.4258L102.898 91.4035C101.317 92.9509 98.7551 92.9509 97.1747 91.4035L71.1486 65.9219C67.9878 62.8272 67.9878 57.8096 71.1486 54.715L79.4993 46.539ZM362.25 99.2378L385.413 121.917C388.574 125.011 388.574 130.029 385.413 133.123L280.969 235.385C277.808 238.48 272.683 238.48 269.522 235.385C269.522 235.385 269.522 235.385 269.522 235.385L195.394 162.807C194.604 162.033 193.322 162.033 192.532 162.807C192.532 162.807 192.532 162.807 192.532 162.807L118.405 235.385C115.244 238.48 110.12 238.48 106.959 235.385C106.959 235.385 106.959 235.385 106.959 235.385L2.51129 133.122C-0.649517 130.027 -0.649517 125.01 2.51129 121.915L25.6746 99.2365C28.8354 96.1418 33.9601 96.1418 37.1209 99.2365L111.25 171.816C112.041 172.589 113.322 172.589 114.112 171.816C114.112 171.816 114.112 171.815 114.112 171.815L188.238 99.2365C191.399 96.1417 196.523 96.1416 199.684 99.2362C199.684 99.2362 199.684 99.2363 199.684 99.2363L273.814 171.815C274.604 172.589 275.885 172.589 276.675 171.815L350.804 99.2378C353.964 96.1431 359.089 96.1431 362.25 99.2378Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,51 +0,0 @@
|
||||
import ChainCard from '@/components/ChainCard'
|
||||
import { truncate } from '@/utils/HelperUtil'
|
||||
import { Avatar, Button, Text, Tooltip } from '@nextui-org/react'
|
||||
import Image from 'next/image'
|
||||
import { useState } from 'react'
|
||||
|
||||
interface Props {
|
||||
name: string
|
||||
logo: string
|
||||
rgb: string
|
||||
address: string
|
||||
}
|
||||
|
||||
export default function AccountCard({ name, logo, rgb, address }: Props) {
|
||||
const [copied, setCopied] = useState(false)
|
||||
|
||||
function onCopy() {
|
||||
navigator?.clipboard?.writeText(address)
|
||||
setCopied(true)
|
||||
setTimeout(() => setCopied(false), 1500)
|
||||
}
|
||||
|
||||
return (
|
||||
<ChainCard rgb={rgb} flexDirection="row" alignItems="center">
|
||||
<Avatar src={logo} />
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text h5 css={{ marginLeft: '$9' }}>
|
||||
{name}
|
||||
</Text>
|
||||
<Text weight="light" size={13} css={{ marginLeft: '$9' }}>
|
||||
{truncate(address, 19)}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<Tooltip content={copied ? 'Copied!' : 'Copy'} placement="left">
|
||||
<Button
|
||||
size="sm"
|
||||
css={{ minWidth: 'auto', backgroundColor: 'rgba(255, 255, 255, 0.15)' }}
|
||||
onClick={onCopy}
|
||||
>
|
||||
<Image
|
||||
src={copied ? '/icons/checkmark-icon.svg' : '/icons/copy-icon.svg'}
|
||||
width={15}
|
||||
height={15}
|
||||
alt="copy icon"
|
||||
/>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</ChainCard>
|
||||
)
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import SettingsStore from '@/store/SettingsStore'
|
||||
import { cosmosAddresses } from '@/utils/CosmosWalletUtil'
|
||||
import { eip155Addresses } from '@/utils/EIP155WalletUtil'
|
||||
import { solanaAddresses } from '@/utils/SolanaWalletUtil'
|
||||
import { useSnapshot } from 'valtio'
|
||||
|
||||
export default function AccountPicker() {
|
||||
const { account } = useSnapshot(SettingsStore.state)
|
||||
|
||||
function onSelect(value: string) {
|
||||
const account = Number(value)
|
||||
SettingsStore.setAccount(account)
|
||||
SettingsStore.setEIP155Address(eip155Addresses[account])
|
||||
SettingsStore.setCosmosAddress(cosmosAddresses[account])
|
||||
SettingsStore.setSolanaAddress(solanaAddresses[account])
|
||||
}
|
||||
|
||||
return (
|
||||
<select value={account} onChange={e => onSelect(e.currentTarget.value)} aria-label="addresses">
|
||||
<option value={0}>Account 1</option>
|
||||
<option value={1}>Account 2</option>
|
||||
</select>
|
||||
)
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import { truncate } from '@/utils/HelperUtil'
|
||||
import { Card, Checkbox, Row, Text } from '@nextui-org/react'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IProps {
|
||||
address: string
|
||||
index: number
|
||||
selected: boolean
|
||||
onSelect: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default function AccountSelectCard({ address, selected, index, onSelect }: IProps) {
|
||||
return (
|
||||
<Card
|
||||
onClick={onSelect}
|
||||
clickable
|
||||
key={address}
|
||||
css={{
|
||||
marginTop: '$5',
|
||||
backgroundColor: selected ? 'rgba(23, 200, 100, 0.2)' : '$accents2'
|
||||
}}
|
||||
>
|
||||
<Row justify="space-between" align="center">
|
||||
<Checkbox size="lg" color="success" checked={selected} />
|
||||
|
||||
<Text>{`${truncate(address, 14)} - Account ${index + 1}`} </Text>
|
||||
</Row>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import { Card } from '@nextui-org/react'
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
interface Props {
|
||||
children: ReactNode | ReactNode[]
|
||||
rgb: string
|
||||
flexDirection: 'row' | 'col'
|
||||
alignItems: 'center' | 'flex-start'
|
||||
}
|
||||
|
||||
export default function ChainCard({ rgb, children, flexDirection, alignItems }: Props) {
|
||||
return (
|
||||
<Card
|
||||
bordered
|
||||
borderWeight="light"
|
||||
css={{
|
||||
borderColor: `rgba(${rgb}, 0.4)`,
|
||||
boxShadow: `0 0 10px 0 rgba(${rgb}, 0.15)`,
|
||||
backgroundColor: `rgba(${rgb}, 0.25)`,
|
||||
marginBottom: '$6',
|
||||
minHeight: '70px'
|
||||
}}
|
||||
>
|
||||
<Card.Body
|
||||
css={{
|
||||
flexDirection,
|
||||
alignItems,
|
||||
justifyContent: 'space-between',
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Card.Body>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import { Avatar, styled } from '@nextui-org/react'
|
||||
|
||||
const ChatAvatar = styled(Avatar, {
|
||||
'> span': {
|
||||
background:
|
||||
'radial-gradient(75.29% 75.29% at 64.96% 24.36%, #FFFFFF 0.52%, #F5CCFC 31.25%, #DBA4F5 51.56%, #9A8EE8 65.62%, #6493DA 82.29%, #6EBDEA 100%) !important'
|
||||
}
|
||||
} as any)
|
||||
|
||||
export default ChatAvatar
|
||||
@@ -1,68 +0,0 @@
|
||||
import { Avatar, Grid, styled, Text } from '@nextui-org/react'
|
||||
import ChatAvatar from './ChatAvatar'
|
||||
|
||||
const Wrapper = styled('div', {
|
||||
display: 'flex',
|
||||
alignItems: 'flex-end',
|
||||
margin: '0.25rem 0',
|
||||
variants: {
|
||||
messageType: {
|
||||
incoming: {
|
||||
alignSelf: 'flex-start'
|
||||
},
|
||||
outgoing: {
|
||||
alignSelf: 'flex-end',
|
||||
flexDirection: 'row-reverse'
|
||||
}
|
||||
}
|
||||
}
|
||||
} as any)
|
||||
|
||||
const MessageContainer = styled('div', {
|
||||
position: 'relative',
|
||||
width: 'fit-content',
|
||||
padding: '0.25rem 0.75rem',
|
||||
textAlign: 'left',
|
||||
wordBreak: 'break-word',
|
||||
color: '$grey500',
|
||||
variants: {
|
||||
messageType: {
|
||||
incoming: {
|
||||
background: '$chatPurplePrimary',
|
||||
alignSelf: 'flex-start',
|
||||
borderRadius: '20px 20px 20px 6px'
|
||||
},
|
||||
outgoing: {
|
||||
background: '$gray800',
|
||||
alignSelf: 'flex-end',
|
||||
borderRadius: '20px 20px 6px 20px'
|
||||
}
|
||||
}
|
||||
}
|
||||
} as any)
|
||||
|
||||
interface IProps {
|
||||
messageType: 'incoming' | 'outgoing'
|
||||
message: string
|
||||
}
|
||||
|
||||
export default function ChatMessage({ messageType, message }: IProps) {
|
||||
return (
|
||||
/* @ts-ignore */
|
||||
<Wrapper messageType={messageType}>
|
||||
{messageType === 'incoming' ? <ChatAvatar /> : null}
|
||||
|
||||
<Grid.Container direction="column" css={{ margin: '0.5rem' }}>
|
||||
{/* {messageType === 'incoming' && (
|
||||
<Text size={12} color={'$secondary'}>
|
||||
username.eth
|
||||
</Text>
|
||||
)} */}
|
||||
{/* @ts-ignore */}
|
||||
<MessageContainer messageType={messageType}>
|
||||
<Text color="$gray100">{message}</Text>
|
||||
</MessageContainer>
|
||||
</Grid.Container>
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import { Button } from '@nextui-org/react'
|
||||
import { MouseEventHandler, ReactNode } from 'react'
|
||||
|
||||
interface IProps {
|
||||
onClick: MouseEventHandler<HTMLButtonElement>
|
||||
icon: ReactNode
|
||||
}
|
||||
|
||||
export default function ChatPrimaryCTAButton({ onClick, icon }: IProps) {
|
||||
return (
|
||||
<Button
|
||||
auto
|
||||
rounded
|
||||
icon={icon}
|
||||
onClick={onClick}
|
||||
css={{
|
||||
background: '$chatGreenPrimary',
|
||||
fontSize: '$md',
|
||||
borderRadius: '100%',
|
||||
padding: '8px'
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
import { Button, Card, Col, CSS, Row, Text } from '@nextui-org/react'
|
||||
import { MouseEventHandler, ReactNode } from 'react'
|
||||
import ChatAvatar from './ChatAvatar'
|
||||
import { truncate } from '@/utils/HelperUtil'
|
||||
import { FiCheck, FiX } from 'react-icons/fi'
|
||||
import { demoAddressResolver } from '@/config/chatConstants'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IProps {
|
||||
account: string
|
||||
message: string
|
||||
onAccept: MouseEventHandler<any>
|
||||
onReject: MouseEventHandler<any>
|
||||
}
|
||||
|
||||
const RequestActionButton = ({
|
||||
onClick,
|
||||
icon,
|
||||
css
|
||||
}: {
|
||||
onClick: MouseEventHandler<HTMLButtonElement>
|
||||
icon: ReactNode
|
||||
css?: CSS
|
||||
}) => (
|
||||
<Button
|
||||
auto
|
||||
rounded
|
||||
size="xs"
|
||||
icon={icon}
|
||||
onClick={onClick}
|
||||
css={{
|
||||
fontSize: '$xs',
|
||||
fontWeight: '$extrabold',
|
||||
color: 'black',
|
||||
borderRadius: '100%',
|
||||
margin: '0 $2',
|
||||
padding: '5px',
|
||||
...css
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default function ChatRequestCard({ account, message, onAccept, onReject }: IProps) {
|
||||
const formattedAccount = demoAddressResolver[account] ?? account
|
||||
return (
|
||||
<Card
|
||||
bordered
|
||||
borderWeight="light"
|
||||
css={{
|
||||
position: 'relative',
|
||||
marginBottom: '$6',
|
||||
minHeight: '70px'
|
||||
}}
|
||||
>
|
||||
<Card.Body
|
||||
css={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
>
|
||||
<ChatAvatar />
|
||||
<Col>
|
||||
<Text h5 css={{ marginLeft: '$9' }}>
|
||||
{truncate(formattedAccount, 20)}
|
||||
</Text>
|
||||
<Text h6 weight="normal" css={{ marginLeft: '$9' }}>
|
||||
{message}
|
||||
</Text>
|
||||
</Col>
|
||||
<Row justify="flex-end">
|
||||
<RequestActionButton
|
||||
onClick={onAccept}
|
||||
icon={<FiCheck />}
|
||||
css={{
|
||||
background: '$chatGreenPrimary'
|
||||
}}
|
||||
/>
|
||||
<RequestActionButton onClick={onReject} icon={<FiX />} css={{ background: '#FF453A' }} />
|
||||
</Row>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import { Avatar, Button } from '@nextui-org/react'
|
||||
import NextLink from 'next/link'
|
||||
|
||||
interface IProps {
|
||||
requestCount: number
|
||||
}
|
||||
|
||||
export default function ChatRequestsButton({ requestCount }: IProps) {
|
||||
return (
|
||||
<NextLink href={`/chatRequests`} passHref>
|
||||
<Button
|
||||
rounded
|
||||
css={{
|
||||
width: '100%',
|
||||
color: '$chatGreenPrimary',
|
||||
background: '$chatGreenSecondary',
|
||||
fontWeight: '$bold'
|
||||
}}
|
||||
>
|
||||
<Avatar
|
||||
text={requestCount.toString()}
|
||||
size="sm"
|
||||
css={{
|
||||
marginRight: '$5',
|
||||
'> span': {
|
||||
fontSize: '$md !important',
|
||||
color: 'black !important',
|
||||
background: '$chatGreenPrimary !important'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
Chat Requests
|
||||
</Button>
|
||||
</NextLink>
|
||||
)
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
import { demoAddressResolver } from '@/config/chatConstants'
|
||||
import { truncate } from '@/utils/HelperUtil'
|
||||
import { Card, Text } from '@nextui-org/react'
|
||||
import Image from 'next/image'
|
||||
import NextLink from 'next/link'
|
||||
import ChatAvatar from './ChatAvatar'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IProps {
|
||||
topic?: string
|
||||
peerAccount: string
|
||||
latestMessage?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default function ChatSummaryCard({ peerAccount, topic, latestMessage }: IProps) {
|
||||
return (
|
||||
<NextLink href={`/chat?topic=${topic}&peerAccount=${peerAccount}`} passHref>
|
||||
<Card
|
||||
clickable
|
||||
bordered
|
||||
borderWeight="light"
|
||||
css={{
|
||||
position: 'relative',
|
||||
marginBottom: '$6',
|
||||
minHeight: '70px'
|
||||
}}
|
||||
>
|
||||
<Card.Body
|
||||
css={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
>
|
||||
<ChatAvatar />
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text h5 css={{ marginLeft: '$9' }}>
|
||||
{demoAddressResolver[peerAccount] ?? truncate(peerAccount, 24)}
|
||||
</Text>
|
||||
<Text h6 weight="normal" css={{ marginLeft: '$9' }}>
|
||||
{latestMessage ?? ''}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<Image src={'/icons/arrow-right-icon.svg'} width={20} height={20} alt="session icon" />
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</NextLink>
|
||||
)
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
import { Input, styled } from '@nextui-org/react'
|
||||
import { SyntheticEvent, useState } from 'react'
|
||||
|
||||
const StyledForm = styled('form', {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
padding: '0.5rem',
|
||||
zIndex: 3
|
||||
} as any)
|
||||
|
||||
const InputContainer = styled('div', {
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'row',
|
||||
position: 'sticky'
|
||||
} as any)
|
||||
|
||||
const SendButton = styled('button', {
|
||||
// reset button styles
|
||||
background: 'transparent',
|
||||
border: 'none',
|
||||
padding: 0,
|
||||
// styles
|
||||
width: '24px',
|
||||
margin: '0 10px',
|
||||
dflex: 'center',
|
||||
bg: 'linear-gradient(90deg, $secondary, $primary)',
|
||||
borderRadius: '$rounded',
|
||||
cursor: 'pointer',
|
||||
transition: 'opacity 0.25s ease 0s, transform 0.25s ease 0s',
|
||||
svg: {
|
||||
size: '100%',
|
||||
padding: '4px',
|
||||
transition: 'transform 0.25s ease 0s, opacity 200ms ease-in-out 50ms',
|
||||
boxShadow: '0 5px 20px -5px rgba(0, 0, 0, 0.1)'
|
||||
},
|
||||
'&:hover': {
|
||||
opacity: 0.8
|
||||
},
|
||||
'&:active': {
|
||||
transform: 'scale(0.9)',
|
||||
svg: {
|
||||
transform: 'translate(24px, -24px)',
|
||||
opacity: 0
|
||||
}
|
||||
}
|
||||
} as any)
|
||||
|
||||
const SendIcon = ({
|
||||
fill = 'currentColor',
|
||||
filled,
|
||||
size,
|
||||
height,
|
||||
width,
|
||||
label,
|
||||
className,
|
||||
...props
|
||||
}: any) => {
|
||||
return (
|
||||
<svg
|
||||
data-name="Iconly/Curved/Lock"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={size || width || 24}
|
||||
height={size || height || 24}
|
||||
viewBox="0 0 24 24"
|
||||
className={className}
|
||||
{...props}
|
||||
>
|
||||
<g transform="translate(2 2)">
|
||||
<path
|
||||
d="M19.435.582A1.933,1.933,0,0,0,17.5.079L1.408,4.76A1.919,1.919,0,0,0,.024,6.281a2.253,2.253,0,0,0,1,2.1L6.06,11.477a1.3,1.3,0,0,0,1.61-.193l5.763-5.8a.734.734,0,0,1,1.06,0,.763.763,0,0,1,0,1.067l-5.773,5.8a1.324,1.324,0,0,0-.193,1.619L11.6,19.054A1.91,1.91,0,0,0,13.263,20a2.078,2.078,0,0,0,.25-.01A1.95,1.95,0,0,0,15.144,18.6L19.916,2.525a1.964,1.964,0,0,0-.48-1.943"
|
||||
fill={fill}
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
handleSend: (message: string) => void
|
||||
}
|
||||
|
||||
export default function ChatboxInput({ handleSend }: IProps) {
|
||||
const [message, setMessage] = useState('')
|
||||
|
||||
function handleMessageChange(evt: any) {
|
||||
setMessage(evt.target.value)
|
||||
}
|
||||
|
||||
function onSend(evt: SyntheticEvent<HTMLButtonElement>) {
|
||||
evt.preventDefault()
|
||||
if (message.length > 0) {
|
||||
handleSend(message)
|
||||
// Clear the input post-send.
|
||||
setMessage('')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<InputContainer>
|
||||
<StyledForm>
|
||||
<Input
|
||||
fullWidth
|
||||
rounded
|
||||
clearable
|
||||
bordered
|
||||
placeholder="Message..."
|
||||
aria-label="chatbox-input"
|
||||
value={message}
|
||||
onChange={handleMessageChange}
|
||||
contentRightStyling={false}
|
||||
contentRight={
|
||||
<SendButton type="submit" onClick={onSend}>
|
||||
<SendIcon />
|
||||
</SendButton>
|
||||
}
|
||||
/>
|
||||
</StyledForm>
|
||||
</InputContainer>
|
||||
)
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
import Navigation from '@/components/Navigation'
|
||||
import RouteTransition from '@/components/RouteTransition'
|
||||
import { Card, Container, Loading } from '@nextui-org/react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { Fragment, ReactNode } from 'react'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface Props {
|
||||
initialized: boolean
|
||||
children: ReactNode | ReactNode[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Container
|
||||
*/
|
||||
export default function Layout({ children, initialized }: Props) {
|
||||
const { route } = useRouter()
|
||||
const shouldHideFooter = route === '/chat'
|
||||
|
||||
return (
|
||||
<Container
|
||||
display="flex"
|
||||
justify="center"
|
||||
alignItems="center"
|
||||
css={{
|
||||
width: '100vw',
|
||||
height: '100vh',
|
||||
paddingLeft: 0,
|
||||
paddingRight: 0
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
bordered={{ '@initial': false, '@xs': true }}
|
||||
borderWeight={{ '@initial': 'light', '@xs': 'light' }}
|
||||
css={{
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
justifyContent: initialized ? 'normal' : 'center',
|
||||
alignItems: initialized ? 'normal' : 'center',
|
||||
borderRadius: 0,
|
||||
paddingBottom: 5,
|
||||
'@xs': {
|
||||
borderRadius: '$lg',
|
||||
height: '95vh',
|
||||
maxWidth: '450px'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{initialized ? (
|
||||
<Fragment>
|
||||
<RouteTransition>
|
||||
<Card.Body
|
||||
css={{
|
||||
display: 'block',
|
||||
paddingLeft: 2,
|
||||
paddingRight: 2,
|
||||
paddingBottom: '40px',
|
||||
'@xs': {
|
||||
padding: '20px',
|
||||
paddingBottom: '40px'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Card.Body>
|
||||
</RouteTransition>
|
||||
|
||||
<Card.Footer
|
||||
css={{
|
||||
display: shouldHideFooter ? 'none' : 'block',
|
||||
height: '85px',
|
||||
minHeight: '85px',
|
||||
position: 'sticky',
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'flex-end',
|
||||
boxShadow: '0 -30px 20px #111111',
|
||||
backgroundColor: '#111111',
|
||||
zIndex: 200,
|
||||
bottom: 0,
|
||||
left: 0
|
||||
}}
|
||||
>
|
||||
<Navigation />
|
||||
</Card.Footer>
|
||||
</Fragment>
|
||||
) : (
|
||||
<Loading />
|
||||
)}
|
||||
</Card>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import ModalStore from '@/store/ModalStore'
|
||||
import SessionProposalModal from '@/views/SessionProposalModal'
|
||||
import SessionSendTransactionModal from '@/views/SessionSendTransactionModal'
|
||||
import SessionSignCosmosModal from '@/views/SessionSignCosmosModal'
|
||||
import SessionRequestModal from '@/views/SessionSignModal'
|
||||
import SessionSignSolanaModal from '@/views/SessionSignSolanaModal'
|
||||
import SessionSignTypedDataModal from '@/views/SessionSignTypedDataModal'
|
||||
import SessionUnsuportedMethodModal from '@/views/SessionUnsuportedMethodModal'
|
||||
import { Modal as NextModal } from '@nextui-org/react'
|
||||
import { useSnapshot } from 'valtio'
|
||||
|
||||
export default function Modal() {
|
||||
const { open, view } = useSnapshot(ModalStore.state)
|
||||
|
||||
return (
|
||||
<NextModal blur open={open} style={{ border: '1px solid rgba(139, 139, 139, 0.4)' }}>
|
||||
{view === 'SessionProposalModal' && <SessionProposalModal />}
|
||||
{view === 'SessionSignModal' && <SessionRequestModal />}
|
||||
{view === 'SessionSignTypedDataModal' && <SessionSignTypedDataModal />}
|
||||
{view === 'SessionSendTransactionModal' && <SessionSendTransactionModal />}
|
||||
{view === 'SessionUnsuportedMethodModal' && <SessionUnsuportedMethodModal />}
|
||||
{view === 'SessionSignCosmosModal' && <SessionSignCosmosModal />}
|
||||
{view === 'SessionSignSolanaModal' && <SessionSignSolanaModal />}
|
||||
</NextModal>
|
||||
)
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
import { Avatar, Row, styled } from '@nextui-org/react'
|
||||
import { FiMessageCircle } from 'react-icons/fi'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
|
||||
const StyledChatIcon = styled(FiMessageCircle, {
|
||||
color: '$primary'
|
||||
} as any)
|
||||
|
||||
export default function Navigation() {
|
||||
return (
|
||||
<Row justify="space-between" align="center">
|
||||
<Link href="/" passHref>
|
||||
<a className="navLink">
|
||||
<Image alt="accounts icon" src="/icons/accounts-icon.svg" width={27} height={27} />
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<Link href="/sessions" passHref>
|
||||
<a className="navLink">
|
||||
<Image alt="sessions icon" src="/icons/sessions-icon.svg" width={27} height={27} />
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<Link href="/walletconnect" passHref>
|
||||
<a className="navLink">
|
||||
<Avatar
|
||||
size="lg"
|
||||
css={{ cursor: 'pointer' }}
|
||||
color="gradient"
|
||||
icon={
|
||||
<Image
|
||||
alt="wallet connect icon"
|
||||
src="/wallet-connect-logo.svg"
|
||||
width={30}
|
||||
height={30}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
{/* TODO: re-enable pairings link */}
|
||||
{/* <Link href="/pairings" passHref>
|
||||
<a className="navLink">
|
||||
<Image alt="pairings icon" src="/icons/pairings-icon.svg" width={25} height={25} />
|
||||
</a>
|
||||
</Link> */}
|
||||
|
||||
<Link href="/chats" passHref>
|
||||
<a className="navLink">
|
||||
<Image alt="chats icon" src="/icons/chat-icon.svg" width={25} height={25} />
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<Link href="/settings" passHref>
|
||||
<a className="navLink">
|
||||
<Image alt="settings icon" src="/icons/settings-icon.svg" width={27} height={27} />
|
||||
</a>
|
||||
</Link>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
import { Button, Col, Divider, Row, Text } from '@nextui-org/react'
|
||||
import { Fragment, ReactNode } from 'react'
|
||||
import { FiChevronLeft } from 'react-icons/fi'
|
||||
import NextLink from 'next/link'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface Props {
|
||||
children?: ReactNode | ReactNode[]
|
||||
title: string
|
||||
withBackButton?: boolean
|
||||
backButtonHref?: string
|
||||
ctaButton?: ReactNode | ReactNode[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default function PageHeader({
|
||||
title,
|
||||
children,
|
||||
ctaButton,
|
||||
withBackButton = false,
|
||||
backButtonHref = '#'
|
||||
}: Props) {
|
||||
return (
|
||||
<Fragment>
|
||||
<Row css={{ marginBottom: '$5', width: '100%' }} justify="space-between" align="center">
|
||||
{withBackButton && (
|
||||
<Col css={{ width: 'auto' }}>
|
||||
<NextLink href={backButtonHref} passHref>
|
||||
<Button
|
||||
size="xl"
|
||||
auto
|
||||
light
|
||||
animated={false}
|
||||
icon={<FiChevronLeft />}
|
||||
css={{ paddingLeft: 0 }}
|
||||
/>
|
||||
</NextLink>
|
||||
</Col>
|
||||
)}
|
||||
<Col>
|
||||
<Text h3 weight="bold">
|
||||
{title}
|
||||
</Text>
|
||||
</Col>
|
||||
{children ? <Col css={{ flex: 1 }}>{children}</Col> : null}
|
||||
{ctaButton}
|
||||
</Row>
|
||||
|
||||
<Divider css={{ marginBottom: '$10' }} />
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import { truncate } from '@/utils/HelperUtil'
|
||||
import { Avatar, Button, Card, Link, Text, Tooltip } from '@nextui-org/react'
|
||||
import Image from 'next/image'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IProps {
|
||||
logo?: string
|
||||
name?: string
|
||||
url?: string
|
||||
onDelete: () => Promise<void>
|
||||
}
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default function PairingCard({ logo, name, url, onDelete }: IProps) {
|
||||
return (
|
||||
<Card
|
||||
bordered
|
||||
borderWeight="light"
|
||||
css={{
|
||||
position: 'relative',
|
||||
marginBottom: '$6',
|
||||
minHeight: '70px'
|
||||
}}
|
||||
>
|
||||
<Card.Body
|
||||
css={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
>
|
||||
<Avatar src={logo} />
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text h5 css={{ marginLeft: '$9' }}>
|
||||
{name}
|
||||
</Text>
|
||||
<Link href={url} css={{ marginLeft: '$9' }}>
|
||||
{truncate(url?.split('https://')[1] ?? 'Unknown', 23)}
|
||||
</Link>
|
||||
</div>
|
||||
<Tooltip content="Delete" placement="left">
|
||||
<Button size="sm" color="error" flat onClick={onDelete} css={{ minWidth: 'auto' }}>
|
||||
<Image src={'/icons/delete-icon.svg'} width={15} height={15} alt="delete icon" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { Avatar, Col, Link, Row, Text } from '@nextui-org/react'
|
||||
import { SignClientTypes } from '@walletconnect/types'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IProps {
|
||||
metadata: SignClientTypes.Metadata
|
||||
}
|
||||
|
||||
/**
|
||||
* Components
|
||||
*/
|
||||
export default function ProjectInfoCard({ metadata }: IProps) {
|
||||
const { icons, name, url } = metadata
|
||||
|
||||
return (
|
||||
<Row align="center">
|
||||
<Col span={3}>
|
||||
<Avatar src={icons[0]} />
|
||||
</Col>
|
||||
<Col span={14}>
|
||||
<Text h5>{name}</Text>
|
||||
<Link href={url}>{url}</Link>
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import AccountSelectCard from '@/components/AccountSelectCard'
|
||||
import { Col, Row, Text } from '@nextui-org/react'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IProps {
|
||||
chain: string
|
||||
addresses: string[]
|
||||
selectedAddresses: string[] | undefined
|
||||
onSelect: (chain: string, address: string) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default function ProposalSelectSection({
|
||||
addresses,
|
||||
selectedAddresses,
|
||||
chain,
|
||||
onSelect
|
||||
}: IProps) {
|
||||
return (
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h4 css={{ marginTop: '$5' }}>{`Choose ${chain} accounts`}</Text>
|
||||
{addresses.map((address, index) => (
|
||||
<AccountSelectCard
|
||||
key={address}
|
||||
address={address}
|
||||
index={index}
|
||||
onSelect={() => onSelect(chain, address)}
|
||||
selected={selectedAddresses?.includes(address) ?? false}
|
||||
/>
|
||||
))}
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
import { Button, Loading } from '@nextui-org/react'
|
||||
import dynamic from 'next/dynamic'
|
||||
import Image from 'next/image'
|
||||
import { Fragment, useState } from 'react'
|
||||
|
||||
/**
|
||||
* You can use normal import if you are not within next / ssr environment
|
||||
* @info https://nextjs.org/docs/advanced-features/dynamic-import
|
||||
*/
|
||||
const ReactQrReader = dynamic(() => import('react-qr-reader-es6'), { ssr: false })
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IProps {
|
||||
onConnect: (uri: string) => Promise<void>
|
||||
}
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default function QrReader({ onConnect }: IProps) {
|
||||
const [show, setShow] = useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
function onError() {
|
||||
setShow(false)
|
||||
}
|
||||
|
||||
async function onScan(data: string | null) {
|
||||
if (data) {
|
||||
await onConnect(data)
|
||||
setShow(false)
|
||||
}
|
||||
}
|
||||
|
||||
function onShowScanner() {
|
||||
setLoading(true)
|
||||
setShow(true)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
{show ? (
|
||||
<Fragment>
|
||||
{loading && <Loading css={{ position: 'absolute' }} />}
|
||||
<div className="qrVideoMask">
|
||||
<ReactQrReader
|
||||
onLoad={() => setLoading(false)}
|
||||
showViewFinder={false}
|
||||
onError={onError}
|
||||
onScan={onScan}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</div>
|
||||
</Fragment>
|
||||
) : (
|
||||
<div className="container qrPlaceholder">
|
||||
<Image
|
||||
src="/icons/qr-icon.svg"
|
||||
width={100}
|
||||
height={100}
|
||||
alt="qr code icon"
|
||||
className="qrIcon"
|
||||
/>
|
||||
<Button
|
||||
color="gradient"
|
||||
css={{ marginTop: '$10', width: '100%' }}
|
||||
onClick={onShowScanner}
|
||||
>
|
||||
Scan QR code
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { Col, Row, Text } from '@nextui-org/react'
|
||||
import { CodeBlock, codepen } from 'react-code-blocks'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IProps {
|
||||
data: Record<string, unknown>
|
||||
}
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default function RequestDataCard({ data }: IProps) {
|
||||
return (
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h5>Data</Text>
|
||||
<CodeBlock
|
||||
showLineNumbers={false}
|
||||
text={JSON.stringify(data, null, 2)}
|
||||
theme={codepen}
|
||||
language="json"
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
import { COSMOS_MAINNET_CHAINS, TCosmosChain } from '@/data/COSMOSData'
|
||||
import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data'
|
||||
import { SOLANA_CHAINS, TSolanaChain } from '@/data/SolanaData'
|
||||
import { Col, Divider, Row, Text } from '@nextui-org/react'
|
||||
import { Fragment } from 'react'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IProps {
|
||||
chains: string[]
|
||||
protocol: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default function RequesDetailsCard({ chains, protocol }: IProps) {
|
||||
return (
|
||||
<Fragment>
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h5>Blockchain(s)</Text>
|
||||
<Text color="$gray400">
|
||||
{chains
|
||||
.map(
|
||||
chain =>
|
||||
EIP155_CHAINS[chain as TEIP155Chain]?.name ??
|
||||
COSMOS_MAINNET_CHAINS[chain as TCosmosChain]?.name ??
|
||||
SOLANA_CHAINS[chain as TSolanaChain]?.name ??
|
||||
chain
|
||||
)
|
||||
.join(', ')}
|
||||
</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h5>Relay Protocol</Text>
|
||||
<Text color="$gray400">{protocol}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { Col, Row, Text } from '@nextui-org/react'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IProps {
|
||||
methods: string[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default function RequestMethodCard({ methods }: IProps) {
|
||||
return (
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h5>Methods</Text>
|
||||
<Text color="$gray400">{methods.map(method => method).join(', ')}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import { Container, Modal, Text } from '@nextui-org/react'
|
||||
import { Fragment, ReactNode } from 'react'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IProps {
|
||||
title: string
|
||||
children: ReactNode | ReactNode[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default function RequestModalContainer({ children, title }: IProps) {
|
||||
return (
|
||||
<Fragment>
|
||||
<Modal.Header>
|
||||
<Text h3>{title}</Text>
|
||||
</Modal.Header>
|
||||
|
||||
<Modal.Body>
|
||||
<Container css={{ padding: 0 }}>{children}</Container>
|
||||
</Modal.Body>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import { useRouter } from 'next/router'
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IProps {
|
||||
children: ReactNode | ReactNode[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Components
|
||||
*/
|
||||
export default function RouteTransition({ children }: IProps) {
|
||||
const { pathname } = useRouter()
|
||||
|
||||
return (
|
||||
<AnimatePresence exitBeforeEnter>
|
||||
<motion.div
|
||||
className="routeTransition"
|
||||
key={pathname}
|
||||
initial={{ opacity: 0, translateY: 7 }}
|
||||
animate={{ opacity: 1, translateY: 0 }}
|
||||
exit={{ opacity: 0, translateY: 7 }}
|
||||
transition={{ duration: 0.18 }}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
)
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
import { truncate } from '@/utils/HelperUtil'
|
||||
import { Avatar, Card, Link, Text } from '@nextui-org/react'
|
||||
import Image from 'next/image'
|
||||
import NextLink from 'next/link'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IProps {
|
||||
topic?: string
|
||||
logo?: string
|
||||
name?: string
|
||||
url?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default function SessionCard({ logo, name, url, topic }: IProps) {
|
||||
return (
|
||||
<NextLink href={`/session?topic=${topic}`} passHref>
|
||||
<Card
|
||||
clickable
|
||||
bordered
|
||||
borderWeight="light"
|
||||
css={{
|
||||
position: 'relative',
|
||||
marginBottom: '$6',
|
||||
minHeight: '70px'
|
||||
}}
|
||||
>
|
||||
<Card.Body
|
||||
css={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
>
|
||||
<Avatar src={logo} />
|
||||
<div style={{ flex: 1 }}>
|
||||
<Text h5 css={{ marginLeft: '$9' }}>
|
||||
{name}
|
||||
</Text>
|
||||
<Link href={url} css={{ marginLeft: '$9' }}>
|
||||
{truncate(url?.split('https://')[1] ?? 'Unknown', 23)}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<Image src={'/icons/arrow-right-icon.svg'} width={20} height={20} alt="session icon" />
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</NextLink>
|
||||
)
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
import ChainCard from '@/components/ChainCard'
|
||||
import { COSMOS_MAINNET_CHAINS } from '@/data/COSMOSData'
|
||||
import { EIP155_MAINNET_CHAINS, EIP155_TEST_CHAINS } from '@/data/EIP155Data'
|
||||
import { SOLANA_MAINNET_CHAINS, SOLANA_TEST_CHAINS } from '@/data/SolanaData'
|
||||
import { formatChainName } from '@/utils/HelperUtil'
|
||||
import { Col, Row, Text } from '@nextui-org/react'
|
||||
import { SessionTypes } from '@walletconnect/types'
|
||||
import { Fragment } from 'react'
|
||||
|
||||
/**
|
||||
* Utilities
|
||||
*/
|
||||
const CHAIN_METADATA = {
|
||||
...COSMOS_MAINNET_CHAINS,
|
||||
...SOLANA_MAINNET_CHAINS,
|
||||
...EIP155_MAINNET_CHAINS,
|
||||
...EIP155_TEST_CHAINS,
|
||||
...SOLANA_TEST_CHAINS
|
||||
}
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IProps {
|
||||
namespace: SessionTypes.Namespace
|
||||
}
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default function SessionChainCard({ namespace }: IProps) {
|
||||
const chains: string[] = []
|
||||
|
||||
// WIP
|
||||
|
||||
namespace.accounts.forEach(account => {
|
||||
const [type, chain] = account.split(':')
|
||||
const chainId = `${type}:${chain}`
|
||||
chains.push(chainId)
|
||||
})
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{chains.map(chainId => {
|
||||
const allMethods = [...namespace.methods]
|
||||
const allEvents = [...namespace.events]
|
||||
// @ts-expect-error
|
||||
const rgb = CHAIN_METADATA[chainId]?.rgb
|
||||
|
||||
return (
|
||||
<ChainCard key={chainId} rgb={rgb ?? ''} flexDirection="col" alignItems="flex-start">
|
||||
<Text h5 css={{ marginBottom: '$5' }}>
|
||||
{formatChainName(chainId)}
|
||||
</Text>
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h6>Methods</Text>
|
||||
<Text color="$gray300">{allMethods.length ? allMethods.join(', ') : '-'}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row css={{ marginTop: '$5' }}>
|
||||
<Col>
|
||||
<Text h6>Events</Text>
|
||||
<Text color="$gray300">{allEvents.length ? allEvents.join(', ') : '-'}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
</ChainCard>
|
||||
)
|
||||
})}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import ChainCard from '@/components/ChainCard'
|
||||
import { COSMOS_MAINNET_CHAINS } from '@/data/COSMOSData'
|
||||
import { EIP155_MAINNET_CHAINS, EIP155_TEST_CHAINS } from '@/data/EIP155Data'
|
||||
import { SOLANA_MAINNET_CHAINS, SOLANA_TEST_CHAINS } from '@/data/SolanaData'
|
||||
import { formatChainName } from '@/utils/HelperUtil'
|
||||
import { Col, Row, Text } from '@nextui-org/react'
|
||||
import { ProposalTypes } from '@walletconnect/types'
|
||||
import { Fragment } from 'react'
|
||||
|
||||
/**
|
||||
* Utilities
|
||||
*/
|
||||
const CHAIN_METADATA = {
|
||||
...COSMOS_MAINNET_CHAINS,
|
||||
...SOLANA_MAINNET_CHAINS,
|
||||
...EIP155_MAINNET_CHAINS,
|
||||
...EIP155_TEST_CHAINS,
|
||||
...SOLANA_TEST_CHAINS
|
||||
}
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IProps {
|
||||
requiredNamespace: ProposalTypes.RequiredNamespace
|
||||
}
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default function SessionProposalChainCard({ requiredNamespace }: IProps) {
|
||||
return (
|
||||
<Fragment>
|
||||
{requiredNamespace.chains?.map(chainId => {
|
||||
const allMethods = [...requiredNamespace.methods]
|
||||
const allEvents = [...requiredNamespace.events]
|
||||
// @ts-expect-error
|
||||
const rgb = CHAIN_METADATA[chainId]?.rgb
|
||||
|
||||
return (
|
||||
<ChainCard key={chainId} rgb={rgb ?? ''} flexDirection="col" alignItems="flex-start">
|
||||
<Text h5 css={{ marginBottom: '$5' }}>
|
||||
{formatChainName(chainId)}
|
||||
</Text>
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h6>Methods</Text>
|
||||
<Text color="$gray300">{allMethods.length ? allMethods.join(', ') : '-'}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row css={{ marginTop: '$5' }}>
|
||||
<Col>
|
||||
<Text h6>Events</Text>
|
||||
<Text color="$gray300">{allEvents.length ? allEvents.join(', ') : '-'}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
</ChainCard>
|
||||
)
|
||||
})}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
export const demoContactsMap: Record<string, string> = {
|
||||
'swift.eth': 'eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb',
|
||||
'kotlin.eth': 'eip155:2:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb'
|
||||
}
|
||||
|
||||
export const demoAddressResolver: Record<string, string> = {
|
||||
'eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb': 'swift.eth',
|
||||
'eip155:2:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb': 'kotlin.eth'
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { BaseTheme } from '@nextui-org/react/types/theme/types'
|
||||
|
||||
export const chatTheme: BaseTheme = {
|
||||
colors: {
|
||||
chatGreenPrimary: '#2BEE6C',
|
||||
chatGreenSecondary: 'rgba(13, 242, 166, 0.15)',
|
||||
chatPurplePrimary: '#794CFF'
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
export type TCosmosChain = keyof typeof COSMOS_MAINNET_CHAINS
|
||||
|
||||
/**
|
||||
* Chains
|
||||
*/
|
||||
export const COSMOS_MAINNET_CHAINS = {
|
||||
'cosmos:cosmoshub-4': {
|
||||
chainId: 'cosmoshub-4',
|
||||
name: 'Cosmos Hub',
|
||||
logo: '/chain-logos/cosmos-cosmoshub-4.png',
|
||||
rgb: '107, 111, 147',
|
||||
rpc: ''
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
export const COSMOS_SIGNING_METHODS = {
|
||||
COSMOS_SIGN_DIRECT: 'cosmos_signDirect',
|
||||
COSMOS_SIGN_AMINO: 'cosmos_signAmino'
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/**
|
||||
* @desc Refference list of eip155 chains
|
||||
* @url https://chainlist.org
|
||||
*/
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
export type TEIP155Chain = keyof typeof EIP155_CHAINS
|
||||
|
||||
/**
|
||||
* Chains
|
||||
*/
|
||||
export const EIP155_MAINNET_CHAINS = {
|
||||
'eip155:1': {
|
||||
chainId: 1,
|
||||
name: 'Ethereum',
|
||||
logo: '/chain-logos/eip155-1.png',
|
||||
rgb: '99, 125, 234',
|
||||
rpc: 'https://cloudflare-eth.com/'
|
||||
},
|
||||
'eip155:43114': {
|
||||
chainId: 43114,
|
||||
name: 'Avalanche C-Chain',
|
||||
logo: '/chain-logos/eip155-43113.png',
|
||||
rgb: '232, 65, 66',
|
||||
rpc: 'https://api.avax.network/ext/bc/C/rpc'
|
||||
},
|
||||
'eip155:137': {
|
||||
chainId: 137,
|
||||
name: 'Polygon',
|
||||
logo: '/chain-logos/eip155-137.png',
|
||||
rgb: '130, 71, 229',
|
||||
rpc: 'https://polygon-rpc.com/'
|
||||
}
|
||||
}
|
||||
|
||||
export const EIP155_TEST_CHAINS = {
|
||||
'eip155:42': {
|
||||
chainId: 42,
|
||||
name: 'Ethereum Kovan',
|
||||
logo: '/chain-logos/eip155-1.png',
|
||||
rgb: '99, 125, 234',
|
||||
rpc: 'https://kovan.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161'
|
||||
},
|
||||
'eip155:43113': {
|
||||
chainId: 43113,
|
||||
name: 'Avalanche Fuji',
|
||||
logo: '/chain-logos/eip155-43113.png',
|
||||
rgb: '232, 65, 66',
|
||||
rpc: 'https://api.avax-test.network/ext/bc/C/rpc'
|
||||
},
|
||||
'eip155:80001': {
|
||||
chainId: 80001,
|
||||
name: 'Polygon Mumbai',
|
||||
logo: '/chain-logos/eip155-137.png',
|
||||
rgb: '130, 71, 229',
|
||||
rpc: 'https://matic-mumbai.chainstacklabs.com'
|
||||
}
|
||||
}
|
||||
|
||||
export const EIP155_CHAINS = { ...EIP155_MAINNET_CHAINS, ...EIP155_TEST_CHAINS }
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
export const EIP155_SIGNING_METHODS = {
|
||||
PERSONAL_SIGN: 'personal_sign',
|
||||
ETH_SIGN: 'eth_sign',
|
||||
ETH_SIGN_TRANSACTION: 'eth_signTransaction',
|
||||
ETH_SIGN_TYPED_DATA: 'eth_signTypedData',
|
||||
ETH_SIGN_TYPED_DATA_V3: 'eth_signTypedData_v3',
|
||||
ETH_SIGN_TYPED_DATA_V4: 'eth_signTypedData_v4',
|
||||
ETH_SEND_RAW_TRANSACTION: 'eth_sendRawTransaction',
|
||||
ETH_SEND_TRANSACTION: 'eth_sendTransaction'
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
export type TSolanaChain = keyof typeof SOLANA_MAINNET_CHAINS
|
||||
|
||||
/**
|
||||
* Chains
|
||||
*/
|
||||
export const SOLANA_MAINNET_CHAINS = {
|
||||
'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ': {
|
||||
chainId: '4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ',
|
||||
name: 'Solana',
|
||||
logo: '/chain-logos/solana-4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ.png',
|
||||
rgb: '30, 240, 166',
|
||||
rpc: ''
|
||||
}
|
||||
}
|
||||
|
||||
export const SOLANA_TEST_CHAINS = {
|
||||
'solana:8E9rvCKLFQia2Y35HXjjpWzj8weVo44K': {
|
||||
chainId: '8E9rvCKLFQia2Y35HXjjpWzj8weVo44K',
|
||||
name: 'Solana Devnet',
|
||||
logo: '/chain-logos/solana-4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ.png',
|
||||
rgb: '30, 240, 166',
|
||||
rpc: ''
|
||||
}
|
||||
}
|
||||
|
||||
export const SOLANA_CHAINS = { ...SOLANA_MAINNET_CHAINS, ...SOLANA_TEST_CHAINS }
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
export const SOLANA_SIGNING_METHODS = {
|
||||
SOLANA_SIGN_TRANSACTION: 'solana_signTransaction',
|
||||
SOLANA_SIGN_MESSAGE: 'solana_signMessage'
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import SettingsStore from '@/store/SettingsStore'
|
||||
import { createOrRestoreCosmosWallet } from '@/utils/CosmosWalletUtil'
|
||||
import { createOrRestoreEIP155Wallet, eip155Wallets } from '@/utils/EIP155WalletUtil'
|
||||
import { createOrRestoreSolanaWallet } from '@/utils/SolanaWalletUtil'
|
||||
import { chatClient, createChatClient, createSignClient } from '@/utils/WalletConnectUtil'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
|
||||
export default function useInitialization() {
|
||||
const [initialized, setInitialized] = useState(false)
|
||||
|
||||
const onInitialize = useCallback(async () => {
|
||||
try {
|
||||
const accountIndex = parseInt(
|
||||
new URLSearchParams(window.location.search).get('accountIndex') ?? '0'
|
||||
)
|
||||
const { eip155Addresses } = createOrRestoreEIP155Wallet()
|
||||
const { cosmosAddresses } = await createOrRestoreCosmosWallet()
|
||||
const { solanaAddresses } = await createOrRestoreSolanaWallet()
|
||||
|
||||
SettingsStore.setAccount(accountIndex)
|
||||
SettingsStore.setEIP155Address(eip155Addresses[accountIndex])
|
||||
SettingsStore.setCosmosAddress(cosmosAddresses[accountIndex])
|
||||
SettingsStore.setSolanaAddress(solanaAddresses[accountIndex])
|
||||
|
||||
await createSignClient()
|
||||
|
||||
await createChatClient()
|
||||
await chatClient.register({
|
||||
account: `eip155:1:${eip155Addresses[accountIndex]}`,
|
||||
onSign: async message => {
|
||||
return eip155Wallets[eip155Addresses[accountIndex]].signMessage(message)
|
||||
}
|
||||
})
|
||||
console.log(
|
||||
'[Chat] registered address %s on keyserver',
|
||||
`eip155:1:${eip155Addresses[accountIndex]}`
|
||||
)
|
||||
|
||||
setInitialized(true)
|
||||
} catch (err: unknown) {
|
||||
alert(err)
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!initialized) {
|
||||
onInitialize()
|
||||
}
|
||||
}, [initialized, onInitialize])
|
||||
|
||||
return initialized
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
import { COSMOS_SIGNING_METHODS } from '@/data/COSMOSData'
|
||||
import { EIP155_SIGNING_METHODS } from '@/data/EIP155Data'
|
||||
import { SOLANA_SIGNING_METHODS } from '@/data/SolanaData'
|
||||
import ModalStore from '@/store/ModalStore'
|
||||
import { signClient } from '@/utils/WalletConnectUtil'
|
||||
import { SignClientTypes } from '@walletconnect/types'
|
||||
import { useCallback, useEffect } from 'react'
|
||||
|
||||
export default function useWalletConnectEventsManager(initialized: boolean) {
|
||||
/******************************************************************************
|
||||
* 1. Open session proposal modal for confirmation / rejection
|
||||
*****************************************************************************/
|
||||
const onSessionProposal = useCallback(
|
||||
(proposal: SignClientTypes.EventArguments['session_proposal']) => {
|
||||
ModalStore.open('SessionProposalModal', { proposal })
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
/******************************************************************************
|
||||
* 3. Open request handling modal based on method that was used
|
||||
*****************************************************************************/
|
||||
const onSessionRequest = useCallback(
|
||||
async (requestEvent: SignClientTypes.EventArguments['session_request']) => {
|
||||
console.log('session_request', requestEvent)
|
||||
const { topic, params } = requestEvent
|
||||
const { request } = params
|
||||
const session = signClient.session.get(topic)
|
||||
const requestSession = {
|
||||
...session,
|
||||
optionalNamespaces: {},
|
||||
pairingTopic: session.topic
|
||||
}
|
||||
|
||||
switch (request.method) {
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN:
|
||||
case EIP155_SIGNING_METHODS.PERSONAL_SIGN:
|
||||
return ModalStore.open('SessionSignModal', {
|
||||
requestEvent,
|
||||
requestSession
|
||||
})
|
||||
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA:
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V3:
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V4:
|
||||
return ModalStore.open('SessionSignTypedDataModal', { requestEvent, requestSession })
|
||||
|
||||
case EIP155_SIGNING_METHODS.ETH_SEND_TRANSACTION:
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN_TRANSACTION:
|
||||
return ModalStore.open('SessionSendTransactionModal', { requestEvent, requestSession })
|
||||
|
||||
case COSMOS_SIGNING_METHODS.COSMOS_SIGN_DIRECT:
|
||||
case COSMOS_SIGNING_METHODS.COSMOS_SIGN_AMINO:
|
||||
return ModalStore.open('SessionSignCosmosModal', { requestEvent, requestSession })
|
||||
|
||||
case SOLANA_SIGNING_METHODS.SOLANA_SIGN_MESSAGE:
|
||||
case SOLANA_SIGNING_METHODS.SOLANA_SIGN_TRANSACTION:
|
||||
return ModalStore.open('SessionSignSolanaModal', { requestEvent, requestSession })
|
||||
|
||||
default:
|
||||
return ModalStore.open('SessionUnsuportedMethodModal', { requestEvent, requestSession })
|
||||
}
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
/******************************************************************************
|
||||
* Set up WalletConnect event listeners
|
||||
*****************************************************************************/
|
||||
useEffect(() => {
|
||||
if (initialized) {
|
||||
// TODOs
|
||||
signClient.on('session_ping', data => console.log('ping', data))
|
||||
signClient.on('session_event', data => console.log('event', data))
|
||||
signClient.on('session_update', data => console.log('update', data))
|
||||
signClient.on('session_delete', data => console.log('delete', data))
|
||||
}
|
||||
}, [initialized, onSessionProposal, onSessionRequest])
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
import { Secp256k1Wallet, StdSignDoc } from '@cosmjs/amino'
|
||||
import { fromHex } from '@cosmjs/encoding'
|
||||
import { DirectSecp256k1Wallet } from '@cosmjs/proto-signing'
|
||||
// @ts-expect-error
|
||||
import { SignDoc } from '@cosmjs/proto-signing/build/codec/cosmos/tx/v1beta1/tx'
|
||||
import Keyring from 'mnemonic-keyring'
|
||||
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
const DEFAULT_PATH = "m/44'/118'/0'/0/0"
|
||||
const DEFAULT_PREFIX = 'cosmos'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IInitArguments {
|
||||
mnemonic?: string
|
||||
path?: string
|
||||
prefix?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Library
|
||||
*/
|
||||
export default class CosmosLib {
|
||||
private keyring: Keyring
|
||||
private directSigner: DirectSecp256k1Wallet
|
||||
private aminoSigner: Secp256k1Wallet
|
||||
|
||||
constructor(keyring: Keyring, directSigner: DirectSecp256k1Wallet, aminoSigner: Secp256k1Wallet) {
|
||||
this.directSigner = directSigner
|
||||
this.keyring = keyring
|
||||
this.aminoSigner = aminoSigner
|
||||
}
|
||||
|
||||
static async init({ mnemonic, path, prefix }: IInitArguments) {
|
||||
const keyring = await Keyring.init({ mnemonic: mnemonic ?? Keyring.generateMnemonic() })
|
||||
const privateKey = fromHex(keyring.getPrivateKey(path ?? DEFAULT_PATH))
|
||||
const directSigner = await DirectSecp256k1Wallet.fromKey(privateKey, prefix ?? DEFAULT_PREFIX)
|
||||
const aminoSigner = await Secp256k1Wallet.fromKey(privateKey, prefix ?? DEFAULT_PREFIX)
|
||||
|
||||
return new CosmosLib(keyring, directSigner, aminoSigner)
|
||||
}
|
||||
|
||||
public getMnemonic() {
|
||||
return this.keyring.mnemonic
|
||||
}
|
||||
|
||||
public async getAddress() {
|
||||
const account = await this.directSigner.getAccounts()
|
||||
|
||||
return account[0].address
|
||||
}
|
||||
|
||||
public async signDirect(address: string, signDoc: SignDoc) {
|
||||
return await this.directSigner.signDirect(address, signDoc)
|
||||
}
|
||||
|
||||
public async signAmino(address: string, signDoc: StdSignDoc) {
|
||||
return await this.aminoSigner.signAmino(address, signDoc)
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
import { providers, Wallet } from 'ethers'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IInitArgs {
|
||||
mnemonic?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Library
|
||||
*/
|
||||
export default class EIP155Lib {
|
||||
wallet: Wallet
|
||||
|
||||
constructor(wallet: Wallet) {
|
||||
this.wallet = wallet
|
||||
}
|
||||
|
||||
static init({ mnemonic }: IInitArgs) {
|
||||
const wallet = mnemonic ? Wallet.fromMnemonic(mnemonic) : Wallet.createRandom()
|
||||
|
||||
return new EIP155Lib(wallet)
|
||||
}
|
||||
|
||||
getMnemonic() {
|
||||
return this.wallet.mnemonic.phrase
|
||||
}
|
||||
|
||||
getAddress() {
|
||||
return this.wallet.address
|
||||
}
|
||||
|
||||
signMessage(message: string) {
|
||||
return this.wallet.signMessage(message)
|
||||
}
|
||||
|
||||
_signTypedData(domain: any, types: any, data: any) {
|
||||
return this.wallet._signTypedData(domain, types, data)
|
||||
}
|
||||
|
||||
connect(provider: providers.JsonRpcProvider) {
|
||||
return this.wallet.connect(provider)
|
||||
}
|
||||
|
||||
signTransaction(transaction: providers.TransactionRequest) {
|
||||
return this.wallet.signTransaction(transaction)
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
import { Keypair } from '@solana/web3.js'
|
||||
import bs58 from 'bs58'
|
||||
import nacl from 'tweetnacl'
|
||||
import SolanaWallet, { SolanaSignTransaction } from 'solana-wallet'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface IInitArguments {
|
||||
secretKey?: Uint8Array
|
||||
}
|
||||
|
||||
/**
|
||||
* Library
|
||||
*/
|
||||
export default class SolanaLib {
|
||||
keypair: Keypair
|
||||
solanaWallet: SolanaWallet
|
||||
|
||||
constructor(keypair: Keypair) {
|
||||
this.keypair = keypair
|
||||
this.solanaWallet = new SolanaWallet(Buffer.from(keypair.secretKey))
|
||||
}
|
||||
|
||||
static init({ secretKey }: IInitArguments) {
|
||||
const keypair = secretKey ? Keypair.fromSecretKey(secretKey) : Keypair.generate()
|
||||
|
||||
return new SolanaLib(keypair)
|
||||
}
|
||||
|
||||
public async getAddress() {
|
||||
return await this.keypair.publicKey.toBase58()
|
||||
}
|
||||
|
||||
public getSecretKey() {
|
||||
return this.keypair.secretKey.toString()
|
||||
}
|
||||
|
||||
public async signMessage(message: string) {
|
||||
const signature = nacl.sign.detached(bs58.decode(message), this.keypair.secretKey)
|
||||
const bs58Signature = bs58.encode(signature)
|
||||
|
||||
return { signature: bs58Signature }
|
||||
}
|
||||
|
||||
public async signTransaction(
|
||||
feePayer: SolanaSignTransaction['feePayer'],
|
||||
recentBlockhash: SolanaSignTransaction['recentBlockhash'],
|
||||
instructions: SolanaSignTransaction['instructions'],
|
||||
partialSignatures?: SolanaSignTransaction['partialSignatures']
|
||||
) {
|
||||
const { signature } = await this.solanaWallet.signTransaction(feePayer, {
|
||||
feePayer,
|
||||
instructions,
|
||||
recentBlockhash,
|
||||
partialSignatures: partialSignatures ?? []
|
||||
})
|
||||
|
||||
return { signature }
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import Layout from '@/components/Layout'
|
||||
import Modal from '@/components/Modal'
|
||||
import { chatTheme } from '@/config/chatTheme'
|
||||
import useInitialization from '@/hooks/useInitialization'
|
||||
import useWalletConnectEventsManager from '@/hooks/useWalletConnectEventsManager'
|
||||
import { createTheme, NextUIProvider } from '@nextui-org/react'
|
||||
import { AppProps } from 'next/app'
|
||||
import { Fragment } from 'react'
|
||||
import '../../public/main.css'
|
||||
|
||||
const theme = createTheme({
|
||||
type: 'dark',
|
||||
theme: chatTheme
|
||||
})
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
// Step 1 - Initialize wallets and wallet connect client
|
||||
const initialized = useInitialization()
|
||||
|
||||
// Step 2 - Once initialized, set up wallet connect event manager
|
||||
useWalletConnectEventsManager(initialized)
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{/* Hacking around this issue with missing shim for `global -> globalThis` */}
|
||||
{/* https://github.com/webpack/webpack/issues/10035#issuecomment-603231120 */}
|
||||
<script>global = globalThis</script>
|
||||
<NextUIProvider theme={theme}>
|
||||
<Layout initialized={initialized}>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
|
||||
<Modal />
|
||||
</NextUIProvider>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
import { Fragment, useEffect, useRef, useState } from 'react'
|
||||
import { styled } from '@nextui-org/react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useSnapshot } from 'valtio'
|
||||
|
||||
import ChatboxInput from '@/components/ChatboxInput'
|
||||
import ChatMessage from '@/components/ChatMessage'
|
||||
import PageHeader from '@/components/PageHeader'
|
||||
import { demoAddressResolver } from '@/config/chatConstants'
|
||||
import SettingsStore from '@/store/SettingsStore'
|
||||
import { chatClient } from '@/utils/WalletConnectUtil'
|
||||
import { truncate } from '@/utils/HelperUtil'
|
||||
|
||||
const ChatContainer = styled('div', {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
flexGrow: 1,
|
||||
height: '84%',
|
||||
maxWidth: '100%'
|
||||
} as any)
|
||||
|
||||
const MessagesContainer = styled('div', {
|
||||
display: 'flex',
|
||||
flexGrow: 1,
|
||||
flexDirection: 'column',
|
||||
overflowY: 'scroll',
|
||||
padding: '10px'
|
||||
} as any)
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default function ChatPage() {
|
||||
const [topic, setTopic] = useState('')
|
||||
const [messages, setMessages] = useState<
|
||||
{
|
||||
message: string
|
||||
authorAccount: string
|
||||
}[]
|
||||
>([])
|
||||
const { eip155Address } = useSnapshot(SettingsStore.state)
|
||||
const { query } = useRouter()
|
||||
const lastMessageRef = useRef<null | HTMLDivElement>(null)
|
||||
|
||||
const fullEip155Address = `eip155:1:${eip155Address}`
|
||||
|
||||
async function onOutgoingMessage(outgoingMessage: string) {
|
||||
await chatClient.message({
|
||||
topic,
|
||||
|
||||
message: outgoingMessage,
|
||||
authorAccount: fullEip155Address,
|
||||
timestamp: Date.now()
|
||||
})
|
||||
|
||||
if (chatClient.getMessages({ topic }).length) {
|
||||
setMessages(chatClient.getMessages({ topic }))
|
||||
}
|
||||
}
|
||||
|
||||
function isOutgoingMessage(authorAccount: string) {
|
||||
return authorAccount === fullEip155Address
|
||||
}
|
||||
|
||||
function getChatTitle() {
|
||||
if (typeof query.peerAccount !== 'string') return ''
|
||||
|
||||
return demoAddressResolver[query.peerAccount] ?? truncate(query.peerAccount, 24)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (query?.topic) {
|
||||
setTopic(query.topic as string)
|
||||
}
|
||||
}, [query])
|
||||
|
||||
useEffect(() => {
|
||||
// Set existing messages on load.
|
||||
if (topic) {
|
||||
try {
|
||||
const messages = chatClient.getMessages({ topic })
|
||||
console.log('getMessages for topic: ', topic, messages)
|
||||
setMessages(messages)
|
||||
} catch (error) {}
|
||||
}
|
||||
}, [topic])
|
||||
|
||||
useEffect(() => {
|
||||
lastMessageRef.current?.scrollIntoView({ behavior: 'smooth' })
|
||||
}, [messages])
|
||||
|
||||
useEffect(() => {
|
||||
if (topic) {
|
||||
// Update local messages state on new message.
|
||||
chatClient.once('chat_message', eventArgs => {
|
||||
console.log('new chat message:', eventArgs)
|
||||
|
||||
setMessages(chatClient.getMessages({ topic }))
|
||||
})
|
||||
}
|
||||
}, [messages, topic])
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader title={getChatTitle()} backButtonHref="/chats" withBackButton />
|
||||
<ChatContainer>
|
||||
<MessagesContainer>
|
||||
{messages.map(({ message, authorAccount }, i) => (
|
||||
<ChatMessage
|
||||
key={i}
|
||||
message={message}
|
||||
messageType={isOutgoingMessage(authorAccount) ? 'outgoing' : 'incoming'}
|
||||
/>
|
||||
))}
|
||||
<div ref={lastMessageRef}></div>
|
||||
</MessagesContainer>
|
||||
<ChatboxInput handleSend={onOutgoingMessage} />
|
||||
</ChatContainer>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
import PageHeader from '@/components/PageHeader'
|
||||
import { Text } from '@nextui-org/react'
|
||||
import { Fragment, useEffect, useState } from 'react'
|
||||
import { chatClient } from '@/utils/WalletConnectUtil'
|
||||
import { ChatClientTypes } from '@walletconnect/chat-client'
|
||||
import ChatRequestCard from '@/components/ChatRequestCard'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import SettingsStore from '@/store/SettingsStore'
|
||||
|
||||
export default function ChatRequestsPage() {
|
||||
const router = useRouter()
|
||||
const [chatInvites, setChatInvites] = useState<ChatClientTypes.ReceivedInvite[]>([])
|
||||
|
||||
const { eip155Address } = useSnapshot(SettingsStore.state)
|
||||
|
||||
useEffect(() => {
|
||||
console.log(
|
||||
'setting invites:',
|
||||
chatClient.getReceivedInvites({ account: `eip155:1:${eip155Address}` })
|
||||
)
|
||||
|
||||
setChatInvites(chatClient.getReceivedInvites({ account: `eip155:1:${eip155Address}` }))
|
||||
}, [])
|
||||
|
||||
console.log('NEWINVITES:::::', chatInvites)
|
||||
|
||||
const acceptChatInvite = async (inviteId: number) => {
|
||||
await chatClient.accept({ id: inviteId })
|
||||
router.push('/chats')
|
||||
}
|
||||
const rejectChatInvite = async (inviteId: number) => {
|
||||
await chatClient.reject({ id: inviteId })
|
||||
router.push('/chats')
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader title="Chat Requests" withBackButton backButtonHref="/chats" />
|
||||
|
||||
{chatInvites.length > 0 ? (
|
||||
chatInvites.map(invite => {
|
||||
return (
|
||||
<ChatRequestCard
|
||||
account={eip155Address}
|
||||
key={invite.id}
|
||||
{...invite}
|
||||
onAccept={() => acceptChatInvite(Number(invite.id))}
|
||||
onReject={() => rejectChatInvite(Number(invite.id))}
|
||||
/>
|
||||
)
|
||||
})
|
||||
) : (
|
||||
<Text css={{ opacity: '0.5', textAlign: 'center', marginTop: '$20' }}>
|
||||
No chat requests
|
||||
</Text>
|
||||
)}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
import { Fragment, useCallback, useEffect, useState } from 'react'
|
||||
import { Row, Text } from '@nextui-org/react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { FiPlus } from 'react-icons/fi'
|
||||
import { useSnapshot } from 'valtio'
|
||||
|
||||
import ChatSummaryCard from '@/components/ChatSummaryCard'
|
||||
import PageHeader from '@/components/PageHeader'
|
||||
import ChatRequestsButton from '@/components/ChatRequestsButton'
|
||||
import { chatClient } from '@/utils/WalletConnectUtil'
|
||||
import ChatPrimaryCTAButton from '@/components/ChatPrimaryCTAButton'
|
||||
import SettingsStore from '@/store/SettingsStore'
|
||||
import { Web3Modal } from '@web3modal/standalone'
|
||||
import { HiQrcode } from 'react-icons/hi'
|
||||
|
||||
const web3modal = new Web3Modal({
|
||||
projectId: process.env.NEXT_PUBLIC_PROJECT_ID || '',
|
||||
walletConnectVersion: 1
|
||||
})
|
||||
|
||||
export default function ChatsPage() {
|
||||
const router = useRouter()
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
|
||||
const [chatThreads, setChatThreads] = useState<
|
||||
{ topic: string; selfAccount: string; peerAccount: string }[]
|
||||
>([])
|
||||
|
||||
const [chatInvites, setChatInvites] = useState<any[]>([])
|
||||
const { eip155Address } = useSnapshot(SettingsStore.state)
|
||||
|
||||
const inviteQrCode = useCallback(async () => {
|
||||
const idx = SettingsStore.state.account === 0 ? 1 : 0
|
||||
const uri = `${window.location.origin}/newChat?accountIndex=${idx}&target=eip155:1:${SettingsStore.state.eip155Address}`
|
||||
|
||||
web3modal.openModal({ uri })
|
||||
}, [])
|
||||
|
||||
const initChatClient = async () => {
|
||||
console.log(chatClient)
|
||||
|
||||
console.log(
|
||||
'chatInvites on load:',
|
||||
chatClient.chatReceivedInvites.getAll({ inviteeAccount: eip155Address })
|
||||
)
|
||||
console.log('chatThreads on load:', chatClient.chatThreads.getAll())
|
||||
console.log('chatMessages on load:', chatClient.chatMessages.getAll())
|
||||
setChatThreads(chatClient.chatThreads.getAll())
|
||||
setChatInvites(chatClient.getReceivedInvites({ account: `eip155:1:${eip155Address}` }))
|
||||
|
||||
chatClient.on('chat_invite', async args => {
|
||||
console.log('chat_invite:', args)
|
||||
web3modal.closeModal()
|
||||
setChatInvites(chatClient.getReceivedInvites({ account: `eip155:1:${eip155Address}` }))
|
||||
})
|
||||
|
||||
chatClient.on('chat_invite_accepted', async args => {
|
||||
console.log('chat_joined:', args)
|
||||
console.log(chatClient.chatThreads.getAll())
|
||||
setChatThreads(chatClient.chatThreads.getAll())
|
||||
})
|
||||
|
||||
setIsLoading(false)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
initChatClient()
|
||||
}, [])
|
||||
|
||||
console.log({ chatInvitesLength: chatInvites.length })
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader
|
||||
title="Chat"
|
||||
ctaButton={
|
||||
<Row justify="space-evenly">
|
||||
<ChatPrimaryCTAButton icon={<HiQrcode />} onClick={inviteQrCode} />
|
||||
<ChatPrimaryCTAButton icon={<FiPlus />} onClick={() => router.push('/newChat')} />
|
||||
</Row>
|
||||
}
|
||||
/>
|
||||
|
||||
<Row justify="center" align="center" css={{ paddingBottom: '$5' }}>
|
||||
{chatInvites.length ? <ChatRequestsButton requestCount={chatInvites.length} /> : null}
|
||||
{/* <ChatRequestsButton requestCount={chatInvites.length} /> */}
|
||||
</Row>
|
||||
|
||||
{isLoading ? (
|
||||
<Text css={{ opacity: '0.5', textAlign: 'center', marginTop: '$20' }}>
|
||||
Fetching chats...
|
||||
</Text>
|
||||
) : chatThreads.length ? (
|
||||
chatThreads.map(props => {
|
||||
return <ChatSummaryCard key={props.topic} {...props} />
|
||||
})
|
||||
) : (
|
||||
<Text css={{ opacity: '0.5', textAlign: 'center', marginTop: '$20' }}>No chats</Text>
|
||||
)}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
import AccountCard from '@/components/AccountCard'
|
||||
import AccountPicker from '@/components/AccountPicker'
|
||||
import PageHeader from '@/components/PageHeader'
|
||||
import { COSMOS_MAINNET_CHAINS } from '@/data/COSMOSData'
|
||||
import { EIP155_MAINNET_CHAINS, EIP155_TEST_CHAINS } from '@/data/EIP155Data'
|
||||
import { SOLANA_MAINNET_CHAINS, SOLANA_TEST_CHAINS } from '@/data/SolanaData'
|
||||
import SettingsStore from '@/store/SettingsStore'
|
||||
import { Text } from '@nextui-org/react'
|
||||
import { Fragment } from 'react'
|
||||
import { useSnapshot } from 'valtio'
|
||||
|
||||
export default function HomePage() {
|
||||
const { testNets, eip155Address, cosmosAddress, solanaAddress } = useSnapshot(SettingsStore.state)
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader title="Accounts">
|
||||
<AccountPicker />
|
||||
</PageHeader>
|
||||
<Text h4 css={{ marginBottom: '$5' }}>
|
||||
Mainnets
|
||||
</Text>
|
||||
{Object.entries(EIP155_MAINNET_CHAINS).map(([namespace, { name, logo, rgb }]) => (
|
||||
<AccountCard
|
||||
key={name}
|
||||
name={name}
|
||||
logo={logo}
|
||||
rgb={rgb}
|
||||
address={`${namespace}:${eip155Address}`}
|
||||
/>
|
||||
))}
|
||||
{Object.entries(COSMOS_MAINNET_CHAINS).map(([namespace, { name, logo, rgb }]) => (
|
||||
<AccountCard
|
||||
key={name}
|
||||
name={name}
|
||||
logo={logo}
|
||||
rgb={rgb}
|
||||
address={`${namespace}:${cosmosAddress}`}
|
||||
/>
|
||||
))}
|
||||
{Object.entries(SOLANA_MAINNET_CHAINS).map(([namespace, { name, logo, rgb }]) => (
|
||||
<AccountCard
|
||||
key={name}
|
||||
name={name}
|
||||
logo={logo}
|
||||
rgb={rgb}
|
||||
address={`${namespace}:${solanaAddress}`}
|
||||
/>
|
||||
))}
|
||||
|
||||
{testNets ? (
|
||||
<Fragment>
|
||||
<Text h4 css={{ marginBottom: '$5' }}>
|
||||
Testnets
|
||||
</Text>
|
||||
{Object.entries(EIP155_TEST_CHAINS).map(([namespace, { name, logo, rgb }]) => (
|
||||
<AccountCard
|
||||
key={name}
|
||||
name={name}
|
||||
logo={logo}
|
||||
rgb={rgb}
|
||||
address={`${namespace}:${eip155Address}`}
|
||||
/>
|
||||
))}
|
||||
{Object.entries(SOLANA_TEST_CHAINS).map(([namespace, { name, logo, rgb }]) => (
|
||||
<AccountCard
|
||||
key={name}
|
||||
name={name}
|
||||
logo={logo}
|
||||
rgb={rgb}
|
||||
address={`${namespace}:${solanaAddress}`}
|
||||
/>
|
||||
))}
|
||||
</Fragment>
|
||||
) : null}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import PageHeader from '@/components/PageHeader'
|
||||
import { Fragment, useEffect, useState } from 'react'
|
||||
|
||||
export default function InvitesPage() {
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader title="Chat Requests" />
|
||||
|
||||
{/* {chatThreads.length ? (
|
||||
chatThreads.map(props => {
|
||||
return <ChatSummaryCard key={props.topic} {...props} />
|
||||
})
|
||||
) : (
|
||||
<Text css={{ opacity: '0.5', textAlign: 'center', marginTop: '$20' }}>No chats</Text>
|
||||
)} */}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
import { Fragment, useCallback, useEffect, useState } from 'react'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { FiArrowRight } from 'react-icons/fi'
|
||||
import { Input, Row } from '@nextui-org/react'
|
||||
import PageHeader from '@/components/PageHeader'
|
||||
import { chatClient } from '@/utils/WalletConnectUtil'
|
||||
import { ChatClientTypes } from '@walletconnect/chat-client'
|
||||
import ChatPrimaryCTAButton from '@/components/ChatPrimaryCTAButton'
|
||||
import { demoContactsMap } from '@/config/chatConstants'
|
||||
import SettingsStore from '@/store/SettingsStore'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function NewChatPage() {
|
||||
const [address, setAddress] = useState('')
|
||||
const router = useRouter()
|
||||
|
||||
const { eip155Address } = useSnapshot(SettingsStore.state)
|
||||
|
||||
useEffect(() => {
|
||||
chatClient.once('chat_invite_accepted', args => {
|
||||
const newChatTarget = new URLSearchParams(document.location.search).get('target')
|
||||
router.push(`/chat?topic=${args.topic}&peerAccount=${newChatTarget}`)
|
||||
})
|
||||
}, [router])
|
||||
|
||||
const createInvite = useCallback(
|
||||
async (targetAddress: string) => {
|
||||
await chatClient.invite({
|
||||
inviteeAccount: targetAddress,
|
||||
inviterAccount: `eip155:1:${eip155Address}`,
|
||||
message: "hey let's message",
|
||||
inviteePublicKey: await chatClient.resolve({ account: targetAddress })
|
||||
})
|
||||
},
|
||||
[eip155Address]
|
||||
)
|
||||
|
||||
const onInvite = useCallback(
|
||||
async (addressToInvite: string) => {
|
||||
if (demoContactsMap[addressToInvite]) {
|
||||
await createInvite(demoContactsMap[addressToInvite])
|
||||
} else {
|
||||
console.log('onInvite: inviting address ', addressToInvite)
|
||||
await createInvite(addressToInvite)
|
||||
}
|
||||
setAddress('')
|
||||
},
|
||||
[setAddress, createInvite]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const newChatTarget = new URLSearchParams(document.location.search).get('target')
|
||||
if (newChatTarget) {
|
||||
setAddress(newChatTarget)
|
||||
onInvite(newChatTarget)
|
||||
}
|
||||
}, [onInvite, setAddress])
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader
|
||||
title="New Chat"
|
||||
withBackButton
|
||||
backButtonHref="/chats"
|
||||
ctaButton={
|
||||
<ChatPrimaryCTAButton icon={<FiArrowRight />} onClick={() => onInvite(address)} />
|
||||
}
|
||||
/>
|
||||
|
||||
<Row justify="center">
|
||||
<Input
|
||||
fullWidth
|
||||
animated={false}
|
||||
label="ENS Name or Address"
|
||||
placeholder="username.eth or 0x0..."
|
||||
value={address}
|
||||
onChange={e => {
|
||||
setAddress(e.target.value)
|
||||
}}
|
||||
css={{
|
||||
padding: '$5',
|
||||
background: '$gray800'
|
||||
}}
|
||||
/>
|
||||
</Row>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import PageHeader from '@/components/PageHeader'
|
||||
import PairingCard from '@/components/PairingCard'
|
||||
import { signClient } from '@/utils/WalletConnectUtil'
|
||||
import { Text } from '@nextui-org/react'
|
||||
import { getSdkError } from '@walletconnect/utils'
|
||||
import { Fragment, useState } from 'react'
|
||||
|
||||
export default function PairingsPage() {
|
||||
const [pairings, setPairings] = useState(signClient.pairing.values)
|
||||
|
||||
async function onDelete(topic: string) {
|
||||
await signClient.disconnect({ topic, reason: getSdkError('USER_DISCONNECTED') })
|
||||
const newPairings = pairings.filter(pairing => pairing.topic !== topic)
|
||||
setPairings(newPairings)
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader title="Pairings" />
|
||||
{pairings.length ? (
|
||||
pairings.map(pairing => {
|
||||
const { peerMetadata } = pairing
|
||||
|
||||
return (
|
||||
<PairingCard
|
||||
key={pairing.topic}
|
||||
logo={peerMetadata?.icons[0]}
|
||||
url={peerMetadata?.url}
|
||||
name={peerMetadata?.name}
|
||||
onDelete={() => onDelete(pairing.topic)}
|
||||
/>
|
||||
)
|
||||
})
|
||||
) : (
|
||||
<Text css={{ opacity: '0.5', textAlign: 'center', marginTop: '$20' }}>No pairings</Text>
|
||||
)}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
import PageHeader from '@/components/PageHeader'
|
||||
import ProjectInfoCard from '@/components/ProjectInfoCard'
|
||||
import SessionChainCard from '@/components/SessionChainCard'
|
||||
import { signClient } from '@/utils/WalletConnectUtil'
|
||||
import { Button, Divider, Loading, Row, Text } from '@nextui-org/react'
|
||||
import { getSdkError } from '@walletconnect/utils'
|
||||
import { useRouter } from 'next/router'
|
||||
import { Fragment, useEffect, useState } from 'react'
|
||||
|
||||
/**
|
||||
* Component
|
||||
*/
|
||||
export default function SessionPage() {
|
||||
const [topic, setTopic] = useState('')
|
||||
const [updated, setUpdated] = useState(new Date())
|
||||
const { query, replace } = useRouter()
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (query?.topic) {
|
||||
setTopic(query.topic as string)
|
||||
}
|
||||
}, [query])
|
||||
|
||||
const session = signClient.session.values.find(s => s.topic === topic)
|
||||
|
||||
if (!session) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Get necessary data from session
|
||||
const expiryDate = new Date(session.expiry * 1000)
|
||||
const { namespaces } = session
|
||||
|
||||
// Handle deletion of a session
|
||||
async function onDeleteSession() {
|
||||
setLoading(true)
|
||||
await signClient.disconnect({ topic, reason: getSdkError('USER_DISCONNECTED') })
|
||||
replace('/sessions')
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
async function onSessionPing() {
|
||||
setLoading(true)
|
||||
await signClient.ping({ topic })
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
async function onSessionEmit() {
|
||||
setLoading(true)
|
||||
console.log('baleg')
|
||||
await signClient.emit({
|
||||
topic,
|
||||
event: { name: 'chainChanged', data: 'Hello World' },
|
||||
chainId: 'eip155:1'
|
||||
})
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const newNs = {
|
||||
eip155: {
|
||||
accounts: [
|
||||
'eip155:1:0x70012948c348CBF00806A3C79E3c5DAdFaAa347B',
|
||||
'eip155:137:0x70012948c348CBF00806A3C79E3c5DAdFaAa347B'
|
||||
],
|
||||
methods: ['personal_sign', 'eth_signTypedData', 'eth_sendTransaction'],
|
||||
events: []
|
||||
}
|
||||
}
|
||||
|
||||
async function onSessionUpdate() {
|
||||
setLoading(true)
|
||||
const { acknowledged } = await signClient.update({ topic, namespaces: newNs })
|
||||
await acknowledged()
|
||||
setUpdated(new Date())
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
// function renderAccountSelection(chain: string) {
|
||||
// if (isEIP155Chain(chain)) {
|
||||
// return (
|
||||
// <ProposalSelectSection
|
||||
// addresses={eip155Addresses}
|
||||
// selectedAddresses={selectedAccounts[chain]}
|
||||
// onSelect={onSelectAccount}
|
||||
// chain={chain}
|
||||
// />
|
||||
// )
|
||||
// } else if (isCosmosChain(chain)) {
|
||||
// return (
|
||||
// <ProposalSelectSection
|
||||
// addresses={cosmosAddresses}
|
||||
// selectedAddresses={selectedAccounts[chain]}
|
||||
// onSelect={onSelectAccount}
|
||||
// chain={chain}
|
||||
// />
|
||||
// )
|
||||
// } else if (isSolanaChain(chain)) {
|
||||
// return (
|
||||
// <ProposalSelectSection
|
||||
// addresses={solanaAddresses}
|
||||
// selectedAddresses={selectedAccounts[chain]}
|
||||
// onSelect={onSelectAccount}
|
||||
// chain={chain}
|
||||
// />
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader title="Session Details" />
|
||||
|
||||
<ProjectInfoCard metadata={session.peer.metadata} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
{Object.keys(namespaces).map(chain => {
|
||||
return (
|
||||
<Fragment key={chain}>
|
||||
<Text h4 css={{ marginBottom: '$5' }}>{`Review ${chain} permissions`}</Text>
|
||||
<SessionChainCard namespace={namespaces[chain]} />
|
||||
{/* {renderAccountSelection(chain)} */}
|
||||
<Divider y={2} />
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
|
||||
<Row justify="space-between">
|
||||
<Text h5>Expiry</Text>
|
||||
<Text css={{ color: '$gray400' }}>{expiryDate.toDateString()}</Text>
|
||||
</Row>
|
||||
|
||||
<Row justify="space-between">
|
||||
<Text h5>Last Updated</Text>
|
||||
<Text css={{ color: '$gray400' }}>{updated.toDateString()}</Text>
|
||||
</Row>
|
||||
|
||||
<Row css={{ marginTop: '$10' }}>
|
||||
<Button flat css={{ width: '100%' }} color="error" onClick={onDeleteSession}>
|
||||
{loading ? <Loading size="sm" color="error" /> : 'Delete'}
|
||||
</Button>
|
||||
</Row>
|
||||
|
||||
<Row css={{ marginTop: '$10' }}>
|
||||
<Button flat css={{ width: '100%' }} color="primary" onClick={onSessionPing}>
|
||||
{loading ? <Loading size="sm" color="primary" /> : 'Ping'}
|
||||
</Button>
|
||||
</Row>
|
||||
|
||||
<Row css={{ marginTop: '$10' }}>
|
||||
<Button flat css={{ width: '100%' }} color="secondary" onClick={onSessionEmit}>
|
||||
{loading ? <Loading size="sm" color="secondary" /> : 'Emit'}
|
||||
</Button>
|
||||
</Row>
|
||||
|
||||
<Row css={{ marginTop: '$10' }}>
|
||||
<Button flat css={{ width: '100%' }} color="warning" onClick={onSessionUpdate}>
|
||||
{loading ? <Loading size="sm" color="warning" /> : 'Update'}
|
||||
</Button>
|
||||
</Row>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import PageHeader from '@/components/PageHeader'
|
||||
import SessionCard from '@/components/SessionCard'
|
||||
import { signClient } from '@/utils/WalletConnectUtil'
|
||||
import { Text } from '@nextui-org/react'
|
||||
import { Fragment, useState } from 'react'
|
||||
|
||||
export default function SessionsPage() {
|
||||
const [sessions, setSessions] = useState(signClient.session.values)
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader title="Sessions" />
|
||||
{sessions.length ? (
|
||||
sessions.map(session => {
|
||||
const { name, icons, url } = session.peer.metadata
|
||||
|
||||
return (
|
||||
<SessionCard
|
||||
key={session.topic}
|
||||
topic={session.topic}
|
||||
name={name}
|
||||
logo={icons[0]}
|
||||
url={url}
|
||||
/>
|
||||
)
|
||||
})
|
||||
) : (
|
||||
<Text css={{ opacity: '0.5', textAlign: 'center', marginTop: '$20' }}>No sessions</Text>
|
||||
)}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
import PageHeader from '@/components/PageHeader'
|
||||
import SettingsStore from '@/store/SettingsStore'
|
||||
import { cosmosWallets } from '@/utils/CosmosWalletUtil'
|
||||
import { eip155Wallets } from '@/utils/EIP155WalletUtil'
|
||||
import { solanaWallets } from '@/utils/SolanaWalletUtil'
|
||||
import { Card, Divider, Row, Switch, Text } from '@nextui-org/react'
|
||||
import { Fragment } from 'react'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import packageJSON from '../../package.json'
|
||||
|
||||
export default function SettingsPage() {
|
||||
const { testNets, eip155Address, cosmosAddress, solanaAddress } = useSnapshot(SettingsStore.state)
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader title="Settings" />
|
||||
|
||||
<Text h4 css={{ marginBottom: '$5' }}>
|
||||
Packages
|
||||
</Text>
|
||||
<Row justify="space-between" align="center">
|
||||
<Text color="$gray400">@walletconnect/sign-client</Text>
|
||||
<Text color="$gray400">{packageJSON.dependencies['@walletconnect/sign-client']}</Text>
|
||||
</Row>
|
||||
<Row justify="space-between" align="center">
|
||||
<Text color="$gray400">@walletconnect/utils</Text>
|
||||
<Text color="$gray400">{packageJSON.dependencies['@walletconnect/utils']}</Text>
|
||||
</Row>
|
||||
<Row justify="space-between" align="center">
|
||||
<Text color="$gray400">@walletconnect/types</Text>
|
||||
<Text color="$gray400">{packageJSON.devDependencies['@walletconnect/types']}</Text>
|
||||
</Row>
|
||||
<Row justify="space-between" align="center">
|
||||
<Text color="$gray400">@walletconnect/chat-client</Text>
|
||||
<Text color="$gray400">{packageJSON.dependencies['@walletconnect/chat-client']}</Text>
|
||||
</Row>
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<Text h4 css={{ marginBottom: '$5' }}>
|
||||
Testnets
|
||||
</Text>
|
||||
<Row justify="space-between" align="center">
|
||||
<Switch checked={testNets} onChange={SettingsStore.toggleTestNets} />
|
||||
<Text>{testNets ? 'Enabled' : 'Disabled'}</Text>
|
||||
</Row>
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<Text css={{ color: '$yellow500', marginBottom: '$5', textAlign: 'left', padding: 0 }}>
|
||||
Warning: mnemonics and secret keys are provided for development purposes only and should not
|
||||
be used elsewhere!
|
||||
</Text>
|
||||
|
||||
<Text h4 css={{ marginTop: '$5', marginBottom: '$5' }}>
|
||||
EIP155 Mnemonic
|
||||
</Text>
|
||||
<Card bordered borderWeight="light" css={{ minHeight: '100px' }}>
|
||||
<Text css={{ fontFamily: '$mono' }}>{eip155Wallets[eip155Address].getMnemonic()}</Text>
|
||||
</Card>
|
||||
|
||||
<Text h4 css={{ marginTop: '$10', marginBottom: '$5' }}>
|
||||
Cosmos Mnemonic
|
||||
</Text>
|
||||
<Card bordered borderWeight="light" css={{ minHeight: '100px' }}>
|
||||
<Text css={{ fontFamily: '$mono' }}>{cosmosWallets[cosmosAddress].getMnemonic()}</Text>
|
||||
</Card>
|
||||
|
||||
<Text h4 css={{ marginTop: '$10', marginBottom: '$5' }}>
|
||||
Solana Secret Key
|
||||
</Text>
|
||||
<Card bordered borderWeight="light" css={{ minHeight: '215px', wordWrap: 'break-word' }}>
|
||||
<Text css={{ fontFamily: '$mono' }}>{solanaWallets[solanaAddress].getSecretKey()}</Text>
|
||||
</Card>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import PageHeader from '@/components/PageHeader'
|
||||
import QrReader from '@/components/QrReader'
|
||||
import { signClient } from '@/utils/WalletConnectUtil'
|
||||
import { Button, Input, Loading, Text } from '@nextui-org/react'
|
||||
import { Fragment, useState } from 'react'
|
||||
|
||||
export default function WalletConnectPage() {
|
||||
const [uri, setUri] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
async function onConnect(uri: string) {
|
||||
try {
|
||||
setLoading(true)
|
||||
await signClient.pair({ uri })
|
||||
} catch (err: unknown) {
|
||||
alert(err)
|
||||
} finally {
|
||||
setUri('')
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageHeader title="WalletConnect" />
|
||||
|
||||
<QrReader onConnect={onConnect} />
|
||||
|
||||
<Text size={13} css={{ textAlign: 'center', marginTop: '$10', marginBottom: '$10' }}>
|
||||
or use walletconnect uri
|
||||
</Text>
|
||||
|
||||
<Input
|
||||
css={{ width: '100%' }}
|
||||
bordered
|
||||
aria-label="wc url connect input"
|
||||
placeholder="e.g. wc:a281567bb3e4..."
|
||||
onChange={e => setUri(e.target.value)}
|
||||
value={uri}
|
||||
contentRight={
|
||||
<Button
|
||||
size="xs"
|
||||
disabled={!uri}
|
||||
css={{ marginLeft: -60 }}
|
||||
onClick={() => onConnect(uri)}
|
||||
color="gradient"
|
||||
>
|
||||
{loading ? <Loading size="sm" /> : 'Connect'}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
import { SessionTypes, SignClientTypes } from '@walletconnect/types'
|
||||
import { proxy } from 'valtio'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface ModalData {
|
||||
proposal?: SignClientTypes.EventArguments['session_proposal']
|
||||
requestEvent?: SignClientTypes.EventArguments['session_request']
|
||||
requestSession?: SessionTypes.Struct
|
||||
}
|
||||
|
||||
interface State {
|
||||
open: boolean
|
||||
view?:
|
||||
| 'SessionProposalModal'
|
||||
| 'SessionSignModal'
|
||||
| 'SessionSignTypedDataModal'
|
||||
| 'SessionSendTransactionModal'
|
||||
| 'SessionUnsuportedMethodModal'
|
||||
| 'SessionSignCosmosModal'
|
||||
| 'SessionSignSolanaModal'
|
||||
data?: ModalData
|
||||
}
|
||||
|
||||
/**
|
||||
* State
|
||||
*/
|
||||
const state = proxy<State>({
|
||||
open: false
|
||||
})
|
||||
|
||||
/**
|
||||
* Store / Actions
|
||||
*/
|
||||
const ModalStore = {
|
||||
state,
|
||||
|
||||
open(view: State['view'], data: State['data']) {
|
||||
state.view = view
|
||||
state.data = data
|
||||
state.open = true
|
||||
},
|
||||
|
||||
close() {
|
||||
state.open = false
|
||||
}
|
||||
}
|
||||
|
||||
export default ModalStore
|
||||
@@ -1,57 +0,0 @@
|
||||
import { proxy } from 'valtio'
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
interface State {
|
||||
testNets: boolean
|
||||
account: number
|
||||
eip155Address: string
|
||||
cosmosAddress: string
|
||||
solanaAddress: string
|
||||
}
|
||||
|
||||
/**
|
||||
* State
|
||||
*/
|
||||
const state = proxy<State>({
|
||||
testNets: typeof localStorage !== 'undefined' ? Boolean(localStorage.getItem('TEST_NETS')) : true,
|
||||
account: 0,
|
||||
eip155Address: '',
|
||||
cosmosAddress: '',
|
||||
solanaAddress: ''
|
||||
})
|
||||
|
||||
/**
|
||||
* Store / Actions
|
||||
*/
|
||||
const SettingsStore = {
|
||||
state,
|
||||
|
||||
setAccount(value: number) {
|
||||
state.account = value
|
||||
},
|
||||
|
||||
setEIP155Address(eip155Address: string) {
|
||||
state.eip155Address = eip155Address
|
||||
},
|
||||
|
||||
setCosmosAddress(cosmosAddresses: string) {
|
||||
state.cosmosAddress = cosmosAddresses
|
||||
},
|
||||
|
||||
setSolanaAddress(solanaAddress: string) {
|
||||
state.solanaAddress = solanaAddress
|
||||
},
|
||||
|
||||
toggleTestNets() {
|
||||
state.testNets = !state.testNets
|
||||
if (state.testNets) {
|
||||
localStorage.setItem('TEST_NETS', 'YES')
|
||||
} else {
|
||||
localStorage.removeItem('TEST_NETS')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default SettingsStore
|
||||
@@ -1,40 +0,0 @@
|
||||
import { COSMOS_SIGNING_METHODS } from '@/data/COSMOSData'
|
||||
import { cosmosAddresses, cosmosWallets } from '@/utils/CosmosWalletUtil'
|
||||
import { getWalletAddressFromParams } from '@/utils/HelperUtil'
|
||||
import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils'
|
||||
import { SignClientTypes } from '@walletconnect/types'
|
||||
import { getSdkError } from '@walletconnect/utils'
|
||||
import { parseSignDocValues } from 'cosmos-wallet'
|
||||
|
||||
export async function approveCosmosRequest(
|
||||
requestEvent: SignClientTypes.EventArguments['session_request']
|
||||
) {
|
||||
const { params, id } = requestEvent
|
||||
const { request } = params
|
||||
const wallet = cosmosWallets[getWalletAddressFromParams(cosmosAddresses, params)]
|
||||
|
||||
switch (request.method) {
|
||||
case COSMOS_SIGNING_METHODS.COSMOS_SIGN_DIRECT:
|
||||
const signedDirect = await wallet.signDirect(
|
||||
request.params.signerAddress,
|
||||
parseSignDocValues(request.params.signDoc)
|
||||
)
|
||||
return formatJsonRpcResult(id, signedDirect.signature)
|
||||
|
||||
case COSMOS_SIGNING_METHODS.COSMOS_SIGN_AMINO:
|
||||
const signedAmino = await wallet.signAmino(
|
||||
request.params.signerAddress,
|
||||
request.params.signDoc
|
||||
)
|
||||
return formatJsonRpcResult(id, signedAmino.signature)
|
||||
|
||||
default:
|
||||
throw new Error(getSdkError('INVALID_METHOD').message)
|
||||
}
|
||||
}
|
||||
|
||||
export function rejectCosmosRequest(request: SignClientTypes.EventArguments['session_request']) {
|
||||
const { id } = request
|
||||
|
||||
return formatJsonRpcError(id, getSdkError('USER_REJECTED_METHODS').message)
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import CosmosLib from '@/lib/CosmosLib'
|
||||
|
||||
export let wallet1: CosmosLib
|
||||
export let wallet2: CosmosLib
|
||||
export let cosmosWallets: Record<string, CosmosLib>
|
||||
export let cosmosAddresses: string[]
|
||||
|
||||
let address1: string
|
||||
let address2: string
|
||||
|
||||
/**
|
||||
* Utilities
|
||||
*/
|
||||
export async function createOrRestoreCosmosWallet() {
|
||||
const mnemonic1 = localStorage.getItem('COSMOS_MNEMONIC_1')
|
||||
const mnemonic2 = localStorage.getItem('COSMOS_MNEMONIC_2')
|
||||
|
||||
if (mnemonic1 && mnemonic2) {
|
||||
wallet1 = await CosmosLib.init({ mnemonic: mnemonic1 })
|
||||
wallet2 = await CosmosLib.init({ mnemonic: mnemonic2 })
|
||||
} else {
|
||||
wallet1 = await CosmosLib.init({})
|
||||
wallet2 = await CosmosLib.init({})
|
||||
|
||||
// Don't store mnemonic in local storage in a production project!
|
||||
localStorage.setItem('COSMOS_MNEMONIC_1', wallet1.getMnemonic())
|
||||
localStorage.setItem('COSMOS_MNEMONIC_2', wallet2.getMnemonic())
|
||||
}
|
||||
|
||||
address1 = await wallet1.getAddress()
|
||||
address2 = await wallet2.getAddress()
|
||||
|
||||
cosmosWallets = {
|
||||
[address1]: wallet1,
|
||||
[address2]: wallet2
|
||||
}
|
||||
cosmosAddresses = Object.keys(cosmosWallets)
|
||||
|
||||
return {
|
||||
cosmosWallets,
|
||||
cosmosAddresses
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import { EIP155_CHAINS, EIP155_SIGNING_METHODS, TEIP155Chain } from '@/data/EIP155Data'
|
||||
import { eip155Addresses, eip155Wallets } from '@/utils/EIP155WalletUtil'
|
||||
import {
|
||||
getSignParamsMessage,
|
||||
getSignTypedDataParamsData,
|
||||
getWalletAddressFromParams
|
||||
} from '@/utils/HelperUtil'
|
||||
import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils'
|
||||
import { SignClientTypes } from '@walletconnect/types'
|
||||
import { getSdkError } from '@walletconnect/utils'
|
||||
import { providers } from 'ethers'
|
||||
|
||||
export async function approveEIP155Request(
|
||||
requestEvent: SignClientTypes.EventArguments['session_request']
|
||||
) {
|
||||
const { params, id } = requestEvent
|
||||
const { chainId, request } = params
|
||||
const wallet = eip155Wallets[getWalletAddressFromParams(eip155Addresses, params)]
|
||||
|
||||
switch (request.method) {
|
||||
case EIP155_SIGNING_METHODS.PERSONAL_SIGN:
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN:
|
||||
const message = getSignParamsMessage(request.params)
|
||||
const signedMessage = await wallet.signMessage(message)
|
||||
return formatJsonRpcResult(id, signedMessage)
|
||||
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA:
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V3:
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V4:
|
||||
const { domain, types, message: data } = getSignTypedDataParamsData(request.params)
|
||||
// https://github.com/ethers-io/ethers.js/issues/687#issuecomment-714069471
|
||||
delete types.EIP712Domain
|
||||
const signedData = await wallet._signTypedData(domain, types, data)
|
||||
return formatJsonRpcResult(id, signedData)
|
||||
|
||||
case EIP155_SIGNING_METHODS.ETH_SEND_TRANSACTION:
|
||||
const provider = new providers.JsonRpcProvider(EIP155_CHAINS[chainId as TEIP155Chain].rpc)
|
||||
const sendTransaction = request.params[0]
|
||||
const connectedWallet = wallet.connect(provider)
|
||||
const { hash } = await connectedWallet.sendTransaction(sendTransaction)
|
||||
return formatJsonRpcResult(id, hash)
|
||||
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN_TRANSACTION:
|
||||
const signTransaction = request.params[0]
|
||||
const signature = await wallet.signTransaction(signTransaction)
|
||||
return formatJsonRpcResult(id, signature)
|
||||
|
||||
default:
|
||||
throw new Error(getSdkError('INVALID_METHOD').message)
|
||||
}
|
||||
}
|
||||
|
||||
export function rejectEIP155Request(request: SignClientTypes.EventArguments['session_request']) {
|
||||
const { id } = request
|
||||
|
||||
return formatJsonRpcError(id, getSdkError('USER_REJECTED_METHODS').message)
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import EIP155Lib from '@/lib/EIP155Lib'
|
||||
|
||||
export let wallet1: EIP155Lib
|
||||
export let wallet2: EIP155Lib
|
||||
export let eip155Wallets: Record<string, EIP155Lib>
|
||||
export let eip155Addresses: string[]
|
||||
|
||||
let address1: string
|
||||
let address2: string
|
||||
|
||||
/**
|
||||
* Utilities
|
||||
*/
|
||||
export function createOrRestoreEIP155Wallet() {
|
||||
const mnemonic1 = localStorage.getItem('EIP155_MNEMONIC_1')
|
||||
const mnemonic2 = localStorage.getItem('EIP155_MNEMONIC_2')
|
||||
|
||||
if (mnemonic1 && mnemonic2) {
|
||||
wallet1 = EIP155Lib.init({ mnemonic: mnemonic1 })
|
||||
wallet2 = EIP155Lib.init({ mnemonic: mnemonic2 })
|
||||
} else {
|
||||
wallet1 = EIP155Lib.init({})
|
||||
wallet2 = EIP155Lib.init({})
|
||||
|
||||
// Don't store mnemonic in local storage in a production project!
|
||||
localStorage.setItem('EIP155_MNEMONIC_1', wallet1.getMnemonic())
|
||||
localStorage.setItem('EIP155_MNEMONIC_2', wallet2.getMnemonic())
|
||||
}
|
||||
|
||||
address1 = wallet1.getAddress()
|
||||
address2 = wallet2.getAddress()
|
||||
|
||||
eip155Wallets = {
|
||||
[address1]: wallet1,
|
||||
[address2]: wallet2
|
||||
}
|
||||
eip155Addresses = Object.keys(eip155Wallets)
|
||||
|
||||
return {
|
||||
eip155Wallets,
|
||||
eip155Addresses
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
import { COSMOS_MAINNET_CHAINS, TCosmosChain } from '@/data/COSMOSData'
|
||||
import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data'
|
||||
import { SOLANA_CHAINS, TSolanaChain } from '@/data/SolanaData'
|
||||
import { utils } from 'ethers'
|
||||
|
||||
/**
|
||||
* Truncates string (in the middle) via given lenght value
|
||||
*/
|
||||
export function truncate(value: string, length: number) {
|
||||
if (value?.length <= length) {
|
||||
return value
|
||||
}
|
||||
|
||||
const separator = '...'
|
||||
const stringLength = length - separator.length
|
||||
const frontLength = Math.ceil(stringLength / 2)
|
||||
const backLength = Math.floor(stringLength / 2)
|
||||
|
||||
return value.substring(0, frontLength) + separator + value.substring(value.length - backLength)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts hex to utf8 string if it is valid bytes
|
||||
*/
|
||||
export function convertHexToUtf8(value: string) {
|
||||
if (utils.isHexString(value)) {
|
||||
return utils.toUtf8String(value)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets message from various signing request methods by filtering out
|
||||
* a value that is not an address (thus is a message).
|
||||
* If it is a hex string, it gets converted to utf8 string
|
||||
*/
|
||||
export function getSignParamsMessage(params: string[]) {
|
||||
const message = params.filter(p => !utils.isAddress(p))[0]
|
||||
|
||||
return convertHexToUtf8(message)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data from various signTypedData request methods by filtering out
|
||||
* a value that is not an address (thus is data).
|
||||
* If data is a string convert it to object
|
||||
*/
|
||||
export function getSignTypedDataParamsData(params: string[]) {
|
||||
const data = params.filter(p => !utils.isAddress(p))[0]
|
||||
|
||||
if (typeof data === 'string') {
|
||||
return JSON.parse(data)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
/**
|
||||
* Get our address from params checking if params string contains one
|
||||
* of our wallet addresses
|
||||
*/
|
||||
export function getWalletAddressFromParams(addresses: string[], params: any) {
|
||||
const paramsString = JSON.stringify(params)
|
||||
let address = ''
|
||||
|
||||
addresses.forEach(addr => {
|
||||
if (paramsString.includes(addr)) {
|
||||
address = addr
|
||||
}
|
||||
})
|
||||
|
||||
return address
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if chain is part of EIP155 standard
|
||||
*/
|
||||
export function isEIP155Chain(chain: string) {
|
||||
return chain.includes('eip155')
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if chain is part of COSMOS standard
|
||||
*/
|
||||
export function isCosmosChain(chain: string) {
|
||||
return chain.includes('cosmos')
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if chain is part of SOLANA standard
|
||||
*/
|
||||
export function isSolanaChain(chain: string) {
|
||||
return chain.includes('solana')
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats chainId to its name
|
||||
*/
|
||||
export function formatChainName(chainId: string) {
|
||||
return (
|
||||
EIP155_CHAINS[chainId as TEIP155Chain]?.name ??
|
||||
COSMOS_MAINNET_CHAINS[chainId as TCosmosChain]?.name ??
|
||||
SOLANA_CHAINS[chainId as TSolanaChain]?.name ??
|
||||
chainId
|
||||
)
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import { SOLANA_SIGNING_METHODS } from '@/data/SolanaData'
|
||||
import { getWalletAddressFromParams } from '@/utils/HelperUtil'
|
||||
import { solanaAddresses, solanaWallets } from '@/utils/SolanaWalletUtil'
|
||||
import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils'
|
||||
import { SignClientTypes } from '@walletconnect/types'
|
||||
import { getSdkError } from '@walletconnect/utils'
|
||||
|
||||
export async function approveSolanaRequest(
|
||||
requestEvent: SignClientTypes.EventArguments['session_request']
|
||||
) {
|
||||
const { params, id } = requestEvent
|
||||
const { request } = params
|
||||
const wallet = solanaWallets[getWalletAddressFromParams(solanaAddresses, params)]
|
||||
|
||||
switch (request.method) {
|
||||
case SOLANA_SIGNING_METHODS.SOLANA_SIGN_MESSAGE:
|
||||
const signedMessage = await wallet.signMessage(request.params.message)
|
||||
return formatJsonRpcResult(id, signedMessage)
|
||||
|
||||
case SOLANA_SIGNING_METHODS.SOLANA_SIGN_TRANSACTION:
|
||||
const signedTransaction = await wallet.signTransaction(
|
||||
request.params.feePayer,
|
||||
request.params.recentBlockhash,
|
||||
request.params.instructions
|
||||
)
|
||||
|
||||
return formatJsonRpcResult(id, signedTransaction)
|
||||
|
||||
default:
|
||||
throw new Error(getSdkError('INVALID_METHOD').message)
|
||||
}
|
||||
}
|
||||
|
||||
export function rejectSolanaRequest(request: SignClientTypes.EventArguments['session_request']) {
|
||||
const { id } = request
|
||||
|
||||
return formatJsonRpcError(id, getSdkError('USER_REJECTED_METHODS').message)
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import SolanaLib from '@/lib/SolanaLib'
|
||||
|
||||
export let wallet1: SolanaLib
|
||||
export let wallet2: SolanaLib
|
||||
export let solanaWallets: Record<string, SolanaLib>
|
||||
export let solanaAddresses: string[]
|
||||
|
||||
let address1: string
|
||||
let address2: string
|
||||
|
||||
/**
|
||||
* Utilities
|
||||
*/
|
||||
export async function createOrRestoreSolanaWallet() {
|
||||
const secretKey1 = localStorage.getItem('SOLANA_SECRET_KEY_1')
|
||||
const secretKey2 = localStorage.getItem('SOLANA_SECRET_KEY_2')
|
||||
|
||||
if (secretKey1 && secretKey2) {
|
||||
const secretArray1: number[] = Object.values(JSON.parse(secretKey1))
|
||||
const secretArray2: number[] = Object.values(JSON.parse(secretKey2))
|
||||
wallet1 = SolanaLib.init({ secretKey: Uint8Array.from(secretArray1) })
|
||||
wallet2 = SolanaLib.init({ secretKey: Uint8Array.from(secretArray2) })
|
||||
} else {
|
||||
wallet1 = SolanaLib.init({})
|
||||
wallet2 = SolanaLib.init({})
|
||||
|
||||
// Don't store secretKey in local storage in a production project!
|
||||
localStorage.setItem(
|
||||
'SOLANA_SECRET_KEY_1',
|
||||
JSON.stringify(Array.from(wallet1.keypair.secretKey))
|
||||
)
|
||||
localStorage.setItem(
|
||||
'SOLANA_SECRET_KEY_2',
|
||||
JSON.stringify(Array.from(wallet2.keypair.secretKey))
|
||||
)
|
||||
}
|
||||
|
||||
address1 = await wallet1.getAddress()
|
||||
address2 = await wallet2.getAddress()
|
||||
|
||||
solanaWallets = {
|
||||
[address1]: wallet1,
|
||||
[address2]: wallet2
|
||||
}
|
||||
solanaAddresses = Object.keys(solanaWallets)
|
||||
|
||||
return {
|
||||
solanaWallets,
|
||||
solanaAddresses
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import SignClient from '@walletconnect/sign-client'
|
||||
import { ChatClient, IChatClient } from '@walletconnect/chat-client'
|
||||
import { ISyncClient, SyncClient, SyncStore } from '@walletconnect/sync-client'
|
||||
import { Core } from '@walletconnect/core'
|
||||
|
||||
export let signClient: SignClient
|
||||
export let chatClient: IChatClient
|
||||
export let syncClient: ISyncClient
|
||||
|
||||
export async function createSignClient() {
|
||||
signClient = await SignClient.init({
|
||||
projectId: process.env.NEXT_PUBLIC_PROJECT_ID,
|
||||
relayUrl: process.env.NEXT_PUBLIC_RELAY_URL ?? 'wss://relay.walletconnect.com',
|
||||
metadata: {
|
||||
name: 'React Wallet',
|
||||
description: 'React Wallet for WalletConnect',
|
||||
url: 'https://walletconnect.com/',
|
||||
icons: ['https://avatars.githubusercontent.com/u/37784886']
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// FIXME: update relayUrl here to not hardcode local relay.
|
||||
export async function createChatClient() {
|
||||
const projectId = process.env.NEXT_PUBLIC_PROJECT_ID
|
||||
|
||||
const core = new Core({ projectId })
|
||||
|
||||
syncClient = await SyncClient.init({
|
||||
core,
|
||||
projectId,
|
||||
relayUrl: process.env.NEXT_PUBLIC_RELAY_URL ?? 'wss://relay.walletconnect.com'
|
||||
})
|
||||
|
||||
chatClient = await ChatClient.init({
|
||||
logger: 'debug',
|
||||
keyserverUrl: 'https://keys.walletconnect.com',
|
||||
projectId: projectId ?? '',
|
||||
relayUrl: process.env.NEXT_PUBLIC_RELAY_URL ?? 'wss://relay.walletconnect.com',
|
||||
syncClient,
|
||||
SyncStoreController: SyncStore
|
||||
})
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
import ProjectInfoCard from '@/components/ProjectInfoCard'
|
||||
import ProposalSelectSection from '@/components/ProposalSelectSection'
|
||||
import RequestModalContainer from '@/components/RequestModalContainer'
|
||||
import SessionProposalChainCard from '@/components/SessionProposalChainCard'
|
||||
import ModalStore from '@/store/ModalStore'
|
||||
import { cosmosAddresses } from '@/utils/CosmosWalletUtil'
|
||||
import { eip155Addresses } from '@/utils/EIP155WalletUtil'
|
||||
import { isCosmosChain, isEIP155Chain, isSolanaChain } from '@/utils/HelperUtil'
|
||||
import { solanaAddresses } from '@/utils/SolanaWalletUtil'
|
||||
import { signClient } from '@/utils/WalletConnectUtil'
|
||||
import { Button, Divider, Modal, Text } from '@nextui-org/react'
|
||||
import { SessionTypes } from '@walletconnect/types'
|
||||
import { getSdkError } from '@walletconnect/utils'
|
||||
import { Fragment, useState } from 'react'
|
||||
|
||||
export default function SessionProposalModal() {
|
||||
const [selectedAccounts, setSelectedAccounts] = useState<Record<string, string[]>>({})
|
||||
const hasSelected = Object.keys(selectedAccounts).length
|
||||
|
||||
// Get proposal data and wallet address from store
|
||||
const proposal = ModalStore.state.data?.proposal
|
||||
|
||||
// Ensure proposal is defined
|
||||
if (!proposal) {
|
||||
return <Text>Missing proposal data</Text>
|
||||
}
|
||||
|
||||
// Get required proposal data
|
||||
const { id, params } = proposal
|
||||
const { proposer, requiredNamespaces, relays } = params
|
||||
|
||||
// Add / remove address from EIP155 selection
|
||||
function onSelectAccount(chain: string, account: string) {
|
||||
if (selectedAccounts[chain]?.includes(account)) {
|
||||
const newSelectedAccounts = selectedAccounts[chain]?.filter(a => a !== account)
|
||||
setSelectedAccounts(prev => ({
|
||||
...prev,
|
||||
[chain]: newSelectedAccounts
|
||||
}))
|
||||
} else {
|
||||
const prevChainAddresses = selectedAccounts[chain] ?? []
|
||||
setSelectedAccounts(prev => ({
|
||||
...prev,
|
||||
[chain]: [...prevChainAddresses, account]
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
// Hanlde approve action, construct session namespace
|
||||
async function onApprove() {
|
||||
if (proposal) {
|
||||
const namespaces: SessionTypes.Namespaces = {}
|
||||
Object.keys(requiredNamespaces).forEach(key => {
|
||||
const accounts: string[] = []
|
||||
requiredNamespaces[key].chains?.map(chain => {
|
||||
selectedAccounts[key].map(acc => accounts.push(`${chain}:${acc}`))
|
||||
})
|
||||
namespaces[key] = {
|
||||
accounts,
|
||||
methods: requiredNamespaces[key].methods,
|
||||
events: requiredNamespaces[key].events
|
||||
}
|
||||
})
|
||||
|
||||
const { acknowledged } = await signClient.approve({
|
||||
id,
|
||||
relayProtocol: relays[0].protocol,
|
||||
namespaces
|
||||
})
|
||||
await acknowledged()
|
||||
}
|
||||
ModalStore.close()
|
||||
}
|
||||
|
||||
// Hanlde reject action
|
||||
async function onReject() {
|
||||
if (proposal) {
|
||||
await signClient.reject({
|
||||
id,
|
||||
reason: getSdkError('USER_REJECTED_METHODS')
|
||||
})
|
||||
}
|
||||
ModalStore.close()
|
||||
}
|
||||
|
||||
// Render account selection checkboxes based on chain
|
||||
function renderAccountSelection(chain: string) {
|
||||
if (isEIP155Chain(chain)) {
|
||||
return (
|
||||
<ProposalSelectSection
|
||||
addresses={eip155Addresses}
|
||||
selectedAddresses={selectedAccounts[chain]}
|
||||
onSelect={onSelectAccount}
|
||||
chain={chain}
|
||||
/>
|
||||
)
|
||||
} else if (isCosmosChain(chain)) {
|
||||
return (
|
||||
<ProposalSelectSection
|
||||
addresses={cosmosAddresses}
|
||||
selectedAddresses={selectedAccounts[chain]}
|
||||
onSelect={onSelectAccount}
|
||||
chain={chain}
|
||||
/>
|
||||
)
|
||||
} else if (isSolanaChain(chain)) {
|
||||
return (
|
||||
<ProposalSelectSection
|
||||
addresses={solanaAddresses}
|
||||
selectedAddresses={selectedAccounts[chain]}
|
||||
onSelect={onSelectAccount}
|
||||
chain={chain}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<RequestModalContainer title="Session Proposal">
|
||||
<ProjectInfoCard metadata={proposer.metadata} />
|
||||
|
||||
{/* TODO(ilja) Relays selection */}
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
{Object.keys(requiredNamespaces).map(chain => {
|
||||
return (
|
||||
<Fragment key={chain}>
|
||||
<Text h4 css={{ marginBottom: '$5' }}>{`Review ${chain} permissions`}</Text>
|
||||
<SessionProposalChainCard requiredNamespace={requiredNamespaces[chain]} />
|
||||
{renderAccountSelection(chain)}
|
||||
<Divider y={2} />
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
</RequestModalContainer>
|
||||
|
||||
<Modal.Footer>
|
||||
<Button auto flat color="error" onClick={onReject}>
|
||||
Reject
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
auto
|
||||
flat
|
||||
color="success"
|
||||
onClick={onApprove}
|
||||
disabled={!hasSelected}
|
||||
css={{ opacity: hasSelected ? 1 : 0.4 }}
|
||||
>
|
||||
Approve
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
import ProjectInfoCard from '@/components/ProjectInfoCard'
|
||||
import RequestDataCard from '@/components/RequestDataCard'
|
||||
import RequesDetailsCard from '@/components/RequestDetalilsCard'
|
||||
import RequestMethodCard from '@/components/RequestMethodCard'
|
||||
import RequestModalContainer from '@/components/RequestModalContainer'
|
||||
import ModalStore from '@/store/ModalStore'
|
||||
import { approveEIP155Request, rejectEIP155Request } from '@/utils/EIP155RequestHandlerUtil'
|
||||
import { signClient } from '@/utils/WalletConnectUtil'
|
||||
import { Button, Divider, Loading, Modal, Text } from '@nextui-org/react'
|
||||
import { Fragment, useState } from 'react'
|
||||
|
||||
export default function SessionSendTransactionModal() {
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
// Get request and wallet data from store
|
||||
const requestEvent = ModalStore.state.data?.requestEvent
|
||||
const requestSession = ModalStore.state.data?.requestSession
|
||||
|
||||
// Ensure request and wallet are defined
|
||||
if (!requestEvent || !requestSession) {
|
||||
return <Text>Missing request data</Text>
|
||||
}
|
||||
|
||||
// Get required proposal data
|
||||
|
||||
const { topic, params } = requestEvent
|
||||
const { request, chainId } = params
|
||||
const transaction = request.params[0]
|
||||
|
||||
// Handle approve action
|
||||
async function onApprove() {
|
||||
if (requestEvent) {
|
||||
setLoading(true)
|
||||
const response = await approveEIP155Request(requestEvent)
|
||||
await signClient.respond({
|
||||
topic,
|
||||
response
|
||||
})
|
||||
ModalStore.close()
|
||||
}
|
||||
}
|
||||
|
||||
// Handle reject action
|
||||
async function onReject() {
|
||||
if (requestEvent) {
|
||||
const response = rejectEIP155Request(requestEvent)
|
||||
await signClient.respond({
|
||||
topic,
|
||||
response
|
||||
})
|
||||
ModalStore.close()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<RequestModalContainer title="Send / Sign Transaction">
|
||||
<ProjectInfoCard metadata={requestSession.peer.metadata} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<RequestDataCard data={transaction} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<RequesDetailsCard chains={[chainId ?? '']} protocol={requestSession.relay.protocol} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<RequestMethodCard methods={[request.method]} />
|
||||
</RequestModalContainer>
|
||||
|
||||
<Modal.Footer>
|
||||
<Button auto flat color="error" onClick={onReject} disabled={loading}>
|
||||
Reject
|
||||
</Button>
|
||||
<Button auto flat color="success" onClick={onApprove} disabled={loading}>
|
||||
{loading ? <Loading size="sm" color="success" /> : 'Approve'}
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
import ProjectInfoCard from '@/components/ProjectInfoCard'
|
||||
import RequestDataCard from '@/components/RequestDataCard'
|
||||
import RequesDetailsCard from '@/components/RequestDetalilsCard'
|
||||
import RequestMethodCard from '@/components/RequestMethodCard'
|
||||
import RequestModalContainer from '@/components/RequestModalContainer'
|
||||
import ModalStore from '@/store/ModalStore'
|
||||
import { approveCosmosRequest, rejectCosmosRequest } from '@/utils/CosmosRequestHandler'
|
||||
import { signClient } from '@/utils/WalletConnectUtil'
|
||||
import { Button, Divider, Modal, Text } from '@nextui-org/react'
|
||||
import { Fragment } from 'react'
|
||||
|
||||
export default function SessionSignCosmosModal() {
|
||||
// Get request and wallet data from store
|
||||
const requestEvent = ModalStore.state.data?.requestEvent
|
||||
const requestSession = ModalStore.state.data?.requestSession
|
||||
|
||||
// Ensure request and wallet are defined
|
||||
if (!requestEvent || !requestSession) {
|
||||
return <Text>Missing request data</Text>
|
||||
}
|
||||
|
||||
// Get required request data
|
||||
const { topic, params } = requestEvent
|
||||
const { chainId, request } = params
|
||||
|
||||
// Handle approve action (logic varies based on request method)
|
||||
async function onApprove() {
|
||||
if (requestEvent) {
|
||||
const response = await approveCosmosRequest(requestEvent)
|
||||
await signClient.respond({
|
||||
topic,
|
||||
response
|
||||
})
|
||||
ModalStore.close()
|
||||
}
|
||||
}
|
||||
|
||||
// Handle reject action
|
||||
async function onReject() {
|
||||
if (requestEvent) {
|
||||
const response = rejectCosmosRequest(requestEvent)
|
||||
await signClient.respond({
|
||||
topic,
|
||||
response
|
||||
})
|
||||
ModalStore.close()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<RequestModalContainer title="Sign Message">
|
||||
<ProjectInfoCard metadata={requestSession.peer.metadata} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<RequesDetailsCard chains={[chainId ?? '']} protocol={requestSession.relay.protocol} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<RequestDataCard data={params} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<RequestMethodCard methods={[request.method]} />
|
||||
</RequestModalContainer>
|
||||
|
||||
<Modal.Footer>
|
||||
<Button auto flat color="error" onClick={onReject}>
|
||||
Reject
|
||||
</Button>
|
||||
<Button auto flat color="success" onClick={onApprove}>
|
||||
Approve
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
import ProjectInfoCard from '@/components/ProjectInfoCard'
|
||||
import RequesDetailsCard from '@/components/RequestDetalilsCard'
|
||||
import RequestMethodCard from '@/components/RequestMethodCard'
|
||||
import RequestModalContainer from '@/components/RequestModalContainer'
|
||||
import ModalStore from '@/store/ModalStore'
|
||||
import { approveEIP155Request, rejectEIP155Request } from '@/utils/EIP155RequestHandlerUtil'
|
||||
import { getSignParamsMessage } from '@/utils/HelperUtil'
|
||||
import { signClient } from '@/utils/WalletConnectUtil'
|
||||
import { Button, Col, Divider, Modal, Row, Text } from '@nextui-org/react'
|
||||
import { Fragment } from 'react'
|
||||
|
||||
export default function SessionSignModal() {
|
||||
// Get request and wallet data from store
|
||||
const requestEvent = ModalStore.state.data?.requestEvent
|
||||
const requestSession = ModalStore.state.data?.requestSession
|
||||
|
||||
// Ensure request and wallet are defined
|
||||
if (!requestEvent || !requestSession) {
|
||||
return <Text>Missing request data</Text>
|
||||
}
|
||||
|
||||
// Get required request data
|
||||
const { topic, params } = requestEvent
|
||||
const { request, chainId } = params
|
||||
|
||||
// Get message, convert it to UTF8 string if it is valid hex
|
||||
const message = getSignParamsMessage(request.params)
|
||||
|
||||
// Handle approve action (logic varies based on request method)
|
||||
async function onApprove() {
|
||||
if (requestEvent) {
|
||||
const response = await approveEIP155Request(requestEvent)
|
||||
await signClient.respond({
|
||||
topic,
|
||||
response
|
||||
})
|
||||
ModalStore.close()
|
||||
}
|
||||
}
|
||||
|
||||
// Handle reject action
|
||||
async function onReject() {
|
||||
if (requestEvent) {
|
||||
const response = rejectEIP155Request(requestEvent)
|
||||
await signClient.respond({
|
||||
topic,
|
||||
response
|
||||
})
|
||||
ModalStore.close()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<RequestModalContainer title="Sign Message">
|
||||
<ProjectInfoCard metadata={requestSession.peer.metadata} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<RequesDetailsCard chains={[chainId ?? '']} protocol={requestSession.relay.protocol} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h5>Message</Text>
|
||||
<Text color="$gray400">{message}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<RequestMethodCard methods={[request.method]} />
|
||||
</RequestModalContainer>
|
||||
|
||||
<Modal.Footer>
|
||||
<Button auto flat color="error" onClick={onReject}>
|
||||
Reject
|
||||
</Button>
|
||||
<Button auto flat color="success" onClick={onApprove}>
|
||||
Approve
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
import ProjectInfoCard from '@/components/ProjectInfoCard'
|
||||
import RequestDataCard from '@/components/RequestDataCard'
|
||||
import RequesDetailsCard from '@/components/RequestDetalilsCard'
|
||||
import RequestMethodCard from '@/components/RequestMethodCard'
|
||||
import RequestModalContainer from '@/components/RequestModalContainer'
|
||||
import ModalStore from '@/store/ModalStore'
|
||||
import { approveSolanaRequest, rejectSolanaRequest } from '@/utils/SolanaRequestHandlerUtil'
|
||||
import { signClient } from '@/utils/WalletConnectUtil'
|
||||
import { Button, Divider, Modal, Text } from '@nextui-org/react'
|
||||
import { Fragment } from 'react'
|
||||
|
||||
export default function SessionSignSolanaModal() {
|
||||
// Get request and wallet data from store
|
||||
const requestEvent = ModalStore.state.data?.requestEvent
|
||||
const requestSession = ModalStore.state.data?.requestSession
|
||||
|
||||
// Ensure request and wallet are defined
|
||||
if (!requestEvent || !requestSession) {
|
||||
return <Text>Missing request data</Text>
|
||||
}
|
||||
|
||||
// Get required request data
|
||||
const { topic, params } = requestEvent
|
||||
const { request, chainId } = params
|
||||
|
||||
// Handle approve action (logic varies based on request method)
|
||||
async function onApprove() {
|
||||
if (requestEvent) {
|
||||
const response = await approveSolanaRequest(requestEvent)
|
||||
await signClient.respond({
|
||||
topic,
|
||||
response
|
||||
})
|
||||
ModalStore.close()
|
||||
}
|
||||
}
|
||||
|
||||
// Handle reject action
|
||||
async function onReject() {
|
||||
if (requestEvent) {
|
||||
const response = rejectSolanaRequest(requestEvent)
|
||||
await signClient.respond({
|
||||
topic,
|
||||
response
|
||||
})
|
||||
ModalStore.close()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<RequestModalContainer title="Sign Message">
|
||||
<ProjectInfoCard metadata={requestSession.peer.metadata} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<RequesDetailsCard chains={[chainId ?? '']} protocol={requestSession.relay.protocol} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<RequestDataCard data={params} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<RequestMethodCard methods={[request.method]} />
|
||||
</RequestModalContainer>
|
||||
|
||||
<Modal.Footer>
|
||||
<Button auto flat color="error" onClick={onReject}>
|
||||
Reject
|
||||
</Button>
|
||||
<Button auto flat color="success" onClick={onApprove}>
|
||||
Approve
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
import ProjectInfoCard from '@/components/ProjectInfoCard'
|
||||
import RequestDataCard from '@/components/RequestDataCard'
|
||||
import RequesDetailsCard from '@/components/RequestDetalilsCard'
|
||||
import RequestMethodCard from '@/components/RequestMethodCard'
|
||||
import RequestModalContainer from '@/components/RequestModalContainer'
|
||||
import ModalStore from '@/store/ModalStore'
|
||||
import { approveEIP155Request, rejectEIP155Request } from '@/utils/EIP155RequestHandlerUtil'
|
||||
import { getSignTypedDataParamsData } from '@/utils/HelperUtil'
|
||||
import { signClient } from '@/utils/WalletConnectUtil'
|
||||
import { Button, Divider, Modal, Text } from '@nextui-org/react'
|
||||
import { Fragment } from 'react'
|
||||
|
||||
export default function SessionSignTypedDataModal() {
|
||||
// Get request and wallet data from store
|
||||
const requestEvent = ModalStore.state.data?.requestEvent
|
||||
const requestSession = ModalStore.state.data?.requestSession
|
||||
|
||||
// Ensure request and wallet are defined
|
||||
if (!requestEvent || !requestSession) {
|
||||
return <Text>Missing request data</Text>
|
||||
}
|
||||
|
||||
// Get required request data
|
||||
const { topic, params } = requestEvent
|
||||
const { request, chainId } = params
|
||||
|
||||
// Get data
|
||||
const data = getSignTypedDataParamsData(request.params)
|
||||
|
||||
// Handle approve action (logic varies based on request method)
|
||||
async function onApprove() {
|
||||
if (requestEvent) {
|
||||
const response = await approveEIP155Request(requestEvent)
|
||||
await signClient.respond({
|
||||
topic,
|
||||
response
|
||||
})
|
||||
ModalStore.close()
|
||||
}
|
||||
}
|
||||
|
||||
// Handle reject action
|
||||
async function onReject() {
|
||||
if (requestEvent) {
|
||||
const response = rejectEIP155Request(requestEvent)
|
||||
await signClient.respond({
|
||||
topic,
|
||||
response
|
||||
})
|
||||
ModalStore.close()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<RequestModalContainer title="Sign Typed Data">
|
||||
<ProjectInfoCard metadata={requestSession.peer.metadata} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<RequesDetailsCard chains={[chainId ?? '']} protocol={requestSession.relay.protocol} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<RequestDataCard data={data} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<RequestMethodCard methods={[request.method]} />
|
||||
</RequestModalContainer>
|
||||
|
||||
<Modal.Footer>
|
||||
<Button auto flat color="error" onClick={onReject}>
|
||||
Reject
|
||||
</Button>
|
||||
<Button auto flat color="success" onClick={onApprove}>
|
||||
Approve
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import ProjectInfoCard from '@/components/ProjectInfoCard'
|
||||
import RequesDetailsCard from '@/components/RequestDetalilsCard'
|
||||
import RequestMethodCard from '@/components/RequestMethodCard'
|
||||
import RequestModalContainer from '@/components/RequestModalContainer'
|
||||
import ModalStore from '@/store/ModalStore'
|
||||
import { Button, Divider, Modal, Text } from '@nextui-org/react'
|
||||
import { Fragment } from 'react'
|
||||
|
||||
export default function SessionUnsuportedMethodModal() {
|
||||
// Get request and wallet data from store
|
||||
const requestEvent = ModalStore.state.data?.requestEvent
|
||||
const requestSession = ModalStore.state.data?.requestSession
|
||||
|
||||
// Ensure request and wallet are defined
|
||||
if (!requestEvent || !requestSession) {
|
||||
return <Text>Missing request data</Text>
|
||||
}
|
||||
|
||||
// Get required request data
|
||||
const { topic, params } = requestEvent
|
||||
const { chainId, request } = params
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<RequestModalContainer title="Unsuported Method">
|
||||
<ProjectInfoCard metadata={requestSession.peer.metadata} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<RequesDetailsCard chains={[chainId ?? '']} protocol={requestSession.relay.protocol} />
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<RequestMethodCard methods={[request.method]} />
|
||||
</RequestModalContainer>
|
||||
|
||||
<Modal.Footer>
|
||||
<Button auto flat color="error" onClick={ModalStore.close}>
|
||||
Close
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"incremental": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||