require signatures for posts to API
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 39s Details

This commit is contained in:
Ladd Hoffman 2024-03-20 16:30:27 -05:00
parent e5d502beab
commit 956aa9728e
10 changed files with 400 additions and 279 deletions

View File

@ -1,5 +1,8 @@
const express = require('express');
const { Level } = require('level');
const { recoverPersonalSignature } = require('@metamask/eth-sig-util');
// const { ecrecover, fromRpcSig, pubToAddress } = require('@ethereumjs/util');
// const { Keccak } = require('sha3');
const {
createHash,
} = require('node:crypto');
@ -12,12 +15,27 @@ const dataDir = process.env.DATA_DIR || 'data';
const db = new Level(`${dataDir}/forum`, { valueEncoding: 'json' });
// const keccak = Keccak(256);
app.use(express.json());
app.post('/write', async (req, res) => {
const { body: data } = req;
// TODO: Require author signature
const { body: { author, content, signature } } = req;
// Check author signature
try {
const account = recoverPersonalSignature({ data: content, signature });
if (account !== author) {
console.log('error: author does not match signature');
res.status(403).end();
return;
}
} catch (e) {
console.log('error: failed to recover signature:', e.message);
res.status(400).end();
return;
}
// Compute content hash
const data = { author, content, signature };
const hash = createHash('sha256').update(JSON.stringify(data)).digest('base64url');
console.log('write', hash);
// Store content

View File

@ -9,9 +9,9 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@metamask/eth-sig-util": "^7.0.1",
"axios": "^1.6.7",
"dotenv": "^16.4.5",
"ethers": "^6.11.1",
"express": "^4.18.2",
"level": "^8.0.1"
},
@ -33,11 +33,6 @@
"node": ">=0.10.0"
}
},
"node_modules/@adraffy/ens-normalize": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz",
"integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw=="
},
"node_modules/@babel/runtime": {
"version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz",
@ -106,6 +101,77 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@ethereumjs/common": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-3.2.0.tgz",
"integrity": "sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA==",
"dependencies": {
"@ethereumjs/util": "^8.1.0",
"crc-32": "^1.2.0"
}
},
"node_modules/@ethereumjs/common/node_modules/@ethereumjs/rlp": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz",
"integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==",
"bin": {
"rlp": "bin/rlp"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@ethereumjs/common/node_modules/@ethereumjs/util": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz",
"integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==",
"dependencies": {
"@ethereumjs/rlp": "^4.0.1",
"ethereum-cryptography": "^2.0.0",
"micro-ftch": "^0.3.1"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@ethereumjs/tx": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-4.2.0.tgz",
"integrity": "sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw==",
"dependencies": {
"@ethereumjs/common": "^3.2.0",
"@ethereumjs/rlp": "^4.0.1",
"@ethereumjs/util": "^8.1.0",
"ethereum-cryptography": "^2.0.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@ethereumjs/tx/node_modules/@ethereumjs/rlp": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz",
"integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==",
"bin": {
"rlp": "bin/rlp"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@ethereumjs/tx/node_modules/@ethereumjs/util": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz",
"integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==",
"dependencies": {
"@ethereumjs/rlp": "^4.0.1",
"ethereum-cryptography": "^2.0.0",
"micro-ftch": "^0.3.1"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
@ -139,6 +205,113 @@
"integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
"dev": true
},
"node_modules/@metamask/abi-utils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@metamask/abi-utils/-/abi-utils-2.0.2.tgz",
"integrity": "sha512-B/A1dY/w4F/t6cDHUscklO6ovb/ztFsrsTXFd8QlqSByk/vyy+QbPE3VVpmmyI/7RX+PA1AJcvBdzCIz+r9dVQ==",
"dependencies": {
"@metamask/utils": "^8.0.0",
"superstruct": "^1.0.3"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@metamask/eth-sig-util": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-7.0.1.tgz",
"integrity": "sha512-59GSrMyFH2fPfu7nKeIQdZ150zxXNNhAQIUaFRUW+MGtVA4w/ONbiQobcRBLi+jQProfIyss51G8pfLPcQ0ylg==",
"dependencies": {
"@ethereumjs/util": "^8.1.0",
"@metamask/abi-utils": "^2.0.2",
"@metamask/utils": "^8.1.0",
"ethereum-cryptography": "^2.1.2",
"tweetnacl": "^1.0.3",
"tweetnacl-util": "^0.15.1"
},
"engines": {
"node": "^16.20 || ^18.16 || >=20"
}
},
"node_modules/@metamask/eth-sig-util/node_modules/@ethereumjs/rlp": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz",
"integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==",
"bin": {
"rlp": "bin/rlp"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@metamask/eth-sig-util/node_modules/@ethereumjs/util": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz",
"integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==",
"dependencies": {
"@ethereumjs/rlp": "^4.0.1",
"ethereum-cryptography": "^2.0.0",
"micro-ftch": "^0.3.1"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@metamask/utils": {
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-8.4.0.tgz",
"integrity": "sha512-dbIc3C7alOe0agCuBHM1h71UaEaEqOk2W8rAtEn8QGz4haH2Qq7MoK6i7v2guzvkJVVh79c+QCzIqphC3KvrJg==",
"dependencies": {
"@ethereumjs/tx": "^4.2.0",
"@noble/hashes": "^1.3.1",
"@scure/base": "^1.1.3",
"@types/debug": "^4.1.7",
"debug": "^4.3.4",
"pony-cause": "^2.1.10",
"semver": "^7.5.4",
"superstruct": "^1.0.3",
"uuid": "^9.0.1"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@metamask/utils/node_modules/semver": {
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@noble/curves": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.3.0.tgz",
"integrity": "sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==",
"dependencies": {
"@noble/hashes": "1.3.3"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@noble/hashes": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz",
"integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==",
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -174,12 +347,58 @@
"node": ">= 8"
}
},
"node_modules/@scure/base": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.6.tgz",
"integrity": "sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==",
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@scure/bip32": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.3.tgz",
"integrity": "sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==",
"dependencies": {
"@noble/curves": "~1.3.0",
"@noble/hashes": "~1.3.2",
"@scure/base": "~1.1.4"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@scure/bip39": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.2.tgz",
"integrity": "sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==",
"dependencies": {
"@noble/hashes": "~1.3.2",
"@scure/base": "~1.1.4"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@types/debug": {
"version": "4.1.12",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
"integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==",
"dependencies": {
"@types/ms": "*"
}
},
"node_modules/@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
"dev": true
},
"node_modules/@types/ms": {
"version": "0.7.34",
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz",
"integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g=="
},
"node_modules/@ungap/structured-clone": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
@ -236,11 +455,6 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/aes-js": {
"version": "4.0.0-beta.5",
"resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz",
"integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q=="
},
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@ -761,6 +975,17 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
"node_modules/crc-32": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
"integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
"bin": {
"crc32": "bin/crc32.njs"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@ -785,7 +1010,6 @@
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
},
@ -1465,83 +1689,15 @@
"node": ">= 0.6"
}
},
"node_modules/ethers": {
"version": "6.11.1",
"resolved": "https://registry.npmjs.org/ethers/-/ethers-6.11.1.tgz",
"integrity": "sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/ethers-io/"
},
{
"type": "individual",
"url": "https://www.buymeacoffee.com/ricmoo"
}
],
"node_modules/ethereum-cryptography": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz",
"integrity": "sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==",
"dependencies": {
"@adraffy/ens-normalize": "1.10.1",
"@noble/curves": "1.2.0",
"@noble/hashes": "1.3.2",
"@types/node": "18.15.13",
"aes-js": "4.0.0-beta.5",
"tslib": "2.4.0",
"ws": "8.5.0"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/ethers/node_modules/@noble/curves": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz",
"integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
"dependencies": {
"@noble/hashes": "1.3.2"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/ethers/node_modules/@noble/hashes": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/ethers/node_modules/@types/node": {
"version": "18.15.13",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz",
"integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q=="
},
"node_modules/ethers/node_modules/tslib": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
},
"node_modules/ethers/node_modules/ws": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
"integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
"@noble/curves": "1.3.0",
"@noble/hashes": "1.3.3",
"@scure/bip32": "1.3.3",
"@scure/bip39": "1.2.2"
}
},
"node_modules/express": {
@ -2638,6 +2794,17 @@
"loose-envify": "cli.js"
}
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@ -2659,6 +2826,11 @@
"node": ">= 0.6"
}
},
"node_modules/micro-ftch": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz",
"integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg=="
},
"node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
@ -2721,8 +2893,7 @@
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/napi-macros": {
"version": "2.2.2",
@ -2996,6 +3167,14 @@
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
},
"node_modules/pony-cause": {
"version": "2.1.10",
"resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.10.tgz",
"integrity": "sha512-3IKLNXclQgkU++2fSi93sQ6BznFuxSLB11HdvZQ6JW/spahf/P1pAHBQEahr20rs0htZW0UDkM1HmA+nZkXKsw==",
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/possible-typed-array-names": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
@ -3556,6 +3735,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/superstruct": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.4.tgz",
"integrity": "sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@ -3606,6 +3793,16 @@
"strip-bom": "^3.0.0"
}
},
"node_modules/tweetnacl": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
},
"node_modules/tweetnacl-util": {
"version": "0.15.1",
"resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz",
"integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw=="
},
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@ -3755,6 +3952,18 @@
"node": ">= 0.4.0"
}
},
"node_modules/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@ -3860,6 +4069,11 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",

