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}`}
+
+
+
+
+
+ ID |
+ Reputation |
+
+
+
+ {members.filter((x) => !!x).map((member) => (
+
+ {member.id} |
+ {member.reputation.toString()} |
+
+ ))}
+
+
+
+ {' '}
+ Posts
+
+
+
+
+ {`Posts count: ${posts.length}`}
+
+
+
+
+
+ ID |
+ Authors |
+ Sender |
+ Reputation |
+ Actions |
+
+
+
+ {posts.filter((x) => !!x).map((post) => (
+
+ {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}`}
+
+
+
+
+
+ ID |
+ Post ID |
+ Sender |
+ Fee |
+ Binding |
+ Quorum |
+ WinRatio |
+
+ Redistribute
+
+ Losing Stakes
+ |
+ Duration |
+ End Time |
+
+ Stake
+
+ Count
+ |
+ Status |
+ Actions |
+
+
+
+ {validationPools.filter((x) => !!x).map((pool) => (
+
+ {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