Implement invoice generation and verification

This commit is contained in:
Michael Bumann
2021-11-28 13:06:01 -06:00
parent b4532cd1bd
commit 8aefd41378
7 changed files with 344 additions and 12 deletions

View File

@@ -1,3 +1,34 @@
const { parsePaymentRequest } = require('invoices');
const axios = require('axios');
const { createHash } = require('crypto');
function hexToUint8Array (hexString) {
const match = hexString.match(/.{1,2}/g);
if (match) {
return new Uint8Array(match.map((byte) => parseInt(byte, 16)));
}
}
// TODO validate responses
function getPaymetRequest(lightning_address, amount_in_sat) {
const [name, domain] = lightning_address.split("@");
const lnurl = `https://${domain}/.well-known/lnurlp/${name}`;
return axios.get(lnurl)
.then((response) => {
console.log(response.data);
const callbackUrl = response.data.callback;
const amount = amount_in_sat * 1000; // msats
return axios.get(callbackUrl, { params: { amount }} )
.then(prResponse => {
console.log(prResponse.data);
return prResponse.data.pr;
});
})
.catch(function (error) {
console.error(error);
})
}
module.exports = {
Query: {
allCategories: async (_source, args, context) => {
@@ -17,13 +48,33 @@ module.exports = {
Mutation: {
vote: async (_source, args, context) => {
const project = await context.prisma.project.findUnique({where: { id: args.project_id }});
console.log(project)
const pr = await getPaymetRequest(project.lightning_address, args.amount_in_sat);
const invoice = parsePaymentRequest({ request: pr });
return context.prisma.vote.create({
data: {
project_id: project.id,
amount_in_sat: args.amount_in_sat,
payment_request: pr,
payment_hash: invoice.id,
}
});
},
confirmVote: async (_source, args, context) => {
const paymentHash = createHash('sha256').update(hexToUint8Array(args.preimage)).digest('hex');
// look for a vote for the payment request and the calculated payment hash
const vote = await context.prisma.vote.findFirst({where: { payment_request: args.payment_request, payment_hash: paymentHash}});
// if we find a vote it means the preimage is correct and we update the vote and mark it as paid
if (vote) {
return context.prisma.vote.update({
where: { id: vote.id },
data: {
paid: true,
preimage: args.preimage,
}
});
} else {
throw new Error("Invalid preimage");
}
}
},
};
};

View File

@@ -7,6 +7,7 @@ module.exports = gql`
thumbnail_image: String!
title: String!
website: String!
lightning_address: String!
votes_count: Int!
category: Category!
}
@@ -21,6 +22,7 @@ module.exports = gql`
project: Project!
amount_in_sat: Int!
payment_request: String!
payment_hash: String!
paid: Boolean!
}
@@ -31,5 +33,6 @@ module.exports = gql`
}
type Mutation {
vote (project_id: Int!, amount_in_sat: Int!): Vote!
confirmVote (payment_request: String!, preimage: String!): Vote!
}
`;

273
package-lock.json generated
View File

@@ -20,8 +20,10 @@
"@types/react-dom": "^17.0.10",
"apollo-server": "^3.5.0",
"apollo-server-lambda": "^3.5.0",
"axios": "^0.24.0",
"framer-motion": "^5.3.0",
"graphql": "^16.0.1",
"invoices": "^2.0.2",
"lodash.throttle": "^4.1.1",
"prisma": "3.5.0",
"react": "^17.0.2",
@@ -8863,6 +8865,14 @@
"node": ">=4"
}
},
"node_modules/axios": {
"version": "0.24.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
"dependencies": {
"follow-redirects": "^1.14.4"
}
},
"node_modules/axobject-query": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
@@ -9590,6 +9600,14 @@
"node": ">=0.10.0"
}
},
"node_modules/base-x": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
"integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
"dependencies": {
"safe-buffer": "^5.0.1"
}
},
"node_modules/base/node_modules/define-property": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
@@ -9631,6 +9649,11 @@
"integrity": "sha1-dclcMrdI4IUNEMKxaPa9vpiRrOg=",
"dev": true
},
"node_modules/bech32": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz",
"integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg=="
},
"node_modules/better-opn": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/better-opn/-/better-opn-2.1.1.tgz",
@@ -9691,6 +9714,31 @@
"file-uri-to-path": "1.0.0"
}
},
"node_modules/bip174": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/bip174/-/bip174-2.0.1.tgz",
"integrity": "sha512-i3X26uKJOkDTAalYAp0Er+qGMDhrbbh2o93/xiPyAN2s25KrClSpe3VXo/7mNJoqA5qfko8rLS2l3RWZgYmjKQ==",
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/bitcoinjs-lib": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-6.0.0.tgz",
"integrity": "sha512-KYx81rVE4LDbZcHfE375NCX4CDeZuz7HECZm/KAmqKMY2jpD3ZcUnI7Fm+QX5EMF/xmtzzfrNL/BNxo8o0iOQg==",
"dependencies": {
"bech32": "^2.0.0",
"bip174": "^2.0.1",
"bs58check": "^2.1.2",
"create-hash": "^1.1.0",
"typeforce": "^1.11.3",
"varuint-bitcoin": "^1.1.2",
"wif": "^2.0.1"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@@ -9742,6 +9790,22 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"node_modules/bolt07": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/bolt07/-/bolt07-1.7.4.tgz",
"integrity": "sha512-y82Na9vEBY+rqjJhjYMFAch70nWvbL5OiEPFqNf7cGTtQfG7g/Vui2KnemrX1mxEw2SgccF+Rn1NSRm9HFtu3w==",
"dependencies": {
"bn.js": "5.2.0"
}
},
"node_modules/bolt09": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/bolt09/-/bolt09-0.2.0.tgz",
"integrity": "sha512-s6QWo7qqu6fKGLISGMSG+vFxIRzeUT3KQHDiHpvhflyI3TQD6zdaMu4fEpP7PoyMFJt2Ve26SBvvRP3MM7V0bw==",
"engines": {
"node": ">=10.4.0"
}
},
"node_modules/bonjour": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz",
@@ -10024,6 +10088,24 @@
"url": "https://opencollective.com/browserslist"
}
},
"node_modules/bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
"integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=",
"dependencies": {
"base-x": "^3.0.2"
}
},
"node_modules/bs58check": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
"integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
"dependencies": {
"bs58": "^4.0.0",
"create-hash": "^1.1.0",
"safe-buffer": "^5.1.2"
}
},
"node_modules/bser": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
@@ -16640,6 +16722,22 @@
"loose-envify": "^1.0.0"
}
},
"node_modules/invoices": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/invoices/-/invoices-2.0.2.tgz",
"integrity": "sha512-d1PX0ivZUw5u5kqIZ4bEajzTmKMe6EHXry4ZypsKT6SuvG4bTmn3sdCz867EhuMNZY2/Yj3/R1LXqCVTtsDPmA==",
"dependencies": {
"bech32": "2.0.0",
"bitcoinjs-lib": "6.0.0",
"bn.js": "5.2.0",
"bolt07": "1.7.4",
"bolt09": "0.2.0",
"secp256k1": "4.0.2"
},
"engines": {
"node": ">=10.4.0"
}
},
"node_modules/ip": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
@@ -43785,6 +43883,11 @@
"tslib": "^2.0.3"
}
},
"node_modules/node-addon-api": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
"integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA=="
},
"node_modules/node-dir": {
"version": "0.1.17",
"resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz",
@@ -43844,6 +43947,16 @@
"node": ">= 6.0.0"
}
},
"node_modules/node-gyp-build": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz",
"integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==",
"bin": {
"node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js",
"node-gyp-build-test": "build-test.js"
}
},
"node_modules/node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@@ -48825,6 +48938,20 @@
"url": "https://opencollective.com/webpack"
}
},
"node_modules/secp256k1": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz",
"integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==",
"hasInstallScript": true,
"dependencies": {
"elliptic": "^6.5.2",
"node-addon-api": "^2.0.0",
"node-gyp-build": "^4.2.0"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/select-hose": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -51197,6 +51324,11 @@
"is-typedarray": "^1.0.0"
}
},
"node_modules/typeforce": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
},
"node_modules/typescript": {
"version": "4.4.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
@@ -51816,6 +51948,14 @@
"node": ">=12"
}
},
"node_modules/varuint-bitcoin": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz",
"integrity": "sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==",
"dependencies": {
"safe-buffer": "^5.1.1"
}
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -53460,6 +53600,14 @@
"node": ">=8"
}
},
"node_modules/wif": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz",
"integrity": "sha1-CNP1IFbGZnkplyb63g1DKudLRwQ=",
"dependencies": {
"bs58check": "<3.0.0"
}
},
"node_modules/word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
@@ -60314,6 +60462,14 @@
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz",
"integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA=="
},
"axios": {
"version": "0.24.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
"requires": {
"follow-redirects": "^1.14.4"
}
},
"axobject-query": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
@@ -60920,6 +61076,14 @@
}
}
},
"base-x": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
"integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -60936,6 +61100,11 @@
"integrity": "sha1-dclcMrdI4IUNEMKxaPa9vpiRrOg=",
"dev": true
},
"bech32": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz",
"integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg=="
},
"better-opn": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/better-opn/-/better-opn-2.1.1.tgz",
@@ -60981,6 +61150,25 @@
"file-uri-to-path": "1.0.0"
}
},
"bip174": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/bip174/-/bip174-2.0.1.tgz",
"integrity": "sha512-i3X26uKJOkDTAalYAp0Er+qGMDhrbbh2o93/xiPyAN2s25KrClSpe3VXo/7mNJoqA5qfko8rLS2l3RWZgYmjKQ=="
},
"bitcoinjs-lib": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-6.0.0.tgz",
"integrity": "sha512-KYx81rVE4LDbZcHfE375NCX4CDeZuz7HECZm/KAmqKMY2jpD3ZcUnI7Fm+QX5EMF/xmtzzfrNL/BNxo8o0iOQg==",
"requires": {
"bech32": "^2.0.0",
"bip174": "^2.0.1",
"bs58check": "^2.1.2",
"create-hash": "^1.1.0",
"typeforce": "^1.11.3",
"varuint-bitcoin": "^1.1.2",
"wif": "^2.0.1"
}
},
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@@ -61028,6 +61216,19 @@
}
}
},
"bolt07": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/bolt07/-/bolt07-1.7.4.tgz",
"integrity": "sha512-y82Na9vEBY+rqjJhjYMFAch70nWvbL5OiEPFqNf7cGTtQfG7g/Vui2KnemrX1mxEw2SgccF+Rn1NSRm9HFtu3w==",
"requires": {
"bn.js": "5.2.0"
}
},
"bolt09": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/bolt09/-/bolt09-0.2.0.tgz",
"integrity": "sha512-s6QWo7qqu6fKGLISGMSG+vFxIRzeUT3KQHDiHpvhflyI3TQD6zdaMu4fEpP7PoyMFJt2Ve26SBvvRP3MM7V0bw=="
},
"bonjour": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz",
@@ -61257,6 +61458,24 @@
"picocolors": "^1.0.0"
}
},
"bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
"integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=",
"requires": {
"base-x": "^3.0.2"
}
},
"bs58check": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
"integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
"requires": {
"bs58": "^4.0.0",
"create-hash": "^1.1.0",
"safe-buffer": "^5.1.2"
}
},
"bser": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
@@ -66382,6 +66601,19 @@
"loose-envify": "^1.0.0"
}
},
"invoices": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/invoices/-/invoices-2.0.2.tgz",
"integrity": "sha512-d1PX0ivZUw5u5kqIZ4bEajzTmKMe6EHXry4ZypsKT6SuvG4bTmn3sdCz867EhuMNZY2/Yj3/R1LXqCVTtsDPmA==",
"requires": {
"bech32": "2.0.0",
"bitcoinjs-lib": "6.0.0",
"bn.js": "5.2.0",
"bolt07": "1.7.4",
"bolt09": "0.2.0",
"secp256k1": "4.0.2"
}
},
"ip": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
@@ -87276,6 +87508,11 @@
"tslib": "^2.0.3"
}
},
"node-addon-api": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz",
"integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA=="
},
"node-dir": {
"version": "0.1.17",
"resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz",
@@ -87328,6 +87565,11 @@
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
"integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA=="
},
"node-gyp-build": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz",
"integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q=="
},
"node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@@ -91234,6 +91476,16 @@
"ajv-keywords": "^3.5.2"
}
},
"secp256k1": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz",
"integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==",
"requires": {
"elliptic": "^6.5.2",
"node-addon-api": "^2.0.0",
"node-gyp-build": "^4.2.0"
}
},
"select-hose": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
@@ -93125,6 +93377,11 @@
"is-typedarray": "^1.0.0"
}
},
"typeforce": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
},
"typescript": {
"version": "4.4.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
@@ -93579,6 +93836,14 @@
"resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.11.tgz",
"integrity": "sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg=="
},
"varuint-bitcoin": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz",
"integrity": "sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==",
"requires": {
"safe-buffer": "^5.1.1"
}
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -94882,6 +95147,14 @@
"string-width": "^4.0.0"
}
},
"wif": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz",
"integrity": "sha1-CNP1IFbGZnkplyb63g1DKudLRwQ=",
"requires": {
"bs58check": "<3.0.0"
}
},
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",