View File

@ -9,9 +9,9 @@
"author": "",
"license": "ISC",
"dependencies": {
"@metamask/eth-sig-util": "^7.0.1",
"axios": "^1.6.7",
"dotenv": "^16.4.5",
"ethers": "^6.11.1",
"express": "^4.18.2",
"level": "^8.0.1"
},

193
client/package-lock.json generated
View File

@ -16,6 +16,7 @@
"axios": "^1.6.8",
"bootstrap": "^5.3.3",
"bootswatch": "^5.3.3",
"buffer": "^6.0.3",
"helia": "^4.1.0",
"ipfs-core": "^0.18.1",
"prop-types": "^15.8.1",
@ -5642,29 +5643,6 @@
"uint8arrays": "^5.0.2"
}
},
"node_modules/@multiformats/dns/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/@multiformats/mafmt": {
"version": "12.1.6",
"resolved": "https://registry.npmjs.org/@multiformats/mafmt/-/mafmt-12.1.6.tgz",
@ -8281,29 +8259,6 @@
"node": ">=12"
}
},
"node_modules/abstract-level/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/abstract-leveldown": {
"version": "0.12.4",
"resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-0.12.4.tgz",
@ -8861,6 +8816,29 @@
"readable-stream": "^3.4.0"
}
},
"node_modules/bl/node_modules/buffer": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.1.13"
}
},
"node_modules/blob-to-it": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/blob-to-it/-/blob-to-it-2.0.5.tgz",
@ -9281,9 +9259,9 @@
}
},
"node_modules/buffer": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
@ -9300,7 +9278,7 @@
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.1.13"
"ieee754": "^1.2.1"
}
},
"node_modules/buffer-es6": {
@ -14906,29 +14884,6 @@
"npm": ">=7.0.0"
}
},
"node_modules/ipfs-core/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/ipfs-core/node_modules/cborg": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/cborg/-/cborg-1.10.2.tgz",
@ -16700,29 +16655,6 @@
"resolved": "https://registry.npmjs.org/browser-readablestream-to-it/-/browser-readablestream-to-it-1.0.3.tgz",
"integrity": "sha512-+12sHB+Br8HIh6VAMVEG5r3UXCyESIgDW7kzk3BjIXa43DVqVwL7GC5TW3jeh+72dtcH99pPVpw0X8i0jt+/kw=="
},
"node_modules/ipfs-utils/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/ipfs-utils/node_modules/it-all": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/it-all/-/it-all-1.0.6.tgz",
@ -17708,29 +17640,6 @@
"readable-stream": "^3.6.0"
}
},
"node_modules/it-to-stream/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/it-to-stream/node_modules/get-iterator": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/get-iterator/-/get-iterator-1.0.2.tgz",
@ -18712,29 +18621,6 @@
"node": ">=12"
}
},
"node_modules/level-transcoder/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/levelup": {
"version": "0.18.6",
"resolved": "https://registry.npmjs.org/levelup/-/levelup-0.18.6.tgz",
@ -21492,29 +21378,6 @@
"readable-stream": "^3.4.0"
}
},
"node_modules/rabin-wasm/node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"base64-js": "^1.3.1",
"ieee754": "^1.2.1"
}
},
"node_modules/race-event": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/race-event/-/race-event-1.2.0.tgz",

