diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 0462be5..f2c824b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@helia/dag-json": "^3.0.2", "@libp2p/websockets": "^8.0.16", + "@matrix-widget-toolkit/api": "^3.3.1", "@matrix-widget-toolkit/mui": "^1.2.1", "@matrix-widget-toolkit/react": "^1.0.6", "@metamask/eth-sig-util": "^7.0.1", @@ -29,6 +30,7 @@ "react": "^18.2.0", "react-bootstrap": "^2.10.1", "react-dom": "^18.2.0", + "react-router-dom": "^6.23.0", "web3": "^4.6.0" }, "devDependencies": { @@ -247,9 +249,9 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.0.tgz", - "integrity": "sha512-QAH+vfvts51BCsNZ2PhY6HAggnlS6omLLFTsIpeqZk/MmJ6cW7tgz5yRv0fMJThcr6FmbMrENh1RgrWPTYA76g==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz", + "integrity": "sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ==", "peer": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", @@ -257,7 +259,7 @@ "@babel/helper-function-name": "^7.23.0", "@babel/helper-member-expression-to-functions": "^7.23.0", "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-replace-supers": "^7.24.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", "semver": "^6.3.1" @@ -412,13 +414,13 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", - "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", + "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", "peer": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-member-expression-to-functions": "^7.23.0", "@babel/helper-optimise-call-expression": "^7.22.5" }, "engines": { @@ -1652,12 +1654,12 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.23.3.tgz", - "integrity": "sha512-GnvhtVfA2OAtzdX58FJxU19rhoGeQzyVndw3GgtdECQvQFXPEZIOVULHVZGAYmOgmqjXpVpfocAbSjh99V/Fqw==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.1.tgz", + "integrity": "sha512-mvoQg2f9p2qlpDQRBC7M3c3XTr0k7cp/0+kFKKO/7Gtu0LSw16eKB+Fabe2bDT/UpsyasTBBkAnbdsLrkD5XMw==", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -7865,6 +7867,14 @@ "react-native": "*" } }, + "node_modules/@remix-run/router": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.0.tgz", + "integrity": "sha512-Quz1KOffeEf/zwkCBM3kBtH4ZoZ+pT3xIXBG4PPW/XFtDP7EGhtTiC2+gpL9GnR7+Qdet5Oa6cYSvwKYg6kN9Q==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@restart/hooks": { "version": "0.4.16", "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", @@ -10203,9 +10213,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001588", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001588.tgz", - "integrity": "sha512-+hVY9jE44uKLkH0SrUTqxjxqNTOWHsbnQDIKjwkZ3lNTzUUVdBLBGXtj/q5Mp5u98r3droaZAewQuEDzjQdZlQ==", + "version": "1.0.30001612", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", + "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", "funding": [ { "type": "opencollective", @@ -10619,6 +10629,20 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/copy-to-clipboard": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", @@ -10854,6 +10878,57 @@ "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/datastore-core": { "version": "9.2.9", "resolved": "https://registry.npmjs.org/datastore-core/-/datastore-core-9.2.9.tgz", @@ -12207,18 +12282,22 @@ } }, "node_modules/es-abstract": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.4.tgz", - "integrity": "sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg==", + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.6", + "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.2", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", "get-intrinsic": "^1.2.4", @@ -12226,15 +12305,16 @@ "globalthis": "^1.0.3", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.1", + "has-proto": "^1.0.3", "has-symbols": "^1.0.3", - "hasown": "^2.0.1", + "hasown": "^2.0.2", "internal-slot": "^1.0.7", "is-array-buffer": "^3.0.4", "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", + "is-shared-array-buffer": "^1.0.3", "is-string": "^1.0.7", "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", @@ -12242,17 +12322,17 @@ "object-keys": "^1.1.1", "object.assign": "^4.1.5", "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.0", + "safe-array-concat": "^1.1.2", "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.1", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.14" + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" @@ -12312,6 +12392,18 @@ "node": ">= 0.4" } }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-set-tostringtag": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", @@ -13711,9 +13803,9 @@ "integrity": "sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A==" }, "node_modules/hasown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", - "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { "function-bind": "^1.1.2" }, @@ -17700,6 +17792,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-date-object": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", @@ -18064,6 +18171,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true, + "optional": true, + "peer": true + }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -19336,6 +19451,73 @@ "node": ">=0.10" } }, + "node_modules/less": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less/node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/less/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/less/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/level": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/level/-/level-8.0.1.tgz", @@ -20853,6 +21035,24 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/needle": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz", + "integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -21669,6 +21869,17 @@ "node": ">=4" } }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -22772,6 +22983,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.0.tgz", + "integrity": "sha512-wPMZ8S2TuPadH0sF5irFGjkNLIcRvOSaEe7v+JER8508dyJumm6XZB1u5kztlX0RVq6AzRVndzqcUh6sFIauzA==", + "dependencies": { + "@remix-run/router": "1.16.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.0.tgz", + "integrity": "sha512-Q9YaSYvubwgbal2c9DJKfx6hTNoBp3iJDsl+Duva/DwxoJH+OTXkxGpql4iUK2sla/8z4RpjAm6EWx1qUDuopQ==", + "dependencies": { + "@remix-run/router": "1.16.0", + "react-router": "6.23.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-shallow-renderer": { "version": "16.15.0", "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", @@ -23279,13 +23520,13 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", - "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, @@ -23966,14 +24207,15 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -23983,28 +24225,31 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -24485,9 +24730,9 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.5.tgz", - "integrity": "sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dev": true, "dependencies": { "call-bind": "^1.0.7", @@ -24515,16 +24760,16 @@ "integrity": "sha512-vjMKrfSoUDN8/Vnqitw2FmstOfuJ73G6CrSEKnf11A6RmasVxHqfeBcnTb6RsL4pTMuV5Zsv9IiHRphMZyckUw==" }, "node_modules/typescript": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", - "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=14.17" + "node": ">=4.2.0" } }, "node_modules/uint8-varint": { @@ -25311,15 +25556,15 @@ "peer": true }, "node_modules/which-typed-array": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz", - "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dependencies": { - "available-typed-arrays": "^1.0.6", - "call-bind": "^1.0.5", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.1" + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" diff --git a/frontend/package.json b/frontend/package.json index a0ccf06..95bbf41 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,6 +12,7 @@ "dependencies": { "@helia/dag-json": "^3.0.2", "@libp2p/websockets": "^8.0.16", + "@matrix-widget-toolkit/api": "^3.3.1", "@matrix-widget-toolkit/mui": "^1.2.1", "@matrix-widget-toolkit/react": "^1.0.6", "@metamask/eth-sig-util": "^7.0.1", @@ -31,6 +32,7 @@ "react": "^18.2.0", "react-bootstrap": "^2.10.1", "react-dom": "^18.2.0", + "react-router-dom": "^6.23.0", "web3": "^4.6.0" }, "devDependencies": { diff --git a/frontend/src/WebApp.jsx b/frontend/src/WebApp.jsx new file mode 100644 index 0000000..576e406 --- /dev/null +++ b/frontend/src/WebApp.jsx @@ -0,0 +1,593 @@ +import { + useCallback, useEffect, useState, useMemo, useRef, +} from 'react'; +import { useSDK } from '@metamask/sdk-react'; +import { Web3 } from 'web3'; +import Button from 'react-bootstrap/Button'; +import Tab from 'react-bootstrap/Tab'; +import Tabs from 'react-bootstrap/Tabs'; +import Container from 'react-bootstrap/Container'; +import Row from 'react-bootstrap/Row'; +import Col from 'react-bootstrap/Col'; +import Stack from 'react-bootstrap/Stack'; + +import useList from './utils/List'; +import { getContractAddressByChainId } from './utils/contract-config'; +import Web3Context from './contexts/Web3Context'; +import DAOArtifact from '../contractArtifacts/DAO.json'; +import Work1Artifact from '../contractArtifacts/Work1.json'; +import OnboardingArtifact from '../contractArtifacts/Onboarding.json'; +import WorkContract from './components/work-contracts/WorkContract'; +import AddPostModal from './components/posts/AddPostModal'; +import ViewPostModal from './components/posts/ViewPostModal'; +import Post from './utils/Post'; +import Proposals from './components/Proposals'; +import ImportPaper from './components/ImportPaper'; +import ImportPapersByAuthor from './components/ImportPapersByAuthor'; +import getAddressName from './utils/get-address-name'; + +function WebApp() { + const { + sdk, connected, provider, chainId, account, balance, + } = useSDK(); + + const DAORef = useRef(); + const workRef = useRef(); + const onboardingRef = useRef(); + const [DAO, setDAO] = useState(); + const [work1, setWork1] = useState(); + const [onboarding, setOnboarding] = useState(); + const [balanceEther, setBalanceEther] = useState(); + const [reputation, setReputation] = useState(); + const [totalReputation, setTotalReputation] = useState(); + const [members, dispatchMember] = useList(); + const [posts, dispatchPost] = useList(); + const [validationPools, dispatchValidationPool] = useList(); + const [showAddPost, setShowAddPost] = useState(false); + const [showViewPost, setShowViewPost] = useState(false); + const [viewPost, setViewPost] = useState({}); + const web3ProviderValue = useMemo(() => ({ + provider, + DAO, + work1, + onboarding, + reputation, + setReputation, + account, + chainId, + posts, + DAORef, + workRef, + onboardingRef, + }), [ + provider, DAO, work1, onboarding, reputation, setReputation, account, chainId, posts, + DAORef, workRef, onboardingRef]); + + useEffect(() => { + if (!provider || balance === undefined) return; + const web3 = new Web3(provider); + setBalanceEther(web3.utils.fromWei(balance, 'ether')); + }, [provider, balance]); + + /* -------------------------------------------------------------------------------- */ + /* --------------------------- BEGIN FETCHERS ------------------------------------- */ + /* -------------------------------------------------------------------------------- */ + + const fetchReputation = useCallback(async () => { + setReputation(await DAORef.current.methods.balanceOf(account).call()); + setTotalReputation(await DAORef.current.methods.totalSupply().call()); + }, [DAORef, account]); + + const fetchPost = useCallback(async (postId) => { + const post = await DAORef.current.methods.posts(postId).call(); + post.authors = await DAORef.current.methods.getPostAuthors(postId).call(); + dispatchPost({ type: 'updateById', item: post }); + return post; + }, [DAORef, dispatchPost]); + + const fetchPostId = useCallback(async (postIndex) => { + const postId = await DAORef.current.methods.postIds(postIndex).call(); + return postId; + }, [DAORef]); + + const fetchPosts = useCallback(async () => { + const count = await DAORef.current.methods.postCount().call(); + let promises = []; + dispatchPost({ type: 'refresh' }); + for (let i = 0; i < count; i += 1) { + promises.push(fetchPostId(i)); + } + const postIds = await Promise.all(promises); + promises = []; + postIds.forEach((postId) => { + promises.push(fetchPost(postId)); + }); + }, [DAORef, dispatchPost, fetchPost, fetchPostId]); + + const fetchValidationPool = useCallback(async (poolIndex) => { + const getPoolStatus = (pool) => { + if (pool.resolved) { + return pool.outcome ? 'Accepted' : 'Rejected'; + } + return pool.timeRemaining > 0 ? 'In Progress' : 'Ready to Evaluate'; + }; + const pool = await DAORef.current.methods.validationPools(poolIndex).call(); + pool.id = Number(pool.id); + pool.timeRemaining = new Date(Number(pool.endTime) * 1000) - new Date(); + pool.status = getPoolStatus(pool); + dispatchValidationPool({ type: 'update', item: pool }); + + // When remaing time expires, we want to update the status for this pool + if (pool.timeRemaining > 0) { + setTimeout(() => { + pool.timeRemaining = 0; + pool.status = getPoolStatus(pool); + dispatchValidationPool({ type: 'update', item: pool }); + }, pool.timeRemaining); + } + }, [DAORef, dispatchValidationPool]); + + const fetchValidationPools = useCallback(async () => { + // TODO: Pagination + // TODO: Memoization + // TODO: Caching + const count = await DAORef.current.methods.validationPoolCount().call(); + const promises = []; + dispatchValidationPool({ type: 'refresh' }); + for (let i = 0; i < count; i += 1) { + promises.push(fetchValidationPool(i)); + } + await Promise.all(promises); + }, [DAORef, dispatchValidationPool, fetchValidationPool]); + + const fetchMember = useCallback(async (memberIndex) => { + const id = await DAORef.current.methods.members(memberIndex).call(); + const member = { id }; + member.reputation = await DAORef.current.methods.balanceOf(id).call(); + dispatchMember({ type: 'updateById', item: member }); + return member; + }, [DAORef, dispatchMember]); + + const fetchMembers = useCallback(async () => { + const count = await DAORef.current.methods.memberCount().call(); + const promises = []; + dispatchMember({ type: 'refresh' }); + for (let i = 0; i < count; i += 1) { + promises.push(fetchMember(i)); + } + await Promise.all(promises); + }, [DAORef, dispatchMember, fetchMember]); + + /* -------------------------------------------------------------------------------- */ + /* --------------------------- END FETCHERS --------------------------------------- */ + /* -------------------------------------------------------------------------------- */ + // In this effect, we initialize everything and add contract event listeners. + useEffect(() => { + if (!provider || !chainId || !account || balance === undefined) return () => {}; + const DAOAddress = getContractAddressByChainId(chainId, 'DAO'); + const Work1Address = getContractAddressByChainId(chainId, 'Work1'); + const OnboardingAddress = getContractAddressByChainId(chainId, 'Onboarding'); + const web3 = new Web3(provider); + const DAOContract = new web3.eth.Contract(DAOArtifact.abi, DAOAddress); + const Work1Contract = new web3.eth.Contract(Work1Artifact.abi, Work1Address); + const OnboardingContract = new web3.eth.Contract(OnboardingArtifact.abi, OnboardingAddress); + DAORef.current = DAOContract; + workRef.current = Work1Contract; + onboardingRef.current = OnboardingContract; + + fetchReputation(); + fetchMembers(); + fetchPosts(); + fetchValidationPools(); + + setDAO(DAOContract); + setWork1(Work1Contract); + setOnboarding(OnboardingContract); + + // const fetchReputationInterval = setInterval(() => { + // // console.log('reputation', reputation); + // if (reputation !== undefined) { + // clearInterval(fetchReputationInterval); + // return; + // } + // fetchReputation(); + // }, 1000); + + /* -------------------------------------------------------------------------------- */ + /* --------------------------- BEGIN EVENT HANDLERS ------------------------------- */ + /* -------------------------------------------------------------------------------- */ + + DAOContract.events.PostAdded({ fromBlock: 'latest' }).on('data', (event) => { + console.log('event: post added'); + fetchPost(event.returnValues.id); + }); + + DAOContract.events.ValidationPoolInitiated({ fromBlock: 'latest' }).on('data', (event) => { + console.log('event: validation pool initiated'); + fetchValidationPool(event.returnValues.poolIndex); + }); + + DAOContract.events.ValidationPoolResolved({ fromBlock: 'latest' }).on('data', (event) => { + console.log('event: validation pool resolved'); + fetchReputation(); + fetchValidationPool(event.returnValues.poolIndex); + fetchMembers(); + }); + + Work1Contract.events.AvailabilityStaked({ fromBlock: 'latest' }).on('data', () => { + fetchReputation(); + }); + + OnboardingContract.events.AvailabilityStaked({ fromBlock: 'latest' }).on('data', () => { + fetchReputation(); + }); + + return () => { + DAOContract.events.PostAdded().off(); + DAOContract.events.ValidationPoolInitiated().off(); + DAOContract.events.ValidationPoolResolved().off(); + Work1Contract.events.AvailabilityStaked().off(); + OnboardingContract.events.AvailabilityStaked().off(); + }; + }, [provider, account, chainId, balance, dispatchValidationPool, dispatchPost, reputation, + DAORef, workRef, onboardingRef, + fetchPost, fetchPosts, fetchReputation, fetchValidationPool, fetchValidationPools, fetchMembers, + ]); + + /* -------------------------------------------------------------------------------- */ + /* --------------------------- END MAIN INITIALIZION EFFECT ----------------------- */ + /* -------------------------------------------------------------------------------- */ + + // useEffect(() => { + // // api.requestCapability(MatrixCapabilities.) + // api.on('action:m.message', (ev) => { + // console.log('action:m.message', ev); + // }); + // api.start(); + // }, []); + + /* -------------------------------------------------------------------------------- */ + /* --------------------------- BEGIN UI ACTIONS ----------------------------------- */ + /* -------------------------------------------------------------------------------- */ + + const connect = useCallback(async () => { + try { + await sdk?.connect(); + } catch (err) { + console.warn('failed to connect..', err); + } + }, [sdk]); + + const disconnect = useCallback(async () => { + try { + sdk?.terminate(); + } catch (err) { + console.warn('failed to disconnect..', err); + } + }, [sdk]); + + const watchReputationToken = useCallback(async () => { + await provider.request({ + method: 'wallet_watchAsset', + params: { + type: 'ERC20', + options: { + address: getContractAddressByChainId(chainId, 'DAO'), + }, + }, + }); + }, [provider, chainId]); + + const initiateValidationPool = useCallback(async (postId, poolDuration) => { + const web3 = new Web3(provider); + await DAO.methods.initiateValidationPool( + postId, + poolDuration ?? 3600, + [1, 3], + [1, 2], + 100, + true, + false, + web3.eth.abi.encodeParameter('bytes', '0x00'), + ).send({ + from: account, + gas: 1000000, + value: 10000, + }); + }, [provider, DAO, account]); + + const stake = useCallback(async (poolIndex, amount, inFavor) => { + console.log(`Attempting to stake ${amount} ${inFavor ? 'for' : 'against'} pool ${poolIndex}`); + await DAO.methods.stakeOnValidationPool(poolIndex, amount, inFavor).send({ + from: account, + gas: 999999, + }); + + // Since this is the result we expect from the server, we preemptively set it here. + // We can let this value be negative -- this would just mean we'll be getting + // at least one error from the server, and a corrected reputation. + setReputation((current) => current - BigInt(amount)); + }, [DAO, account, setReputation]); + + const stakeHalfInFavor = useCallback(async (poolIndex) => { + await stake(poolIndex, reputation / BigInt(2), true); + }, [stake, reputation]); + + const evaluateOutcome = useCallback(async (poolIndex) => { + await DAO.methods.evaluateOutcome(poolIndex).send({ + from: account, + gas: 10000000, + }); + }, [DAO, account]); + + const handleShowAddPost = () => setShowAddPost(true); + + const handleShowViewPost = useCallback(async ({ id }) => { + const post = await Post.read(id); + setViewPost(post); + setShowViewPost(true); + }, [setViewPost, setShowViewPost]); + + /* -------------------------------------------------------------------------------- */ + /* --------------------------- END UI ACTIONS ------------------------------------- */ + /* -------------------------------------------------------------------------------- */ + + return ( + + + + + + + {!connected && } + + {connected && ( + <> + + + + {chainId !== '0xaa36a7' && ( +
+ Please switch MetaMask to Sepolia testnet! +
+ + )} + +
+ + + +
+ {chainId && `Chain ID: ${chainId}`} +
+
+ {`Account: ${account}`} +
+
+ {`Balance: ${balanceEther} ETH`} +
+
+ + + +
+ {`Your REP: ${reputation?.toString()}`} +
+
+ {`Total REP: ${totalReputation?.toString()}`} +
+
+ + +
+
+ +
+
+ + +

Members

+
+ {`Members count: ${members.length}`} +
+
+ + + + + + + + + {members.filter((x) => !!x).map((member) => ( + + + + + ))} + +
IDReputation
{member.id}{member.reputation.toString()}
+
+ {' '} +

Posts

+
+ +
+
+ {`Posts count: ${posts.length}`} +
+
+ + + + + + + + + + + + {posts.filter((x) => !!x).map((post) => ( + + + + + + + + ))} + +
IDAuthorsSenderReputationActions
{post.id.toString()} + + {post.authors.map(({ authorAddress, weightPPM }) => ( +
+ {getAddressName(chainId, authorAddress)} + {' '} + {Number(weightPPM) / 10000} + % +
+ ))} +
+
{getAddressName(chainId, post.sender)}{post.reputation.toString()} + + {' '} + Initiate Validation Pool + {' '} + + {' '} + + {' '} + +
+
+

Validation Pools

+
+ {`Validation Pool Count: ${validationPools.length}`} +
+
+ + + + + + + + + + + + + + + + + + + + {validationPools.filter((x) => !!x).map((pool) => ( + + + + + + + + + + + + + + + + ))} + +
IDPost IDSenderFeeBindingQuorumWinRatio + Redistribute +
+ Losing Stakes +
DurationEnd Time + Stake +
+ Count +
StatusActions
{pool.id.toString()}{pool.postId}{getAddressName(chainId, pool.sender)}{pool.fee.toString()} + {pool.params.bindingPercent.toString()} + % + {`${pool.params.quorum[0].toString()}/${pool.params.quorum[1].toString()}`}{`${pool.params.winRatio[0].toString()}/${pool.params.winRatio[1].toString()}`}{pool.params.redistributeLosingStakes.toString()}{pool.params.duration.toString()}{new Date(Number(pool.endTime) * 1000).toLocaleString()}{pool.stakeCount.toString()}{pool.status} + {!pool.resolved && reputation > 0 && pool.timeRemaining > 0 && ( + <> + + {' '} + + {' '} + + )} + {!pool.resolved && (pool.timeRemaining <= 0 || !reputation) && ( + + )} +
+
+
+ + {work1 && ( + + )} + {onboarding && ( + + )} + + + {work1 && ( + + )} + + + + + +

Semantic Scholar Import

+ + +
+
+ + )} +
+ ); +} + +export default WebApp; diff --git a/frontend/src/App.jsx b/frontend/src/Widget.jsx similarity index 97% rename from frontend/src/App.jsx rename to frontend/src/Widget.jsx index ac1e370..eb6833a 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/Widget.jsx @@ -10,11 +10,10 @@ import Container from 'react-bootstrap/Container'; import Row from 'react-bootstrap/Row'; import Col from 'react-bootstrap/Col'; import Stack from 'react-bootstrap/Stack'; -import { EventDirection, WidgetEventCapability } from 'matrix-widget-api'; -import { MuiCapabilitiesGuard } from '@matrix-widget-toolkit/mui'; -import { useWidgetApi } from '@matrix-widget-toolkit/react'; +// import { EventDirection, WidgetEventCapability } from 'matrix-widget-api'; +// import { MuiCapabilitiesGuard } from '@matrix-widget-toolkit/mui'; +// import { useWidgetApi } from '@matrix-widget-toolkit/react'; -import './App.css'; import useList from './utils/List'; import { getContractAddressByChainId } from './utils/contract-config'; import Web3Context from './contexts/Web3Context'; @@ -30,7 +29,7 @@ import ImportPaper from './components/ImportPaper'; import ImportPapersByAuthor from './components/ImportPapersByAuthor'; import getAddressName from './utils/get-address-name'; -function App() { +function Widget() { const { sdk, connected, provider, chainId, account, balance, } = useSDK(); @@ -50,7 +49,7 @@ function App() { const [showAddPost, setShowAddPost] = useState(false); const [showViewPost, setShowViewPost] = useState(false); const [viewPost, setViewPost] = useState({}); - const widgetApi = useWidgetApi(); + // const widgetApi = useWidgetApi(); const web3ProviderValue = useMemo(() => ({ provider, DAO, @@ -334,15 +333,15 @@ function App() { }, [setViewPost, setShowViewPost]); // TODO: Sign and send a message to the forum-api bot / to a room in matrix - const registerMatrixIdentity = async () => { - await widgetApi.requestCapabilities([ - WidgetEventCapability.forRoomEvent( - EventDirection.Send, - 'm.message', - ), - ]); - widgetApi.sendRoomEvent('m.message', 'test message'); - }; + // const registerMatrixIdentity = async () => { + // await widgetApi.requestCapabilities([ + // WidgetEventCapability.forRoomEvent( + // EventDirection.Send, + // 'm.message', + // ), + // ]); + // widgetApi.sendRoomEvent('m.message', 'test message'); + // }; /* -------------------------------------------------------------------------------- */ /* --------------------------- END UI ACTIONS ------------------------------------- */ @@ -395,6 +394,7 @@ function App() {
+ {/* + */}
@@ -618,4 +619,4 @@ function App() { ); } -export default App; +export default Widget; diff --git a/frontend/src/main.jsx b/frontend/src/main.jsx index f2ed655..e7a883a 100644 --- a/frontend/src/main.jsx +++ b/frontend/src/main.jsx @@ -1,9 +1,29 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import { MetaMaskProvider } from '@metamask/sdk-react'; -import App from './App'; -// import 'bootstrap/dist/css/bootstrap.min.css'; import 'bootswatch/dist/slate/bootstrap.min.css'; +import './App.css'; +import { + createBrowserRouter, + RouterProvider, +} from 'react-router-dom'; +import { WidgetApiImpl } from '@matrix-widget-toolkit/api'; + +import WebApp from './WebApp'; +import Widget from './Widget'; + +window.widgetApiPromise = WidgetApiImpl.create(); + +const router = createBrowserRouter([ + { + path: '/', + element: , + }, + { + path: 'widget/', + element: , + }, +]); ReactDOM.createRoot(document.getElementById('root')).render( @@ -15,13 +35,12 @@ ReactDOM.createRoot(document.getElementById('root')).render( url: window.location.href, }, enableAnalytics: false, - // infuraAPIKey: '579d264c5f534aa1aefd6be323cb1a35', readonlyRPCMap: { '0x539': 'http://127.0.0.1:8545/', }, }} > - + , ); diff --git a/frontend/theme.config b/frontend/theme.config new file mode 100644 index 0000000..e69de29