From cc694e4a7c6e687afa8a602b4a30df110755f885 Mon Sep 17 00:00:00 2001 From: Haza Shami Date: Fri, 26 Jul 2024 13:46:52 -0700 Subject: [PATCH 1/2] added stellar server with basic configuration --- .gitignore | 3 +- deploy/.gitkeep | 0 deploy/README.md | 5 + package-lock.json | 248 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + stellar-server.js | 239 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 495 insertions(+), 1 deletion(-) create mode 100644 deploy/.gitkeep create mode 100644 deploy/README.md create mode 100644 stellar-server.js diff --git a/.gitignore b/.gitignore index b512c09..c24653f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -node_modules \ No newline at end of file +node_modules +deploy/crypto_vote_* \ No newline at end of file diff --git a/deploy/.gitkeep b/deploy/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 0000000..5d9344d --- /dev/null +++ b/deploy/README.md @@ -0,0 +1,5 @@ +# stellar contract deploy files +contains WASM files built from soroban-crypto-vote. + +each 'election' and 'ballot' instance requires one of these files is deployed to the stellar blockchain. +once we've deployed a contract and created a ledger (aka a 'block' on the chain), we can invoke functions as required. \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1aee762..0a5d161 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,12 +9,48 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@stellar/stellar-sdk": "^12.2.0", "express": "^4.19.2" }, "devDependencies": { "nodemon": "^3.1.4" } }, + "node_modules/@stellar/js-xdr": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@stellar/js-xdr/-/js-xdr-3.1.2.tgz", + "integrity": "sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ==" + }, + "node_modules/@stellar/stellar-base": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-12.1.0.tgz", + "integrity": "sha512-pWwn+XWP5NotmIteZNuJzHeNn9DYSqH3lsYbtFUoSYy1QegzZdi9D8dK6fJ2fpBAnf/rcDjHgHOw3gtHaQFVbg==", + "dependencies": { + "@stellar/js-xdr": "^3.1.2", + "base32.js": "^0.1.0", + "bignumber.js": "^9.1.2", + "buffer": "^6.0.3", + "sha.js": "^2.3.6", + "tweetnacl": "^1.0.3" + }, + "optionalDependencies": { + "sodium-native": "^4.1.1" + } + }, + "node_modules/@stellar/stellar-sdk": { + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-12.2.0.tgz", + "integrity": "sha512-Wy5sDOqb5JvAC76f4sQIV6Pe3JNyZb0PuyVNjwt3/uWsjtxRkFk6s2yTHTefBLWoR+mKxDjO7QfzhycF1v8FXQ==", + "dependencies": { + "@stellar/stellar-base": "^12.1.0", + "axios": "^1.7.2", + "bignumber.js": "^9.1.2", + "eventsource": "^2.0.2", + "randombytes": "^2.1.0", + "toml": "^3.0.0", + "urijs": "^1.19.1" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -48,6 +84,21 @@ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "license": "MIT" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -55,6 +106,41 @@ "dev": true, "license": "MIT" }, + "node_modules/base32.js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base32.js/-/base32.js-0.1.0.tgz", + "integrity": "sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -116,6 +202,29 @@ "node": ">=8" } }, + "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/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -169,6 +278,17 @@ "fsevents": "~2.3.2" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -238,6 +358,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -308,6 +436,14 @@ "node": ">= 0.6" } }, + "node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/express": { "version": "4.19.2", "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", @@ -381,6 +517,38 @@ "node": ">= 0.8" } }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -553,6 +721,25 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", @@ -706,6 +893,17 @@ "node": ">= 0.6" } }, + "node_modules/node-gyp-build": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", + "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/nodemon": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz", @@ -835,6 +1033,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", @@ -857,6 +1060,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -1001,6 +1212,18 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, "node_modules/side-channel": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", @@ -1032,6 +1255,16 @@ "node": ">=10" } }, + "node_modules/sodium-native": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-4.1.1.tgz", + "integrity": "sha512-LXkAfRd4FHtkQS4X6g+nRcVaN7mWVNepV06phIsC6+IZFvGh1voW5TNQiQp2twVaMf05gZqQjuS+uWLM6gHhNQ==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build": "^4.8.0" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -1076,6 +1309,11 @@ "node": ">=0.6" } }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==" + }, "node_modules/touch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", @@ -1086,6 +1324,11 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -1115,6 +1358,11 @@ "node": ">= 0.8" } }, + "node_modules/urijs": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", diff --git a/package.json b/package.json index fe59b7c..b8545c1 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "author": "", "license": "ISC", "dependencies": { + "@stellar/stellar-sdk": "^12.2.0", "express": "^4.19.2" }, "devDependencies": { diff --git a/stellar-server.js b/stellar-server.js new file mode 100644 index 0000000..7bd00a7 --- /dev/null +++ b/stellar-server.js @@ -0,0 +1,239 @@ +const StellarSdk = require('@stellar/stellar-sdk'); +const horizonUrl = 'https://horizon-testnet.stellar.org'; + +const server = new StellarSdk.Horizon.Server(horizonUrl); + +class StellarServer { + static server; + static account; + static electionWasm; + static ballotWasm; + electionContractId = ""; + ballotContractIds = []; + ready = false; + + constructor() { + this.server = new StellarSdk.Horizon.Server(horizonUrl); + this.loadAccount(); + } + + //should include versioning on these and load them based on some env + //for now, result of `stellar keys crypto-vote` -> public key: GDAYOSOILNQ7C5ZGR6QYFOLEDFWW5L766PPMBDLZ6UMM22MCMVJP6TEJ + //~/.config/soroban/identity/crypto-vote.toml -> default identity file location + loadWasmFiles() { + this.electionWasm = new File([], './deploy/crypto_vote_election.optimized.wasm').arrayBuffer(); + this.ballotWasm = new File([], './deploy/crypto_vote_ballot.optimized.wasm').arrayBuffer(); + } + + async loadAccount() { + try { + this.account = await server.loadAccount('GDAYOSOILNQ7C5ZGR6QYFOLEDFWW5L766PPMBDLZ6UMM22MCMVJP6TEJ') + this.ready = true; + } catch (error) { + console.error("ERROR: Failed to initialize account state!", error); + } + } + + isReady() { + return this.ready; + } + + getElectionId() { + return this.electionContractId; + } + + //returns bool verifying election has started + //sets electionContractId for this StellarServer instance + async startElection(electionName, durationInMillis, candidates) { + if (!this.ready) { + console.warn("Warning: StellarServer not ready yet."); + return; + } + try { + const fee = await this.server.fetchBaseFee(); + const electionTxn = this.getTxnBuilder(fee); + this.electionContractId = await this.uploadWasm(electionTxn, this.electionWasm); + console.log(this.electionContractId); + + let endTime = new Date(); + endTime.setMilliseconds(endTime.getMilliseconds() + durationInMillis); + + let startTxn = this.getTxnBuilder(); + startTxn.addOperation( + StellarSdk.Operation.invokeContractFunction({ + contract: this.electionContractId, + function: "start_election", + args: StellarSdk.nativeToScVal(endTime.getMilliseconds(), {type: 'number'}) + }) + ).build(); + + await server.submitAsyncTransaction(startElection); + } catch (error) { + console.error("Error! Could not start election.", error); + } + } + + //returns bool + async electionInProgress(electionId) { + if (!this.ready) { + console.warn("Warning: StellarServer not ready yet."); + } + try { + const fee = await this.server.fetchBaseFee(); + const txn = this.getTxnBuilder(fee); + txn.addOperation( + StellarSdk.Operation.invokeContractFunction({ + contract: electionId, + function: "in_progress" + }) + ).build(); + + return await server.submitAsyncTransaction(txn); + } catch (error) { + console.error("Error! Could not verify election in progress", error); + } + } + + //generates ballot ledger + //returns ballotId + async generateBallot(electionId) { + if (!this.ready) { + console.warn("Warning: Election not ready yet."); + } + try { + let fee = await this.server.fetchBaseFee(); + const txn = this.getTxnBuilder(fee); + let ballotId = await this.uploadWasm(txn, this.ballotWasm); + + const initTxn = this.getTxnBuilder(fee); + initTxn.addOperation( + StellarSdk.Operation.invokeContractFunction({ + contract: this.ballotId, + function: "initialize" + }) + ).build(); + + await server.submitAsyncTransaction(initTxn); + return ballotId; + } catch (error) { + console.error("Error! Could not generate ballot", error); + } + } + + //adds ballot ledger to election ledger + //returns length of ballotContractIds for simple verification + async addBallotToElection(electionId, ballotId) { + if (!this.ready) { + console.warn("Warning!: Election not ready yet."); + return; + } + try { + let fee = await this.server.fetchBaseFee(); + const txn = this.getTxnBuilder(fee); + txn.addOperation( + StellarSdk.Operation.invokeContractFunction({ + contract: electionId, + function: "add_ballot", + args: { + "ballot_id": StellarSdk.nativeToScVal(ballotId, {type: 'Address'}) + } + }) + ).build(); + await server.submitAsyncTransaction(initTxn); + //potentially inaccurate/naive state. for important operations fetch from election ledger directly + this.ballotContractIds.push(ballotId); + return this.ballotContractIds.length; + } catch (error) { + console.error("Error! Could not add ballot to election", error); + } + } + + //returns bool + async hasVoted(ballotId) { + if (!this.ready) { + console.warn("Warning!: Election not ready yet."); + return; + } + try { + let fee = await this.server.fetchBaseFee(); + const txn = this.getTxnBuilder(fee); + txn.addOperation( + StellarSdk.Operation.invokeContractFunction({ + contract: ballotId, + function: "has_voted" + }) + ).build(); + return await server.submitAsyncTransaction(txn); + } catch(error) { + console.error("Error! Could not verify if ballot has voted", error); + } + } + + //votes must have string keys with int values + //TODO: verify that votes gets passed correctly. may need to update keys from Symbol to String + //returns bool + async submitVote(ballotId, votes) { + if (!this.ready) { + console.warn("Warning! Election not ready yet."); + return; + } + try { + let fee = await this.server.fetchBaseFee(); + const txn = this.getTxnBuilder(fee); + txn.addOperation( + StellarSdk.Operation.invokeContractFunction({ + contract: ballotId, + function: "vote", + args: { + "votes": StellarSdk.nativeToScVal(votes) + } + }) + ).build(); + + await server.submitAsyncTransaction(txn); + } catch (error) { + console.error("Error! Could not submit votes to ballot with id", ballotId, error); + } + } + + //returns votes object associated with provided ballotId + async getVotes(ballotId) { + if (!this.ready) { + console.warn("Warning! Election not ready yet."); + return; + } + try { + let fee = await this.server.fetchBaseFee(); + const txn = this.getTxnBuilder(fee); + txn.addOperation( + StellarSdk.Operation.invokeContractFunction({ + contract: ballotId, + function: "get_votes", + }) + ).build(); + + return await server.submitAsyncTransaction(txn); + } catch (error) { + console.error("Error! Couldn't fetch votes for ballot with ID", ballotId, error); + } + } + + //utility function + //returns a primed TransactionBuilder + getTxnBuilder(fee) { + return new StellarSdk.TransactionBuilder( + this.account, { fee, networkPassphrase: StellarSdk.Networks.TESTNET } + ); + } + + //utility function + //returns contractId of uploaded .wasm + async uploadWasm(txn, wasm) { + txn.addOperation(StellarSdk.Operation.uploadContractWasm({wasm: wasm})).build(); + return await this.server.submitAsyncTransaction(uploadTxn); + } +} + +module.exports = { + StellarServer +} \ No newline at end of file From 0570d027c007f042134f94cbc15f02bc0281308f Mon Sep 17 00:00:00 2001 From: Arron McCrory Date: Thu, 7 Nov 2024 15:03:50 -0500 Subject: [PATCH 2/2] updated election --- app.js | 4 +--- mockElection.js | 11 ++++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app.js b/app.js index d2ff30b..3a9fd0d 100644 --- a/app.js +++ b/app.js @@ -9,14 +9,12 @@ app.get('/', (req, res) => { res.sendFile('/public/index.html'); }) - app.listen(port, () => { console.log(`Example app listening on port ${port}`) }) - app.get('/mock-election', (req, res) => { - const results = mockElection(10) + const results = mockElection(100) res.send(results) }) diff --git a/mockElection.js b/mockElection.js index 1fd1c7d..20e834a 100644 --- a/mockElection.js +++ b/mockElection.js @@ -13,15 +13,18 @@ function generateMockVoter(voteObj) { // we need to create a way for a voter to access their ballot after it's been created // maybe a UUID that is returned to the voter... ideally something like a SSN would be "best" const randomVoterId = randomUUID() - console.log("🚀 ~ generateMockVoter ~ randomVoterId:", randomVoterId) + console.log("randomVoterId:", randomVoterId) + console.log('is voting for:', voteObj) new Ballot(randomVoterId).sendItem(voteObj, GLOBAL_BALLOT.publicKey); // console.log('voter ballot '+ voter_ballot) return 'this is your unique voter ID, save it so you can view your vote later: ' + randomVoterId } function generateMockVote() { - const candidates = ['alpha', 'beta', 'gamma']; - const values = [1, 2, 3]; + // const candidates = ['bush', 'gore']; + // const values = [1, 2]; + const candidates = ['alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', 'upsilon', 'omega']; + const values = [1, 2, 3, 4, 5, 6, 7, 8]; const obj = {}; candidates.forEach(prop => { const randomIndex = Math.floor(Math.random() * values.length); @@ -53,8 +56,6 @@ function countVotes() { return GLOBAL_CHAIN.countVotes(); } - - module.exports = { generateMockVotes, generateMockVote,