View File

@ -18,6 +18,7 @@
"axios": "^1.6.8",
"bootstrap": "^5.3.3",
"bootswatch": "^5.3.3",
"buffer": "^6.0.3",
"helia": "^4.1.0",
"ipfs-core": "^0.18.1",
"prop-types": "^15.8.1",

View File

@ -16,7 +16,7 @@ import Stack from 'react-bootstrap/Stack';
import './App.css';
import useList from './utils/List';
import { getContractByChainId as getContractAdressByChainId, getContractNameByAddress } from './utils/contract-config';
import { getContractAddressByChainId, getContractNameByAddress } from './utils/contract-config';
import Web3Context from './contexts/Web3Context';
import DAOArtifact from './assets/DAO.json';
import Work1Artifact from './assets/Work1.json';
@ -58,9 +58,9 @@ function App() {
// In this effect, we initialize everything and add contract event listeners.
useEffect(() => {
if (!provider || !chainId || !account || balance === undefined) return;
const DAOAddress = getContractAdressByChainId(chainId, 'DAO');
const Work1Address = getContractAdressByChainId(chainId, 'Work1');
const OnboardingAddress = getContractAdressByChainId(chainId, 'Onboarding');
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);
@ -205,7 +205,7 @@ function App() {
params: {
type: 'ERC20',
options: {
address: getContractAdressByChainId(chainId, 'DAO'),
address: getContractAddressByChainId(chainId, 'DAO'),
},
},
});

View File

@ -4,13 +4,16 @@ import Form from 'react-bootstrap/Form';
import Modal from 'react-bootstrap/Modal';
import axios from 'axios';
import PropTypes from 'prop-types';
import { Buffer } from 'buffer/'; // note: the trailing slash is important!
import Web3Context from '../contexts/Web3Context';
function AddPostModal({
show, setShow, title, postToBlockchain, onSubmit,
}) {
const { DAO, account } = useContext(Web3Context);
const {
provider, DAO, account,
} = useContext(Web3Context);
const [content, setContent] = useState('');
const handleClose = () => setShow(false);
@ -18,7 +21,14 @@ function AddPostModal({
const handleSubmit = useCallback(async () => {
// Upload content to API
// TODO: include metamask signature
const data = { author: account, content };
const msg = `0x${Buffer.from(content, 'utf8').toString('hex')}`;
const signature = await provider.request({
method: 'personal_sign',
params: [msg, account],
});
const data = {
author: account, content, signature,
};
const res = await axios.post('/api/write', data);
const hash = res.data;
setShow(false);
@ -33,7 +43,7 @@ function AddPostModal({
if (onSubmit) {
onSubmit(hash, data);
}
}, [DAO, account, content, setShow, postToBlockchain, onSubmit]);
}, [provider, DAO, account, content, setShow, postToBlockchain, onSubmit]);
return (
<Modal show={show} onHide={handleClose}>

View File

@ -5,16 +5,16 @@ const networks = {
sepolia: '0xaa36a7',
};
export const getContractByNetworkName = (networkName, contractName) => {
export const getContractAddressByNetworkName = (networkName, contractName) => {
const address = contractAddresses[networkName][contractName];
if (!address) throw new Error(`Contract ${contractName} not recognized`);
return address;
};
export const getContractByChainId = (chainId, contractName) => {
export const getContractAddressByChainId = (chainId, contractName) => {
const network = Object.entries(networks).find(([, id]) => id === chainId)[0];
if (!network) throw new Error(`Chain ID ${chainId} not recognized`);
return getContractByNetworkName(network, contractName);
return getContractAddressByNetworkName(network, contractName);
};
export const getContractNameByAddress = (chainId, address) => {

View File

@ -1,9 +1,11 @@
const { ethers } = require('hardhat');
const { getContractByNetworkName } = require('./contract-config');
const { getContractAddressByNetworkName } = require('./contract-config');
const network = process.env.HARDHAT_NETWORK;
let dao;
let work1;
let onboarding;
let account;
let validationPools;
let reputation;
@ -31,8 +33,13 @@ const fetchValidationPools = async () => {
};
const initialize = async () => {
const DAOAddress = getContractByNetworkName(network, 'DAO');
dao = await ethers.getContractAt('DAO', DAOAddress);
const getContract = (name) => ethers.getContractAt(
name,
getContractAddressByNetworkName(network, name),
);
dao = await getContract('DAO');
work1 = await getContract('Work1');
onboarding = await getContract('Onboarding');
[account] = await ethers.getSigners();
const address = await account.getAddress();
console.log(`account: ${address}`);
@ -47,8 +54,8 @@ const poolIsActive = (pool) => {
};
const poolIsValid = (pool) => [
getContractByNetworkName(network, 'Work1'),
getContractByNetworkName(network, 'Onboarding'),
getContractAddressByNetworkName(network, 'Work1'),
getContractAddressByNetworkName(network, 'Onboarding'),
].includes(pool.sender);
const getPoolStatus = (pool) => {
@ -107,6 +114,14 @@ async function main() {
fetchValidationPool(poolIndex);
fetchReputation();
});
work1.on('AvailabilityStaked', async () => {
fetchReputation();
});
onboarding.on('AvailabilityStaked', async () => {
fetchReputation();
});
}
main().catch((error) => {

View File

@ -5,19 +5,19 @@ const networks = {
sepolia: '0xaa36a7',
};
const getContractByNetworkName = (networkName, contractName) => {
const getContractAddressByNetworkName = (networkName, contractName) => {
const address = contractAddresses[networkName][contractName];
if (!address) throw new Error(`Contract ${contractName} not recognized`);
return address;
};
const getContractByChainId = (chainId, contractName) => {
const getContractAddressByChainId = (chainId, contractName) => {
const network = Object.entries(networks).find(([, id]) => id === chainId)[0];
if (!network) throw new Error(`Chain ID ${chainId} not recognized`);
return getContractByNetworkName(network, contractName);
return getContractAddressByNetworkName(network, contractName);
};
module.exports = {
getContractByChainId,
getContractByNetworkName,
getContractAddressByChainId,
getContractAddressByNetworkName,
};