From 6f24c0ad790d24739bc92ad329151242ae98d151 Mon Sep 17 00:00:00 2001 From: Raja Ilayaperumal Date: Sun, 10 Nov 2024 14:59:56 +0530 Subject: [PATCH] feature: Snapshot block height will be asked for setting up the FT voting. --- common/constants.js | 6 +- components/builder/BuilderComponent.js | 161 +++++---- components/common/InformationComponent.js | 24 +- components/poll/PollComponent.js | 10 +- package-lock.json | 390 ++++++++++++++++------ package.json | 8 +- pages/[...id].js | 19 +- services/contract.js | 67 +++- services/utils.js | 10 + yarn.lock | 199 +++++++---- 10 files changed, 658 insertions(+), 236 deletions(-) diff --git a/common/constants.js b/common/constants.js index 6c663aee..ad0d02e5 100644 --- a/common/constants.js +++ b/common/constants.js @@ -146,5 +146,9 @@ export const Constants = { "name": "Weighted Voting", "link": "https://docs.ballot.gg/ballot.gg/voting-system/weighted-voting" } - } + }, + + // Ballot.gg wallet address for donations + MAINNET_DONATION_ADDRESS: "SP1FQ3G3MYSXW68CWPY4GW342T3Y9HQCCXXCKENPH", + TESTNET_DONATION_ADDRESS: "ST2FYE64JK2NMRS1640FE9SKJS37CYYJ3B1EHB6AR", }; diff --git a/components/builder/BuilderComponent.js b/components/builder/BuilderComponent.js index d880e705..41fac72b 100644 --- a/components/builder/BuilderComponent.js +++ b/components/builder/BuilderComponent.js @@ -39,41 +39,44 @@ export default function BuilderComponent(props) { const [currentProgressMessage, setCurrentProgressMessage] = useState(); + // Current block height + const [currentBlockHeight, setCurrentBlockHeight] = useState(0); + + // On page load + useEffect(() => { + getCurrentBlockHeight(); + }, []); + // Functions useEffect(() => { - let _pollId, _mode, isCancelled = false; + let isCancelled = false; if (pathParams && pathParams?.[0]) { - _pollId = pathParams[0]; - setPollId(_pollId); + setPollId(pathParams[0]); } if (pathParams && pathParams?.[1]) { - _mode = pathParams[1]; - setMode(_mode); + setMode(pathParams[1]); } else { setMode(""); } - // Fetch from Gaia - if (_pollId) { - if (_pollId === "new") { - // Initialize new poll - setPollObject(initializeNewPoll()); - } else if (_mode === "draft") { - getFileFromGaia(_pollId + ".json", {}).then( - (response) => { - if (response && !isCancelled) { - setPollObject(JSON.parse(response)); - } - }, - (error) => { - // File does not exit in gaia - if (error && error.code == "does_not_exist" && !isCancelled) { - // Initialize new poll - setPollObject(initializeNewPoll()); - } - }); - } + // Initialize new poll + if (pathParams?.[0] === "new") { + setPollObject(initializeNewPoll()); + } else if (pathParams?.[1] === "draft") { + // Fetch from Gaia + getFileFromGaia(pathParams[0] + ".json", {}).then( + (response) => { + if (response && !isCancelled) { + setPollObject(JSON.parse(response)); + } + }, (error) => { + // File does not exit in gaia + if (error && error.code == "does_not_exist" && !isCancelled) { + // Initialize new poll + setPollObject(initializeNewPoll()); + } + }); } return () => { @@ -112,6 +115,12 @@ export default function BuilderComponent(props) { } } + const getCurrentBlockHeight = async () => { + // Get current block height + const currentBlock = await getRecentBlock(); + setCurrentBlockHeight(currentBlock?.height || 0); + } + const handleChange = e => { const { name, value } = e.target; @@ -125,10 +134,12 @@ export default function BuilderComponent(props) { pollObject["strategyTokenName"] = strategyTemplate["strategyTokenName"]; pollObject["strategyContractName"] = strategyTemplate["strategyContractName"]; pollObject["strategyTokenDecimals"] = strategyTemplate["strategyTokenDecimals"]; + pollObject["snapshotBlockHeight"] = strategyTemplate["snapshotBlockHeight"]; } else { pollObject["strategyTokenName"] = ""; pollObject["strategyContractName"] = ""; pollObject["strategyTokenDecimals"] = ""; + pollObject["snapshotBlockHeight"] = 0; } } @@ -136,6 +147,9 @@ export default function BuilderComponent(props) { if (!value && pollObject) { // Delete key from JSON delete pollObject[name]; + } else if (name == "startAtBlock" || name == "endAtBlock" || name == "snapshotBlockHeight") { + // Update the value + pollObject[name] = parseInt(value); } else { // Update the value pollObject[name] = value; @@ -190,8 +204,7 @@ export default function BuilderComponent(props) { if (response) { updatePollIndex(JSON.parse(response)); } - }, - (error) => { + }, (error) => { // File does not exit in gaia if (error && error.code == "does_not_exist") { // Initialize new @@ -272,14 +285,15 @@ export default function BuilderComponent(props) { } } - // Check for start and end date - if (!pollObject?.startAtDate || !pollObject?.endAtDate) { - return "Please select poll start and end date." - } else if (new Date() > new Date(pollObject?.startAtDate)) { - return "Start date should be a future date." - } else if (new Date() > new Date(pollObject?.endAtDate) || - new Date(pollObject?.startAtDate) > new Date(pollObject?.endAtDate)) { - return "End date should be greater than start date." + // Check for start and end block + if (!pollObject?.startAtBlock || !pollObject?.endAtBlock) { + return "Please enter start and end block height." + } else if (pollObject?.startAtBlock < currentBlockHeight) { + return "Start block should be greater than current block height." + } else if (pollObject?.startAtBlock > pollObject?.endAtBlock) { + return "End block should be greater than start block height." + } else if (pollObject?.endAtBlock <= pollObject?.startAtBlock) { + return "End block should be greater than start block height." } // Check for voting strategy template @@ -296,6 +310,14 @@ export default function BuilderComponent(props) { (!pollObject?.strategyTokenDecimals || !Number.isInteger(parseInt(pollObject?.strategyTokenDecimals)))) { return "Please enter positive integer value for strategy decimals" } + + // Fungible token + if (pollObject?.votingStrategyFlag && pollObject?.strategyTokenType == "ft") { + // Check for snapshotBlockHeight + if ((!pollObject?.snapshotBlockHeight || !Number.isInteger(parseInt(pollObject?.snapshotBlockHeight))) || pollObject?.snapshotBlockHeight <= 0) { + return "Please enter positive integer value for snapshot block height" + } + } } catch (e) { return "Please enter positive integer value for strategy decimals" } @@ -316,6 +338,18 @@ export default function BuilderComponent(props) { return 0; } + const calculateDate = (blockHeight, currentBlockHeight) => { + if (blockHeight && currentBlockHeight && blockHeight > 0 && currentBlockHeight > 0 && + blockHeight > currentBlockHeight) { + const diff = blockHeight - currentBlockHeight; + const minutes = diff * 10; + + return new Date(new Date().getTime() + (minutes * 60 * 1000)); + } + + return new Date(); + } + const publishPoll = async () => { // Start processing setIsProcessing(true); @@ -336,15 +370,12 @@ export default function BuilderComponent(props) { // Show message setCurrentProgressMessage("Publishing contract ..."); - // Get current Block - const currentBlock = await getRecentBlock(); - - // Calculate block time - if (pollObject?.startAtDate) { - pollObject['startAtBlock'] = calculateBlockTime(new Date(pollObject?.startAtDate).getTime(), currentBlock?.height); + // Calculate stand and end time based on block height + if (pollObject?.startAtBlock) { + pollObject['startAtDate'] = calculateDate(pollObject?.startAtBlock, currentBlockHeight); } - if (pollObject?.endAtDate) { - pollObject['endAtBlock'] = calculateBlockTime(new Date(pollObject?.endAtDate).getTime(), currentBlock?.height); + if (pollObject?.endAtBlock) { + pollObject['endAtDate'] = calculateDate(pollObject?.endAtBlock, currentBlockHeight); } // Convert local date to ISO date @@ -520,25 +551,29 @@ export default function BuilderComponent(props) { {/* Voting Period */} - Voting period + + Voting period + + + {/* By Block Height */}
- - Start * - + Start block height * + - - End * - + + End block height * + - - - The start and End date with time are stored in ISO date format(2022-10-21T17:19). It will be converted to a local date format for displaying. -
+ + + {/* The start and End date with time are stored in ISO date format(2022-10-21T17:19). It will be converted to a local date format for displaying. */} + Current Block Height: {currentBlockHeight} +
{/* Voting Strategy */} @@ -621,6 +656,18 @@ export default function BuilderComponent(props) { } } + + {/* Fungible Token - Snapshot block height */} + {pollObject?.strategyTokenType == "ft" && + <> + + Snapshot block height + + + + } } @@ -651,7 +698,7 @@ export default function BuilderComponent(props) { {/* Error Message */} {errorMessage &&
- {errorMessage} + {errorMessage}
} diff --git a/components/common/InformationComponent.js b/components/common/InformationComponent.js index 2814c992..fb32b08f 100644 --- a/components/common/InformationComponent.js +++ b/components/common/InformationComponent.js @@ -1,12 +1,12 @@ import { useEffect, useState } from "react"; import { Table } from "react-bootstrap"; import { Constants } from "../../common/constants"; -import { convertToDisplayDateFormat, formStacksExplorerUrl, formatUtcDateTime } from "../../services/utils"; +import { calculateDateByBlockHeight, convertToDisplayDateFormat, formStacksExplorerUrl, formatUtcDateTime } from "../../services/utils"; export default function InformationComponent(props) { // Variables - const { pollObject, resultsByOption } = props; + const { pollObject, resultsByOption, currentBlockHeight } = props; const [votingSystemInfo, setVotingSystemInfo] = useState(); // Function @@ -104,10 +104,23 @@ export default function InformationComponent(props) { Voting System {votingSystemInfo?.name}
- Start Date {pollObject?.startAtDateUTC ? (formatUtcDateTime(pollObject?.startAtDateUTC) + " UTC") : convertToDisplayDateFormat(pollObject?.startAtDate)} + Start Date + + {pollObject?.startAtDateUTC ? (formatUtcDateTime(pollObject?.startAtDateUTC) + " UTC") : convertToDisplayDateFormat(pollObject?.startAtDate)} +
- End Date {pollObject?.endAtDateUTC ? (formatUtcDateTime(pollObject?.endAtDateUTC) + " UTC") : convertToDisplayDateFormat(pollObject?.endAtDate)} + End Date + + {pollObject?.endAtBlock && currentBlockHeight < pollObject?.endAtBlock ? + <> + {formatUtcDateTime(calculateDateByBlockHeight(currentBlockHeight, pollObject?.endAtBlock))} UTC + : + <> + {pollObject?.endAtDateUTC ? (formatUtcDateTime(pollObject?.endAtDateUTC) + " UTC") : convertToDisplayDateFormat(pollObject?.endAtDate)} + + } +
Start Block {pollObject?.startAtBlock} @@ -115,6 +128,9 @@ export default function InformationComponent(props) {
End Block {pollObject?.endAtBlock}
+
+ Current Block {currentBlockHeight} +
{pollObject?.contractAddress &&
Contract Address {pollObject?.contractAddress} diff --git a/components/poll/PollComponent.js b/components/poll/PollComponent.js index e17fcebc..5b59bd96 100644 --- a/components/poll/PollComponent.js +++ b/components/poll/PollComponent.js @@ -27,7 +27,8 @@ export default function PollComponent(props) { publicUrl, txStatus, noOfResultsLoaded, - setNoOfResultsLoaded } = props; + setNoOfResultsLoaded, + currentBlockHeight } = props; const [voteObject, setVoteObject] = useState({}); const [errorMessage, setErrorMessage] = useState(); const [txId, setTxId] = useState(); @@ -267,8 +268,9 @@ export default function PollComponent(props) {
@@ -401,7 +403,7 @@ export default function PollComponent(props) { {/* Right Side */}
{/* Information */} - +
diff --git a/package-lock.json b/package-lock.json index e818b19b..dbb470a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,10 +8,10 @@ "name": "ballot", "version": "0.1.0", "dependencies": { - "@stacks/connect": "^7.7.1", - "@stacks/network": "^6.11.3", - "@stacks/storage": "^6.12.0", - "@stacks/transactions": "^6.12.0", + "@stacks/connect": "^7.8.0", + "@stacks/network": "^6.17.0", + "@stacks/storage": "^6.17.0", + "@stacks/transactions": "^6.17.0", "bootstrap": "^5.2.0", "lodash": "^4.17.21", "nanoid": "^4.0.0", @@ -482,57 +482,129 @@ } }, "node_modules/@stacks/auth": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@stacks/auth/-/auth-6.12.0.tgz", - "integrity": "sha512-ViSpeWNw1MJBtvykcPTcn9vTy9v8pK8jiQFjfOkiFQ0q+oEhIDQrtpN5OYtTh5HvoZk8du+43nIoUYUECNahHQ==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@stacks/auth/-/auth-6.17.0.tgz", + "integrity": "sha512-SaxB6ULkYLRd5WZotymlPzroBn5/28KgJOTY0nKDcwCqxSkYjPZepweA30LK5eUOmePuGILaMTagj1ibZRnvUg==", "dependencies": { - "@stacks/common": "^6.10.0", - "@stacks/encryption": "^6.12.0", - "@stacks/network": "^6.11.3", - "@stacks/profile": "^6.12.0", + "@stacks/common": "^6.16.0", + "@stacks/encryption": "^6.17.0", + "@stacks/network": "^6.17.0", + "@stacks/profile": "^6.17.0", "cross-fetch": "^3.1.5", "jsontokens": "^4.0.1" } }, "node_modules/@stacks/common": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@stacks/common/-/common-6.10.0.tgz", - "integrity": "sha512-6x5Z7AKd9/kj3+DYE9xIDIkFLHihBH614i2wqrZIjN02WxVo063hWSjIlUxlx8P4gl6olVzlOy5LzhLJD9OP0A==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@stacks/common/-/common-6.16.0.tgz", + "integrity": "sha512-PnzvhrdGRMVZvxTulitlYafSK4l02gPCBBoI9QEoTqgSnv62oaOXhYAUUkTMFKxdHW1seVEwZsrahuXiZPIAwg==", "dependencies": { "@types/bn.js": "^5.1.0", "@types/node": "^18.0.4" } }, "node_modules/@stacks/connect": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@stacks/connect/-/connect-7.7.1.tgz", - "integrity": "sha512-MwLRhgRLOGo0Y4IDC0qp9RUX2SZubgse1aI2TN/fz2abNIh1LgmOKUua3w17YiBEZxDD9nyQ4KW1c33bdnrOPw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@stacks/connect/-/connect-7.8.0.tgz", + "integrity": "sha512-whwHygS69XyY/LMvlyp0Whu4mkWkFoJ4Z/Bva9aO1xLLyEVDbKLZnslGWmPs1Io/y76oGEorqVEh0MeLymTIjg==", "dependencies": { - "@stacks/auth": "^6.1.1", - "@stacks/connect-ui": "6.4.1", - "@stacks/network": "^6.1.1", - "@stacks/profile": "^6.1.1", - "@stacks/transactions": "^6.1.1", + "@stacks/auth": "^7.0.0-next.70", + "@stacks/common": "^7.0.0-next.70", + "@stacks/connect-ui": "6.5.0", + "@stacks/network": "^7.0.0-next.70", + "@stacks/network-v6": "npm:@stacks/network@^6.16.0", + "@stacks/profile": "^7.0.0-next.70", + "@stacks/transactions": "^7.0.0-next.70", + "@stacks/transactions-v6": "npm:@stacks/transactions@^6.16.0", "jsontokens": "^4.0.1" } }, "node_modules/@stacks/connect-ui": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/@stacks/connect-ui/-/connect-ui-6.4.1.tgz", - "integrity": "sha512-Y6Fp26MUsMQq08zFSWus40rS7RNHrHj6VDJrFUqM9VsksV3wftpsRcy7psQusUvW1DS7fPza67IlM1dcN4rvSg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@stacks/connect-ui/-/connect-ui-6.5.0.tgz", + "integrity": "sha512-iXSpl2NxrjERBqtGgkZp0tX1uJgdWZXmsNo3I0cJYYTTbieSAE/Al9nTYc1wLTPW5w5oVvZEkQKo90WIrHR8Rw==", "dependencies": { "@stencil/core": "^2.17.1" } }, - "node_modules/@stacks/encryption": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@stacks/encryption/-/encryption-6.12.0.tgz", - "integrity": "sha512-CubE51pHrcxx3yA+xapevPgA9UDleIoEaUZ06/9uD91B42yvTg37HyS8t06rzukU9q+X7Cv2I/+vbuf4nJIo8g==", + "node_modules/@stacks/connect/node_modules/@stacks/auth": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@stacks/auth/-/auth-7.0.0.tgz", + "integrity": "sha512-p0/FJy5jRRgtsVzGpWDgNE0fi/ioPCL3S1tZHRsvdKO7moquHWnTlBV/9yVkGbd+V0kD95Sd0euX5pwWA82MhA==", + "dependencies": { + "@noble/secp256k1": "1.7.1", + "@stacks/common": "^7.0.0", + "@stacks/encryption": "^7.0.0", + "@stacks/network": "^7.0.0", + "@stacks/profile": "^7.0.0", + "cross-fetch": "^3.1.5", + "jsontokens": "^4.0.1" + } + }, + "node_modules/@stacks/connect/node_modules/@stacks/common": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@stacks/common/-/common-7.0.0.tgz", + "integrity": "sha512-/BKBK9S9GEuGjbnc2fBAwsG21f8cfNekG/9mXLSMwBqnh4qaQY2hxK+6wRI2YXJgpkXrpZilpZy2sdPGlVUdQA==" + }, + "node_modules/@stacks/connect/node_modules/@stacks/encryption": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@stacks/encryption/-/encryption-7.0.0.tgz", + "integrity": "sha512-kQhiurn8s0DV6OALqEy2Aqwp2DNJUD41S1bnD/+UESyEDD5XRqL84MEo7mCL8pTPr+FVdhT+diEIPeAfEtbTPQ==", "dependencies": { "@noble/hashes": "1.1.5", "@noble/secp256k1": "1.7.1", "@scure/bip39": "1.1.0", - "@stacks/common": "^6.10.0", + "@stacks/common": "^7.0.0", + "base64-js": "^1.5.1", + "bs58": "^5.0.0", + "ripemd160-min": "^0.0.6", + "varuint-bitcoin": "^1.1.2" + } + }, + "node_modules/@stacks/connect/node_modules/@stacks/network": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@stacks/network/-/network-7.0.0.tgz", + "integrity": "sha512-4diddT0ii85BQ4PW6ww3l4cS7Oo0a5VIsJ7umBcCPAArIc4Sm/MIOEXIg9joKK8fVHLnWyh1p4D+febJQFfa+Q==", + "dependencies": { + "@stacks/common": "^7.0.0", + "cross-fetch": "^3.1.5" + } + }, + "node_modules/@stacks/connect/node_modules/@stacks/profile": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@stacks/profile/-/profile-7.0.0.tgz", + "integrity": "sha512-E9RDodVgcLBs6ZiV88lVQyDjA8ZDVPswbPpLNHeAA+evJ2GwRKMJrNnirjydMI37aWm3ZpYOEMLMbqdi38VR7w==", + "dependencies": { + "@stacks/common": "^7.0.0", + "@stacks/network": "^7.0.0", + "@stacks/transactions": "^7.0.0", + "jsontokens": "^4.0.1", + "schema-inspector": "^2.0.2", + "zone-file": "^2.0.0-beta.3" + } + }, + "node_modules/@stacks/connect/node_modules/@stacks/transactions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-7.0.0.tgz", + "integrity": "sha512-9kGTnJLwRQPugLzbdJ8MmFED+eRhlJKIXpz2mshyy238hvBc4T0jynsoJMi4qGqvJYzsiRYCLDPJVkkUde85vA==", + "dependencies": { + "@noble/hashes": "1.1.5", + "@noble/secp256k1": "1.7.1", + "@stacks/common": "^7.0.0", + "@stacks/network": "^7.0.0", + "c32check": "^2.0.0", + "lodash.clonedeep": "^4.5.0" + } + }, + "node_modules/@stacks/encryption": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@stacks/encryption/-/encryption-6.17.0.tgz", + "integrity": "sha512-c0+ZOjrAiB1fDCjXO6XqHdYgpeBeMYyeH+dWahpD1VQUDor2PE5Q47qyuibWmx36rLWt1M6wlaLdeVm6HlKGzw==", + "dependencies": { + "@noble/hashes": "1.1.5", + "@noble/secp256k1": "1.7.1", + "@scure/bip39": "1.1.0", + "@stacks/common": "^6.16.0", "@types/node": "^18.0.4", "base64-js": "^1.5.1", "bs58": "^5.0.0", @@ -541,49 +613,73 @@ } }, "node_modules/@stacks/network": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/@stacks/network/-/network-6.11.3.tgz", - "integrity": "sha512-c4ClCU/QUwuu8NbHtDKPJNa0M5YxauLN3vYaR0+S4awbhVIKFQSxirm9Q9ckV1WBh7FtD6u2S0x+tDQGAODjNg==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@stacks/network/-/network-6.17.0.tgz", + "integrity": "sha512-numHbfKjwco/rbkGPOEz8+FcJ2nBnS/tdJ8R422Q70h3SiA9eqk9RjSzB8p4JP8yW1SZvW+eihADHfMpBuZyfw==", "dependencies": { - "@stacks/common": "^6.10.0", + "@stacks/common": "^6.16.0", + "cross-fetch": "^3.1.5" + } + }, + "node_modules/@stacks/network-v6": { + "name": "@stacks/network", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@stacks/network/-/network-6.17.0.tgz", + "integrity": "sha512-numHbfKjwco/rbkGPOEz8+FcJ2nBnS/tdJ8R422Q70h3SiA9eqk9RjSzB8p4JP8yW1SZvW+eihADHfMpBuZyfw==", + "dependencies": { + "@stacks/common": "^6.16.0", "cross-fetch": "^3.1.5" } }, "node_modules/@stacks/profile": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@stacks/profile/-/profile-6.12.0.tgz", - "integrity": "sha512-eY5IpX+GGHIcYLkivDmf3mkxDIgTQ+LhU8UG4jvOqDi+e1DvF9cIi3+reG5KVo0pQzqyT1OS7+16AwVcgp7/og==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@stacks/profile/-/profile-6.17.0.tgz", + "integrity": "sha512-EoYe0NapFc6bgA+vyCVY2sYYRHk3pbsbRnm3eaSp8y9Drfy8dBqsM10W1jjTwOn0R+IMmDT52lojdW7Pw3c7Mw==", "dependencies": { - "@stacks/common": "^6.10.0", - "@stacks/network": "^6.11.3", - "@stacks/transactions": "^6.12.0", + "@stacks/common": "^6.16.0", + "@stacks/network": "^6.17.0", + "@stacks/transactions": "^6.17.0", "jsontokens": "^4.0.1", "schema-inspector": "^2.0.2", "zone-file": "^2.0.0-beta.3" } }, "node_modules/@stacks/storage": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@stacks/storage/-/storage-6.12.0.tgz", - "integrity": "sha512-RiB8cfWKCm4LrDLXdjtRj4syzvpwmJ/6WKcF+1RHQBTyJerPgxoBn1NoKzjOcydQvVj1jpR/ccaS78xVxlMsTQ==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@stacks/storage/-/storage-6.17.0.tgz", + "integrity": "sha512-vhgV8C+1UahSWrafOHh/ZnTVYs8JadLsh5OZCVgtxWXV7z8ruQzVN24eeXbR+C7Vme2YpDP210ly7Wyqxd755Q==", "dependencies": { - "@stacks/auth": "^6.12.0", - "@stacks/common": "^6.10.0", - "@stacks/encryption": "^6.12.0", - "@stacks/network": "^6.11.3", + "@stacks/auth": "^6.17.0", + "@stacks/common": "^6.16.0", + "@stacks/encryption": "^6.17.0", + "@stacks/network": "^6.17.0", "base64-js": "^1.5.1", "jsontokens": "^4.0.1" } }, "node_modules/@stacks/transactions": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.12.0.tgz", - "integrity": "sha512-gRP3SfTaAIoTdjMvOiLrMZb/senqB8JQlT5Y4C3/CiHhiprYwTx7TbOCSa7WsNOU99H4aNfHvatmymuggXQVkA==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.17.0.tgz", + "integrity": "sha512-FUah2BRgV66ApLcEXGNGhwyFTRXqX5Zco3LpiM3essw8PF0NQlHwwdPgtDko5RfrJl3LhGXXe/30nwsfNnB3+g==", "dependencies": { "@noble/hashes": "1.1.5", "@noble/secp256k1": "1.7.1", - "@stacks/common": "^6.10.0", - "@stacks/network": "^6.11.3", + "@stacks/common": "^6.16.0", + "@stacks/network": "^6.17.0", + "c32check": "^2.0.0", + "lodash.clonedeep": "^4.5.0" + } + }, + "node_modules/@stacks/transactions-v6": { + "name": "@stacks/transactions", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.17.0.tgz", + "integrity": "sha512-FUah2BRgV66ApLcEXGNGhwyFTRXqX5Zco3LpiM3essw8PF0NQlHwwdPgtDko5RfrJl3LhGXXe/30nwsfNnB3+g==", + "dependencies": { + "@noble/hashes": "1.1.5", + "@noble/secp256k1": "1.7.1", + "@stacks/common": "^6.16.0", + "@stacks/network": "^6.17.0", "c32check": "^2.0.0", "lodash.clonedeep": "^4.5.0" } @@ -4103,57 +4199,131 @@ } }, "@stacks/auth": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@stacks/auth/-/auth-6.12.0.tgz", - "integrity": "sha512-ViSpeWNw1MJBtvykcPTcn9vTy9v8pK8jiQFjfOkiFQ0q+oEhIDQrtpN5OYtTh5HvoZk8du+43nIoUYUECNahHQ==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@stacks/auth/-/auth-6.17.0.tgz", + "integrity": "sha512-SaxB6ULkYLRd5WZotymlPzroBn5/28KgJOTY0nKDcwCqxSkYjPZepweA30LK5eUOmePuGILaMTagj1ibZRnvUg==", "requires": { - "@stacks/common": "^6.10.0", - "@stacks/encryption": "^6.12.0", - "@stacks/network": "^6.11.3", - "@stacks/profile": "^6.12.0", + "@stacks/common": "^6.16.0", + "@stacks/encryption": "^6.17.0", + "@stacks/network": "^6.17.0", + "@stacks/profile": "^6.17.0", "cross-fetch": "^3.1.5", "jsontokens": "^4.0.1" } }, "@stacks/common": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@stacks/common/-/common-6.10.0.tgz", - "integrity": "sha512-6x5Z7AKd9/kj3+DYE9xIDIkFLHihBH614i2wqrZIjN02WxVo063hWSjIlUxlx8P4gl6olVzlOy5LzhLJD9OP0A==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/@stacks/common/-/common-6.16.0.tgz", + "integrity": "sha512-PnzvhrdGRMVZvxTulitlYafSK4l02gPCBBoI9QEoTqgSnv62oaOXhYAUUkTMFKxdHW1seVEwZsrahuXiZPIAwg==", "requires": { "@types/bn.js": "^5.1.0", "@types/node": "^18.0.4" } }, "@stacks/connect": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@stacks/connect/-/connect-7.7.1.tgz", - "integrity": "sha512-MwLRhgRLOGo0Y4IDC0qp9RUX2SZubgse1aI2TN/fz2abNIh1LgmOKUua3w17YiBEZxDD9nyQ4KW1c33bdnrOPw==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@stacks/connect/-/connect-7.8.0.tgz", + "integrity": "sha512-whwHygS69XyY/LMvlyp0Whu4mkWkFoJ4Z/Bva9aO1xLLyEVDbKLZnslGWmPs1Io/y76oGEorqVEh0MeLymTIjg==", "requires": { - "@stacks/auth": "^6.1.1", - "@stacks/connect-ui": "6.4.1", - "@stacks/network": "^6.1.1", - "@stacks/profile": "^6.1.1", - "@stacks/transactions": "^6.1.1", + "@stacks/auth": "^7.0.0-next.70", + "@stacks/common": "^7.0.0-next.70", + "@stacks/connect-ui": "6.5.0", + "@stacks/network": "^7.0.0-next.70", + "@stacks/network-v6": "npm:@stacks/network@^6.16.0", + "@stacks/profile": "^7.0.0-next.70", + "@stacks/transactions": "^7.0.0-next.70", + "@stacks/transactions-v6": "npm:@stacks/transactions@^6.16.0", "jsontokens": "^4.0.1" + }, + "dependencies": { + "@stacks/auth": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@stacks/auth/-/auth-7.0.0.tgz", + "integrity": "sha512-p0/FJy5jRRgtsVzGpWDgNE0fi/ioPCL3S1tZHRsvdKO7moquHWnTlBV/9yVkGbd+V0kD95Sd0euX5pwWA82MhA==", + "requires": { + "@noble/secp256k1": "1.7.1", + "@stacks/common": "^7.0.0", + "@stacks/encryption": "^7.0.0", + "@stacks/network": "^7.0.0", + "@stacks/profile": "^7.0.0", + "cross-fetch": "^3.1.5", + "jsontokens": "^4.0.1" + } + }, + "@stacks/common": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@stacks/common/-/common-7.0.0.tgz", + "integrity": "sha512-/BKBK9S9GEuGjbnc2fBAwsG21f8cfNekG/9mXLSMwBqnh4qaQY2hxK+6wRI2YXJgpkXrpZilpZy2sdPGlVUdQA==" + }, + "@stacks/encryption": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@stacks/encryption/-/encryption-7.0.0.tgz", + "integrity": "sha512-kQhiurn8s0DV6OALqEy2Aqwp2DNJUD41S1bnD/+UESyEDD5XRqL84MEo7mCL8pTPr+FVdhT+diEIPeAfEtbTPQ==", + "requires": { + "@noble/hashes": "1.1.5", + "@noble/secp256k1": "1.7.1", + "@scure/bip39": "1.1.0", + "@stacks/common": "^7.0.0", + "base64-js": "^1.5.1", + "bs58": "^5.0.0", + "ripemd160-min": "^0.0.6", + "varuint-bitcoin": "^1.1.2" + } + }, + "@stacks/network": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@stacks/network/-/network-7.0.0.tgz", + "integrity": "sha512-4diddT0ii85BQ4PW6ww3l4cS7Oo0a5VIsJ7umBcCPAArIc4Sm/MIOEXIg9joKK8fVHLnWyh1p4D+febJQFfa+Q==", + "requires": { + "@stacks/common": "^7.0.0", + "cross-fetch": "^3.1.5" + } + }, + "@stacks/profile": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@stacks/profile/-/profile-7.0.0.tgz", + "integrity": "sha512-E9RDodVgcLBs6ZiV88lVQyDjA8ZDVPswbPpLNHeAA+evJ2GwRKMJrNnirjydMI37aWm3ZpYOEMLMbqdi38VR7w==", + "requires": { + "@stacks/common": "^7.0.0", + "@stacks/network": "^7.0.0", + "@stacks/transactions": "^7.0.0", + "jsontokens": "^4.0.1", + "schema-inspector": "^2.0.2", + "zone-file": "^2.0.0-beta.3" + } + }, + "@stacks/transactions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-7.0.0.tgz", + "integrity": "sha512-9kGTnJLwRQPugLzbdJ8MmFED+eRhlJKIXpz2mshyy238hvBc4T0jynsoJMi4qGqvJYzsiRYCLDPJVkkUde85vA==", + "requires": { + "@noble/hashes": "1.1.5", + "@noble/secp256k1": "1.7.1", + "@stacks/common": "^7.0.0", + "@stacks/network": "^7.0.0", + "c32check": "^2.0.0", + "lodash.clonedeep": "^4.5.0" + } + } } }, "@stacks/connect-ui": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/@stacks/connect-ui/-/connect-ui-6.4.1.tgz", - "integrity": "sha512-Y6Fp26MUsMQq08zFSWus40rS7RNHrHj6VDJrFUqM9VsksV3wftpsRcy7psQusUvW1DS7fPza67IlM1dcN4rvSg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@stacks/connect-ui/-/connect-ui-6.5.0.tgz", + "integrity": "sha512-iXSpl2NxrjERBqtGgkZp0tX1uJgdWZXmsNo3I0cJYYTTbieSAE/Al9nTYc1wLTPW5w5oVvZEkQKo90WIrHR8Rw==", "requires": { "@stencil/core": "^2.17.1" } }, "@stacks/encryption": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@stacks/encryption/-/encryption-6.12.0.tgz", - "integrity": "sha512-CubE51pHrcxx3yA+xapevPgA9UDleIoEaUZ06/9uD91B42yvTg37HyS8t06rzukU9q+X7Cv2I/+vbuf4nJIo8g==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@stacks/encryption/-/encryption-6.17.0.tgz", + "integrity": "sha512-c0+ZOjrAiB1fDCjXO6XqHdYgpeBeMYyeH+dWahpD1VQUDor2PE5Q47qyuibWmx36rLWt1M6wlaLdeVm6HlKGzw==", "requires": { "@noble/hashes": "1.1.5", "@noble/secp256k1": "1.7.1", "@scure/bip39": "1.1.0", - "@stacks/common": "^6.10.0", + "@stacks/common": "^6.16.0", "@types/node": "^18.0.4", "base64-js": "^1.5.1", "bs58": "^5.0.0", @@ -4162,49 +4332,71 @@ } }, "@stacks/network": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/@stacks/network/-/network-6.11.3.tgz", - "integrity": "sha512-c4ClCU/QUwuu8NbHtDKPJNa0M5YxauLN3vYaR0+S4awbhVIKFQSxirm9Q9ckV1WBh7FtD6u2S0x+tDQGAODjNg==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@stacks/network/-/network-6.17.0.tgz", + "integrity": "sha512-numHbfKjwco/rbkGPOEz8+FcJ2nBnS/tdJ8R422Q70h3SiA9eqk9RjSzB8p4JP8yW1SZvW+eihADHfMpBuZyfw==", "requires": { - "@stacks/common": "^6.10.0", + "@stacks/common": "^6.16.0", + "cross-fetch": "^3.1.5" + } + }, + "@stacks/network-v6": { + "version": "npm:@stacks/network@6.17.0", + "resolved": "https://registry.npmjs.org/@stacks/network/-/network-6.17.0.tgz", + "integrity": "sha512-numHbfKjwco/rbkGPOEz8+FcJ2nBnS/tdJ8R422Q70h3SiA9eqk9RjSzB8p4JP8yW1SZvW+eihADHfMpBuZyfw==", + "requires": { + "@stacks/common": "^6.16.0", "cross-fetch": "^3.1.5" } }, "@stacks/profile": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@stacks/profile/-/profile-6.12.0.tgz", - "integrity": "sha512-eY5IpX+GGHIcYLkivDmf3mkxDIgTQ+LhU8UG4jvOqDi+e1DvF9cIi3+reG5KVo0pQzqyT1OS7+16AwVcgp7/og==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@stacks/profile/-/profile-6.17.0.tgz", + "integrity": "sha512-EoYe0NapFc6bgA+vyCVY2sYYRHk3pbsbRnm3eaSp8y9Drfy8dBqsM10W1jjTwOn0R+IMmDT52lojdW7Pw3c7Mw==", "requires": { - "@stacks/common": "^6.10.0", - "@stacks/network": "^6.11.3", - "@stacks/transactions": "^6.12.0", + "@stacks/common": "^6.16.0", + "@stacks/network": "^6.17.0", + "@stacks/transactions": "^6.17.0", "jsontokens": "^4.0.1", "schema-inspector": "^2.0.2", "zone-file": "^2.0.0-beta.3" } }, "@stacks/storage": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@stacks/storage/-/storage-6.12.0.tgz", - "integrity": "sha512-RiB8cfWKCm4LrDLXdjtRj4syzvpwmJ/6WKcF+1RHQBTyJerPgxoBn1NoKzjOcydQvVj1jpR/ccaS78xVxlMsTQ==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@stacks/storage/-/storage-6.17.0.tgz", + "integrity": "sha512-vhgV8C+1UahSWrafOHh/ZnTVYs8JadLsh5OZCVgtxWXV7z8ruQzVN24eeXbR+C7Vme2YpDP210ly7Wyqxd755Q==", "requires": { - "@stacks/auth": "^6.12.0", - "@stacks/common": "^6.10.0", - "@stacks/encryption": "^6.12.0", - "@stacks/network": "^6.11.3", + "@stacks/auth": "^6.17.0", + "@stacks/common": "^6.16.0", + "@stacks/encryption": "^6.17.0", + "@stacks/network": "^6.17.0", "base64-js": "^1.5.1", "jsontokens": "^4.0.1" } }, "@stacks/transactions": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.12.0.tgz", - "integrity": "sha512-gRP3SfTaAIoTdjMvOiLrMZb/senqB8JQlT5Y4C3/CiHhiprYwTx7TbOCSa7WsNOU99H4aNfHvatmymuggXQVkA==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.17.0.tgz", + "integrity": "sha512-FUah2BRgV66ApLcEXGNGhwyFTRXqX5Zco3LpiM3essw8PF0NQlHwwdPgtDko5RfrJl3LhGXXe/30nwsfNnB3+g==", "requires": { "@noble/hashes": "1.1.5", "@noble/secp256k1": "1.7.1", - "@stacks/common": "^6.10.0", - "@stacks/network": "^6.11.3", + "@stacks/common": "^6.16.0", + "@stacks/network": "^6.17.0", + "c32check": "^2.0.0", + "lodash.clonedeep": "^4.5.0" + } + }, + "@stacks/transactions-v6": { + "version": "npm:@stacks/transactions@6.17.0", + "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.17.0.tgz", + "integrity": "sha512-FUah2BRgV66ApLcEXGNGhwyFTRXqX5Zco3LpiM3essw8PF0NQlHwwdPgtDko5RfrJl3LhGXXe/30nwsfNnB3+g==", + "requires": { + "@noble/hashes": "1.1.5", + "@noble/secp256k1": "1.7.1", + "@stacks/common": "^6.16.0", + "@stacks/network": "^6.17.0", "c32check": "^2.0.0", "lodash.clonedeep": "^4.5.0" } diff --git a/package.json b/package.json index 8ec6a844..89f77313 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,10 @@ "lint": "next lint" }, "dependencies": { - "@stacks/connect": "^7.7.1", - "@stacks/network": "^6.11.3", - "@stacks/storage": "^6.12.0", - "@stacks/transactions": "^6.12.0", + "@stacks/connect": "^7.8.0", + "@stacks/network": "^6.17.0", + "@stacks/storage": "^6.17.0", + "@stacks/transactions": "^6.17.0", "bootstrap": "^5.2.0", "lodash": "^4.17.21", "nanoid": "^4.0.0", diff --git a/pages/[...id].js b/pages/[...id].js index 4918729b..28202249 100644 --- a/pages/[...id].js +++ b/pages/[...id].js @@ -9,10 +9,11 @@ import { DashboardNavBarComponent } from "../components/common/DashboardNavBarCo import PollComponent from "../components/poll/PollComponent"; import { getIndividualResultByStartAndEndPosition } from "../components/poll/PollService"; import { getMyStxAddress, getStacksAPIPrefix, userSession } from "../services/auth"; +import { getRecentBlock } from "../services/utils"; export default function Poll(props) { // Variables - const { pollObject, pollId, gaiaAddress } = props; + const { pollObject, pollId, gaiaAddress, currentBlockHeight } = props; // Contract transaction status const [txStatus, setTxStatus] = useState(); @@ -229,7 +230,8 @@ export default function Poll(props) { // Fetch STX holdings getSTXHolding(); } else if (pollObject?.strategyContractName && pollObject?.strategyTokenName) { - const response = await fetch(`${getStacksAPIPrefix()}/extended/v1/address/${getMyStxAddress()}/balances`); + const response = await fetch(`${getStacksAPIPrefix()}/extended/v1/address/${getMyStxAddress()}/balances` + + (pollObject?.snapshotBlockHeight ? "?until_block=" + pollObject?.snapshotBlockHeight : "")); const responseObject = await response.json(); if (responseObject?.fungible_tokens && responseObject?.fungible_tokens?.[pollObject?.strategyContractName + "::" + pollObject?.strategyTokenName]) { @@ -260,7 +262,8 @@ export default function Poll(props) { } const getSTXHolding = async () => { - const response = await fetch(`${getStacksAPIPrefix()}/extended/v1/address/${getMyStxAddress()}/stx`); + const response = await fetch(`${getStacksAPIPrefix()}/extended/v1/address/${getMyStxAddress()}/stx` + + (pollObject?.snapshotBlockHeight ? "?until_block=" + pollObject?.snapshotBlockHeight : "")); const responseObject = await response.json(); if (responseObject?.balance !== "0") { @@ -411,7 +414,8 @@ export default function Poll(props) { dns={dns} alreadyVoted={alreadyVoted} noHoldingToken={noHoldingToken} holdingTokenIdsArray={holdingTokenIdsArray} votingPower={votingPower} publicUrl={publicUrl} txStatus={txStatus} - noOfResultsLoaded={noOfResultsLoaded} setNoOfResultsLoaded={setNoOfResultsLoaded} /> + noOfResultsLoaded={noOfResultsLoaded} setNoOfResultsLoaded={setNoOfResultsLoaded} + currentBlockHeight={currentBlockHeight} /> @@ -443,12 +447,17 @@ export async function getServerSideProps(context) { pollObject = await response.json(); } + // Get current block height + const currentBlock = await getRecentBlock(); + const currentBlockHeight = currentBlock?.height || 0; + // Pass data to the page via props return { props: { pollObject, pollId, - gaiaAddress + gaiaAddress, + currentBlockHeight }, }; } \ No newline at end of file diff --git a/services/contract.js b/services/contract.js index 6bbc49ea..65d0a265 100644 --- a/services/contract.js +++ b/services/contract.js @@ -1,5 +1,6 @@ import { openContractCall, openContractDeploy } from "@stacks/connect"; -import { AnchorMode, bufferCV, listCV, stringAsciiCV, uintCV } from "@stacks/transactions"; +import { AnchorMode, bufferCV, FungibleConditionCode, listCV, makeStandardSTXPostCondition, stringAsciiCV, uintCV } from "@stacks/transactions"; +import { Constants } from "../common/constants"; import { getNetworkType } from "../services/auth"; const cancelCallbackFunction = (data) => { @@ -9,6 +10,15 @@ const cancelCallbackFunction = (data) => { export async function deployContract(pollObject, contractName, callbackFunction) { const contract = getContract(pollObject); + // Add an optional post condition + // See below for details on constructing post conditions + const postConditionAddress = Constants.STACKS_MAINNET_FLAG ? Constants.MAINNET_DONATION_ADDRESS : Constants.TESTNET_DONATION_ADDRESS; + const postConditionCode = FungibleConditionCode.GreaterEqual; + const postConditionAmount = 5000000n; + const postConditions = [ + makeStandardSTXPostCondition(postConditionAddress, postConditionCode, postConditionAmount), + ]; + // Transaction options const txOptions = { contractName: contractName, @@ -19,6 +29,7 @@ export async function deployContract(pollObject, contractName, callbackFunction) name: "Ballot", icon: window.location.origin + "/images/logo/ballot.png" }, + postConditions: postConditions, onFinish: callbackFunction, onCancel: cancelCallbackFunction }; @@ -63,10 +74,10 @@ function getContract(pollObject) { } else { // Fungible tokens if (pollObject?.votingStrategyTemplate == "stx") { - strategyFunction = getStrategyFunctionForStxHolders(); + strategyFunction = getStrategyFunctionForStxHolders(pollObject?.snapshotBlockHeight || 0); votingPowerVariable = `(voting-power (get-voting-power-by-stx-holdings))`; } else if (pollObject?.strategyContractName) { - strategyFunction = getStrategyFunctionForFT(pollObject?.strategyContractName); + strategyFunction = getStrategyFunctionForFT(pollObject?.strategyContractName, pollObject?.snapshotBlockHeight || 0); votingPowerVariable = `(voting-power (get-voting-power-by-ft-holdings))`; } } @@ -337,7 +348,12 @@ function getRawContract() { (var-set options (list &{optionIds})) (var-set start u&{startAtBlock}) (var-set end u&{endAtBlock}) - &{optionResults}`; + &{optionResults} + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Supporting Ballot.gg + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + (stx-transfer? u5000000 tx-sender '${Constants.STACKS_MAINNET_FLAG ? Constants.MAINNET_DONATION_ADDRESS : Constants.TESTNET_DONATION_ADDRESS})`; } function getStrategyFunctionForBtcHolders() { @@ -392,7 +408,24 @@ function getStrategyFunctionForNFT(strategyContractName) { )`; } -function getStrategyFunctionForStxHolders() { +function getStrategyFunctionForStxHolders(snapshotBlockHeight) { + if (snapshotBlockHeight > 0) { + return ` + (define-private (get-voting-power-by-stx-holdings) + (at-block (unwrap-panic (get-block-info? id-header-hash u${snapshotBlockHeight})) + (let + ( + (stx-balance (stx-get-balance tx-sender)) + ) + (if (> stx-balance u0) + (/ stx-balance u1000000) + stx-balance + ) + ) + ) + )`; + } + return ` (define-private (get-voting-power-by-stx-holdings) (let @@ -407,7 +440,29 @@ function getStrategyFunctionForStxHolders() { )`; } -function getStrategyFunctionForFT(strategyContractName) { +function getStrategyFunctionForFT(strategyContractName, snapshotBlockHeight) { + if (snapshotBlockHeight > 0) { + return ` + (define-private (get-voting-power-by-ft-holdings) + (at-block (unwrap-panic (get-block-info? id-header-hash u${snapshotBlockHeight})) + (let + ( + (ft-balance (unwrap-panic (contract-call? '${strategyContractName} get-balance tx-sender))) + (ft-decimals (unwrap-panic (contract-call? '${strategyContractName} get-decimals))) + ) + + (if (> ft-balance u0) + (if (> ft-decimals u0) + (/ ft-balance (pow u10 ft-decimals)) + ft-balance + ) + ft-balance + ) + ) + ) + )`; + } + return ` (define-private (get-voting-power-by-ft-holdings) (let diff --git a/services/utils.js b/services/utils.js index 8f3c8d05..0963279c 100644 --- a/services/utils.js +++ b/services/utils.js @@ -187,3 +187,13 @@ export function formatUtcDateTime(dateTimeStr) { // Construct the formatted string return `${day} ${month} ${year}, ${hourFormatted}:${minuteFormatted} ${amPm}`; } + +export const calculateDateByBlockHeight = (currentBlockHeight, targetBlockHeight) => { + if (targetBlockHeight && currentBlockHeight && targetBlockHeight > 0 && currentBlockHeight > 0 && + targetBlockHeight > currentBlockHeight) { + const diff = targetBlockHeight - currentBlockHeight; + const minutes = diff * 10; + + return new Date(new Date().getTime() + (minutes * 60 * 1000)).toISOString(); + } +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 6fbd51e5..aed0ad32 100644 --- a/yarn.lock +++ b/yarn.lock @@ -151,101 +151,188 @@ "@noble/hashes" "~1.1.1" "@scure/base" "~1.1.0" -"@stacks/auth@^6.1.1", "@stacks/auth@^6.12.0": - version "6.12.0" - resolved "https://registry.npmjs.org/@stacks/auth/-/auth-6.12.0.tgz" - integrity sha512-ViSpeWNw1MJBtvykcPTcn9vTy9v8pK8jiQFjfOkiFQ0q+oEhIDQrtpN5OYtTh5HvoZk8du+43nIoUYUECNahHQ== +"@stacks/auth@^6.17.0": + version "6.17.0" + resolved "https://registry.npmjs.org/@stacks/auth/-/auth-6.17.0.tgz" + integrity sha512-SaxB6ULkYLRd5WZotymlPzroBn5/28KgJOTY0nKDcwCqxSkYjPZepweA30LK5eUOmePuGILaMTagj1ibZRnvUg== dependencies: - "@stacks/common" "^6.10.0" - "@stacks/encryption" "^6.12.0" - "@stacks/network" "^6.11.3" - "@stacks/profile" "^6.12.0" + "@stacks/common" "^6.16.0" + "@stacks/encryption" "^6.17.0" + "@stacks/network" "^6.17.0" + "@stacks/profile" "^6.17.0" cross-fetch "^3.1.5" jsontokens "^4.0.1" -"@stacks/common@^6.10.0": - version "6.10.0" - resolved "https://registry.npmjs.org/@stacks/common/-/common-6.10.0.tgz" - integrity sha512-6x5Z7AKd9/kj3+DYE9xIDIkFLHihBH614i2wqrZIjN02WxVo063hWSjIlUxlx8P4gl6olVzlOy5LzhLJD9OP0A== +"@stacks/auth@^7.0.0-next.70": + version "7.0.0" + resolved "https://registry.npmjs.org/@stacks/auth/-/auth-7.0.0.tgz" + integrity sha512-p0/FJy5jRRgtsVzGpWDgNE0fi/ioPCL3S1tZHRsvdKO7moquHWnTlBV/9yVkGbd+V0kD95Sd0euX5pwWA82MhA== + dependencies: + "@noble/secp256k1" "1.7.1" + "@stacks/common" "^7.0.0" + "@stacks/encryption" "^7.0.0" + "@stacks/network" "^7.0.0" + "@stacks/profile" "^7.0.0" + cross-fetch "^3.1.5" + jsontokens "^4.0.1" + +"@stacks/common@^6.16.0": + version "6.16.0" + resolved "https://registry.npmjs.org/@stacks/common/-/common-6.16.0.tgz" + integrity sha512-PnzvhrdGRMVZvxTulitlYafSK4l02gPCBBoI9QEoTqgSnv62oaOXhYAUUkTMFKxdHW1seVEwZsrahuXiZPIAwg== dependencies: "@types/bn.js" "^5.1.0" "@types/node" "^18.0.4" -"@stacks/connect-ui@6.4.1": - version "6.4.1" - resolved "https://registry.npmjs.org/@stacks/connect-ui/-/connect-ui-6.4.1.tgz" - integrity sha512-Y6Fp26MUsMQq08zFSWus40rS7RNHrHj6VDJrFUqM9VsksV3wftpsRcy7psQusUvW1DS7fPza67IlM1dcN4rvSg== +"@stacks/common@^7.0.0", "@stacks/common@^7.0.0-next.70": + version "7.0.0" + resolved "https://registry.npmjs.org/@stacks/common/-/common-7.0.0.tgz" + integrity sha512-/BKBK9S9GEuGjbnc2fBAwsG21f8cfNekG/9mXLSMwBqnh4qaQY2hxK+6wRI2YXJgpkXrpZilpZy2sdPGlVUdQA== + +"@stacks/connect-ui@6.5.0": + version "6.5.0" + resolved "https://registry.npmjs.org/@stacks/connect-ui/-/connect-ui-6.5.0.tgz" + integrity sha512-iXSpl2NxrjERBqtGgkZp0tX1uJgdWZXmsNo3I0cJYYTTbieSAE/Al9nTYc1wLTPW5w5oVvZEkQKo90WIrHR8Rw== dependencies: "@stencil/core" "^2.17.1" -"@stacks/connect@^7.7.1": - version "7.7.1" - resolved "https://registry.npmjs.org/@stacks/connect/-/connect-7.7.1.tgz" - integrity sha512-MwLRhgRLOGo0Y4IDC0qp9RUX2SZubgse1aI2TN/fz2abNIh1LgmOKUua3w17YiBEZxDD9nyQ4KW1c33bdnrOPw== +"@stacks/connect@^7.8.0": + version "7.8.0" + resolved "https://registry.npmjs.org/@stacks/connect/-/connect-7.8.0.tgz" + integrity sha512-whwHygS69XyY/LMvlyp0Whu4mkWkFoJ4Z/Bva9aO1xLLyEVDbKLZnslGWmPs1Io/y76oGEorqVEh0MeLymTIjg== dependencies: - "@stacks/auth" "^6.1.1" - "@stacks/connect-ui" "6.4.1" - "@stacks/network" "^6.1.1" - "@stacks/profile" "^6.1.1" - "@stacks/transactions" "^6.1.1" + "@stacks/auth" "^7.0.0-next.70" + "@stacks/common" "^7.0.0-next.70" + "@stacks/connect-ui" "6.5.0" + "@stacks/network" "^7.0.0-next.70" + "@stacks/network-v6" "npm:@stacks/network@^6.16.0" + "@stacks/profile" "^7.0.0-next.70" + "@stacks/transactions" "^7.0.0-next.70" + "@stacks/transactions-v6" "npm:@stacks/transactions@^6.16.0" jsontokens "^4.0.1" -"@stacks/encryption@^6.12.0": - version "6.12.0" - resolved "https://registry.npmjs.org/@stacks/encryption/-/encryption-6.12.0.tgz" - integrity sha512-CubE51pHrcxx3yA+xapevPgA9UDleIoEaUZ06/9uD91B42yvTg37HyS8t06rzukU9q+X7Cv2I/+vbuf4nJIo8g== +"@stacks/encryption@^6.17.0": + version "6.17.0" + resolved "https://registry.npmjs.org/@stacks/encryption/-/encryption-6.17.0.tgz" + integrity sha512-c0+ZOjrAiB1fDCjXO6XqHdYgpeBeMYyeH+dWahpD1VQUDor2PE5Q47qyuibWmx36rLWt1M6wlaLdeVm6HlKGzw== dependencies: "@noble/hashes" "1.1.5" "@noble/secp256k1" "1.7.1" "@scure/bip39" "1.1.0" - "@stacks/common" "^6.10.0" + "@stacks/common" "^6.16.0" "@types/node" "^18.0.4" base64-js "^1.5.1" bs58 "^5.0.0" ripemd160-min "^0.0.6" varuint-bitcoin "^1.1.2" -"@stacks/network@^6.1.1", "@stacks/network@^6.11.3": - version "6.11.3" - resolved "https://registry.npmjs.org/@stacks/network/-/network-6.11.3.tgz" - integrity sha512-c4ClCU/QUwuu8NbHtDKPJNa0M5YxauLN3vYaR0+S4awbhVIKFQSxirm9Q9ckV1WBh7FtD6u2S0x+tDQGAODjNg== +"@stacks/encryption@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@stacks/encryption/-/encryption-7.0.0.tgz" + integrity sha512-kQhiurn8s0DV6OALqEy2Aqwp2DNJUD41S1bnD/+UESyEDD5XRqL84MEo7mCL8pTPr+FVdhT+diEIPeAfEtbTPQ== dependencies: - "@stacks/common" "^6.10.0" + "@noble/hashes" "1.1.5" + "@noble/secp256k1" "1.7.1" + "@scure/bip39" "1.1.0" + "@stacks/common" "^7.0.0" + base64-js "^1.5.1" + bs58 "^5.0.0" + ripemd160-min "^0.0.6" + varuint-bitcoin "^1.1.2" + +"@stacks/network-v6@npm:@stacks/network@^6.16.0": + version "6.17.0" + resolved "https://registry.npmjs.org/@stacks/network/-/network-6.17.0.tgz" + integrity sha512-numHbfKjwco/rbkGPOEz8+FcJ2nBnS/tdJ8R422Q70h3SiA9eqk9RjSzB8p4JP8yW1SZvW+eihADHfMpBuZyfw== + dependencies: + "@stacks/common" "^6.16.0" cross-fetch "^3.1.5" -"@stacks/profile@^6.1.1", "@stacks/profile@^6.12.0": - version "6.12.0" - resolved "https://registry.npmjs.org/@stacks/profile/-/profile-6.12.0.tgz" - integrity sha512-eY5IpX+GGHIcYLkivDmf3mkxDIgTQ+LhU8UG4jvOqDi+e1DvF9cIi3+reG5KVo0pQzqyT1OS7+16AwVcgp7/og== +"@stacks/network@^6.17.0": + version "6.17.0" + resolved "https://registry.npmjs.org/@stacks/network/-/network-6.17.0.tgz" + integrity sha512-numHbfKjwco/rbkGPOEz8+FcJ2nBnS/tdJ8R422Q70h3SiA9eqk9RjSzB8p4JP8yW1SZvW+eihADHfMpBuZyfw== dependencies: - "@stacks/common" "^6.10.0" - "@stacks/network" "^6.11.3" - "@stacks/transactions" "^6.12.0" + "@stacks/common" "^6.16.0" + cross-fetch "^3.1.5" + +"@stacks/network@^7.0.0", "@stacks/network@^7.0.0-next.70": + version "7.0.0" + resolved "https://registry.npmjs.org/@stacks/network/-/network-7.0.0.tgz" + integrity sha512-4diddT0ii85BQ4PW6ww3l4cS7Oo0a5VIsJ7umBcCPAArIc4Sm/MIOEXIg9joKK8fVHLnWyh1p4D+febJQFfa+Q== + dependencies: + "@stacks/common" "^7.0.0" + cross-fetch "^3.1.5" + +"@stacks/profile@^6.17.0": + version "6.17.0" + resolved "https://registry.npmjs.org/@stacks/profile/-/profile-6.17.0.tgz" + integrity sha512-EoYe0NapFc6bgA+vyCVY2sYYRHk3pbsbRnm3eaSp8y9Drfy8dBqsM10W1jjTwOn0R+IMmDT52lojdW7Pw3c7Mw== + dependencies: + "@stacks/common" "^6.16.0" + "@stacks/network" "^6.17.0" + "@stacks/transactions" "^6.17.0" jsontokens "^4.0.1" schema-inspector "^2.0.2" zone-file "^2.0.0-beta.3" -"@stacks/storage@^6.12.0": - version "6.12.0" - resolved "https://registry.npmjs.org/@stacks/storage/-/storage-6.12.0.tgz" - integrity sha512-RiB8cfWKCm4LrDLXdjtRj4syzvpwmJ/6WKcF+1RHQBTyJerPgxoBn1NoKzjOcydQvVj1jpR/ccaS78xVxlMsTQ== +"@stacks/profile@^7.0.0", "@stacks/profile@^7.0.0-next.70": + version "7.0.0" + resolved "https://registry.npmjs.org/@stacks/profile/-/profile-7.0.0.tgz" + integrity sha512-E9RDodVgcLBs6ZiV88lVQyDjA8ZDVPswbPpLNHeAA+evJ2GwRKMJrNnirjydMI37aWm3ZpYOEMLMbqdi38VR7w== dependencies: - "@stacks/auth" "^6.12.0" - "@stacks/common" "^6.10.0" - "@stacks/encryption" "^6.12.0" - "@stacks/network" "^6.11.3" + "@stacks/common" "^7.0.0" + "@stacks/network" "^7.0.0" + "@stacks/transactions" "^7.0.0" + jsontokens "^4.0.1" + schema-inspector "^2.0.2" + zone-file "^2.0.0-beta.3" + +"@stacks/storage@^6.17.0": + version "6.17.0" + resolved "https://registry.npmjs.org/@stacks/storage/-/storage-6.17.0.tgz" + integrity sha512-vhgV8C+1UahSWrafOHh/ZnTVYs8JadLsh5OZCVgtxWXV7z8ruQzVN24eeXbR+C7Vme2YpDP210ly7Wyqxd755Q== + dependencies: + "@stacks/auth" "^6.17.0" + "@stacks/common" "^6.16.0" + "@stacks/encryption" "^6.17.0" + "@stacks/network" "^6.17.0" base64-js "^1.5.1" jsontokens "^4.0.1" -"@stacks/transactions@^6.1.1", "@stacks/transactions@^6.12.0": - version "6.12.0" - resolved "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.12.0.tgz" - integrity sha512-gRP3SfTaAIoTdjMvOiLrMZb/senqB8JQlT5Y4C3/CiHhiprYwTx7TbOCSa7WsNOU99H4aNfHvatmymuggXQVkA== +"@stacks/transactions-v6@npm:@stacks/transactions@^6.16.0": + version "6.17.0" + resolved "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.17.0.tgz" + integrity sha512-FUah2BRgV66ApLcEXGNGhwyFTRXqX5Zco3LpiM3essw8PF0NQlHwwdPgtDko5RfrJl3LhGXXe/30nwsfNnB3+g== dependencies: "@noble/hashes" "1.1.5" "@noble/secp256k1" "1.7.1" - "@stacks/common" "^6.10.0" - "@stacks/network" "^6.11.3" + "@stacks/common" "^6.16.0" + "@stacks/network" "^6.17.0" + c32check "^2.0.0" + lodash.clonedeep "^4.5.0" + +"@stacks/transactions@^6.17.0": + version "6.17.0" + resolved "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.17.0.tgz" + integrity sha512-FUah2BRgV66ApLcEXGNGhwyFTRXqX5Zco3LpiM3essw8PF0NQlHwwdPgtDko5RfrJl3LhGXXe/30nwsfNnB3+g== + dependencies: + "@noble/hashes" "1.1.5" + "@noble/secp256k1" "1.7.1" + "@stacks/common" "^6.16.0" + "@stacks/network" "^6.17.0" + c32check "^2.0.0" + lodash.clonedeep "^4.5.0" + +"@stacks/transactions@^7.0.0", "@stacks/transactions@^7.0.0-next.70": + version "7.0.0" + resolved "https://registry.npmjs.org/@stacks/transactions/-/transactions-7.0.0.tgz" + integrity sha512-9kGTnJLwRQPugLzbdJ8MmFED+eRhlJKIXpz2mshyy238hvBc4T0jynsoJMi4qGqvJYzsiRYCLDPJVkkUde85vA== + dependencies: + "@noble/hashes" "1.1.5" + "@noble/secp256k1" "1.7.1" + "@stacks/common" "^7.0.0" + "@stacks/network" "^7.0.0" c32check "^2.0.0" lodash.clonedeep "^4.5.0"