View File

@@ -16,8 +16,10 @@
"@types/react-dom": "^17.0.10",
"apollo-server": "^3.5.0",
"apollo-server-lambda": "^3.5.0",
"axios": "^0.24.0",
"framer-motion": "^5.3.0",
"graphql": "^16.0.1",
"invoices": "^2.0.2",
"lodash.throttle": "^4.1.1",
"prisma": "3.5.0",
"react": "^17.0.2",

View File

@@ -16,6 +16,7 @@ CREATE TABLE "Project" (
"cover_image" TEXT,
"category_id" INTEGER NOT NULL,
"votes_count" INTEGER NOT NULL DEFAULT 0,
"lightning_address" TEXT,
CONSTRAINT "Project_pkey" PRIMARY KEY ("id")
);

View File

@@ -14,16 +14,17 @@ model Category {
}
model Project {
id Int @id @default(autoincrement())
title String
description String
website String
thumbnail_image String?
cover_image String?
category Category @relation(fields: [category_id], references: [id])
category_id Int
votes_count Int @default(0)
Vote Vote[]
id Int @id @default(autoincrement())
title String
description String
website String
thumbnail_image String?
cover_image String?
lightning_address String?
category Category @relation(fields: [category_id], references: [id])
category_id Int
votes_count Int @default(0)
Vote Vote[]
}
model Vote {

View File

@@ -14,6 +14,7 @@ async function main() {
description: "HQ on a VULCANO lake",
website: "https://github.com/peakshift",
category_id: category.id,
lightning_address: "johns@getalby.com",
}
});
}