diff --git a/apps/playground/src/data/team.ts b/apps/playground/src/data/team.ts index c905e693..3708a923 100644 --- a/apps/playground/src/data/team.ts +++ b/apps/playground/src/data/team.ts @@ -5,13 +5,6 @@ export const team = [ twitter: "https://x.com/abdelkrimdev", github: "https://github.com/abdelkrimdev", }, - { - name: "Jingles", - image: "jingles.png", - twitter: "https://x.com/jinglescode", - github: "https://github.com/jinglescode", - website: "https://jingles.dev/", - }, { name: "Felix", image: "felix.png", @@ -23,6 +16,13 @@ export const team = [ twitter: "https://x.com/HinsonSIDAN", github: "https://github.com/HinsonSIDAN", }, + { + name: "Jingles", + image: "jingles.png", + twitter: "https://x.com/jinglescode", + github: "https://github.com/jinglescode", + website: "https://jingles.dev/", + }, { name: "Tszwai", image: "tszwai.png", diff --git a/apps/playground/src/pages/about/about-us/meeting.tsx b/apps/playground/src/pages/about/about-us/meeting.tsx new file mode 100644 index 00000000..280d37ce --- /dev/null +++ b/apps/playground/src/pages/about/about-us/meeting.tsx @@ -0,0 +1,18 @@ +import Button from "~/components/button/button"; +import Link from "~/components/link"; +import { AboutSection } from "../"; + +export default function AboutMeeting() { + return ( + + <> + + + + + + ); +} diff --git a/apps/playground/src/pages/about/about-us/team.tsx b/apps/playground/src/pages/about/about-us/team.tsx index 6d8c841e..1ea562a1 100644 --- a/apps/playground/src/pages/about/about-us/team.tsx +++ b/apps/playground/src/pages/about/about-us/team.tsx @@ -4,7 +4,7 @@ import { AboutSection } from "../"; export default function AboutTeam() { return ( - +
{team.map((person, i) => ( diff --git a/apps/playground/src/pages/about/index.tsx b/apps/playground/src/pages/about/index.tsx index 0c0d0ed2..7965fca3 100644 --- a/apps/playground/src/pages/about/index.tsx +++ b/apps/playground/src/pages/about/index.tsx @@ -1,5 +1,6 @@ import AboutHero from "./about-us/hero"; import AboutIncorporation from "./about-us/incorporation"; +// import AboutMeeting from "./about-us/meeting"; import AboutStatus from "./about-us/status"; import AboutTeam from "./about-us/team"; @@ -7,6 +8,7 @@ export default function AboutPage() { return ( <> + {/* */} @@ -26,7 +28,7 @@ export function AboutSection({ return (
-
+

{title}

diff --git a/apps/playground/src/pages/apis/txbuilder/governance/index.tsx b/apps/playground/src/pages/apis/txbuilder/governance/index.tsx index a9f5574f..e8a454b3 100644 --- a/apps/playground/src/pages/apis/txbuilder/governance/index.tsx +++ b/apps/playground/src/pages/apis/txbuilder/governance/index.tsx @@ -10,12 +10,14 @@ import { Intro } from "../common"; import GovernanceDeregistration from "./deregistration"; import GovernanceRegistration from "./registration"; import GovernanceVoteDelegation from "./vote-delegation"; +import GovernanceVote from "./vote"; const ReactPage: NextPage = () => { const sidebarItems = [ { label: "DRep Registration", to: "registration" }, { label: "DRep Deregistration", to: "deregistration" }, { label: "Vote Delegation", to: "delegation" }, + { label: "Vote", to: "vote" }, ]; return ( @@ -44,11 +46,12 @@ const ReactPage: NextPage = () => { the Mesh SDK.

- + + ); diff --git a/apps/playground/src/pages/apis/txbuilder/governance/registration.tsx b/apps/playground/src/pages/apis/txbuilder/governance/registration.tsx index 672e2ba7..27ac6f38 100644 --- a/apps/playground/src/pages/apis/txbuilder/governance/registration.tsx +++ b/apps/playground/src/pages/apis/txbuilder/governance/registration.tsx @@ -153,8 +153,17 @@ function Right() { throw new Error("No DRep key found, this wallet does not support CIP95"); const dRepId = dRep.dRepIDCip105; - const anchorHash = await getMeshJsonHash(anchorUrl); + let anchor: { anchorUrl: string; anchorDataHash: string } | undefined = + undefined; + if (anchorUrl.length > 0) { + const anchorHash = await getMeshJsonHash(anchorUrl); + anchor = { + anchorUrl: anchorUrl, + anchorDataHash: anchorHash, + }; + } + // get utxo to pay for the registration const utxos = await wallet.getUtxos(); const registrationFee = "500000000"; @@ -166,10 +175,7 @@ function Right() { const txBuilder = getTxBuilder(); txBuilder - .drepRegistrationCertificate(dRepId, { - anchorUrl: anchorUrl, - anchorDataHash: anchorHash, - }) + .drepRegistrationCertificate(dRepId, anchor) .changeAddress(changeAddress) .selectUtxosFrom(selectedUtxos); diff --git a/apps/playground/src/pages/apis/txbuilder/governance/test-native-script.tsx b/apps/playground/src/pages/apis/txbuilder/governance/test-native-script.tsx deleted file mode 100644 index 0733f54f..00000000 --- a/apps/playground/src/pages/apis/txbuilder/governance/test-native-script.tsx +++ /dev/null @@ -1,326 +0,0 @@ -import { - BrowserWallet, - getFile, - hashDrepAnchor, - keepRelevant, - MeshWallet, - NativeScript, - Quantity, - resolveNativeScriptHash, - resolvePaymentKeyHash, - resolveScriptHashDRepId, - serializeNativeScript, - Unit, -} from "@meshsdk/core"; - -import { getProvider } from "~/components/cardano/mesh-wallet"; -import { getTxBuilder } from "../common"; - -const network = 0; - -async function getMeshJsonHash(url: string) { - var drepAnchor = getFile(url); - const anchorObj = JSON.parse(drepAnchor); - const anchorHash = hashDrepAnchor(anchorObj); - return anchorHash; -} - -function walletsSign(unsignedTx: string) { - const { wallet: walletA } = getWallet(walletASeed); - const { wallet: walletB } = getWallet(walletBSeed); - // const { wallet: walletC } = getWallet(walletCSeed); - - const signedTx1 = walletA.signTx(unsignedTx, true); - const signedTx2 = walletB.signTx(signedTx1, true); - // const signedTx3 = walletC.signTx(signedTx2, true); - return signedTx2; -} - -export async function voteAction(wallet: BrowserWallet) { - // test vote -} - -export async function deregisterDRep(wallet: BrowserWallet) { - const { address: scriptAddress, scriptCbor, dRepId } = getNativeScript(); - - const blockchainProvider = getProvider(); - const utxos = await blockchainProvider.fetchAddressUTxOs(scriptAddress); - const assetMap = new Map(); - assetMap.set("lovelace", "5000000"); - const selectedUtxos = keepRelevant(assetMap, utxos); - if (selectedUtxos.length === 0) throw new Error("No relevant UTxOs found"); - - const txBuilder = getTxBuilder(); - - for (let utxo of selectedUtxos) { - txBuilder.txIn( - utxo.input.txHash, - utxo.input.outputIndex, - utxo.output.amount, - utxo.output.address, - ); - } - - txBuilder - .txInScript(scriptCbor) - .changeAddress(scriptAddress) - .drepDeregistrationCertificate(dRepId, "500000000") - .certificateScript(scriptCbor); - - const unsignedTx = await txBuilder.complete(); - - console.log("Unsigned tx", unsignedTx); - const signedTx = walletsSign(unsignedTx); - console.log("signedTx", signedTx); - - const txHash = await wallet.submitTx(signedTx); - console.log("txHash", txHash); -} - -export async function registerDRep(wallet: BrowserWallet) { - const registrationFee = "500000000"; - - const blockchainProvider = getProvider(); - - const { address: scriptAddress, scriptCbor, dRepId } = getNativeScript(); - - const utxos = await blockchainProvider.fetchAddressUTxOs(scriptAddress); - const assetMap = new Map(); - assetMap.set("lovelace", registrationFee); - const selectedUtxos = keepRelevant(assetMap, utxos); - if (selectedUtxos.length === 0) throw new Error("No relevant UTxOs found"); - - // - - const anchorUrl = "https://meshjs.dev/governance/meshjs.jsonld"; - const anchorHash = await getMeshJsonHash(anchorUrl); - console.log("dRepId", dRepId); - - const txBuilder = getTxBuilder(); - - for (let utxo of selectedUtxos) { - txBuilder.txIn( - utxo.input.txHash, - utxo.input.outputIndex, - utxo.output.amount, - utxo.output.address, - ); - } - - txBuilder - .txInScript(scriptCbor) - .drepRegistrationCertificate(dRepId, { - anchorUrl: anchorUrl, - anchorDataHash: anchorHash, - }) - .certificateScript(scriptCbor) - .changeAddress(scriptAddress) - .selectUtxosFrom(selectedUtxos); - - const unsignedTx = await txBuilder.complete(); - - console.log("Unsigned tx", unsignedTx); - const signedTx = walletsSign(unsignedTx); - console.log("signedTx", signedTx); - - const txHash = await wallet.submitTx(signedTx); - console.log("txHash", txHash); -} - -export async function makePayment(wallet: BrowserWallet) { - const amount = "2000000"; - - const blockchainProvider = getProvider(); - - const { address: scriptAddress, scriptCbor } = getNativeScript(); - const utxos = await blockchainProvider.fetchAddressUTxOs(scriptAddress); - - const assetMap = new Map(); - assetMap.set("lovelace", amount); - - const selectedUtxos = keepRelevant(assetMap, utxos); - - if (selectedUtxos.length === 0) throw new Error("No relevant UTxOs found"); - - const txBuilder = getTxBuilder(); - - for (let utxo of selectedUtxos) { - txBuilder.txIn( - utxo.input.txHash, - utxo.input.outputIndex, - utxo.output.amount, - utxo.output.address, - ); - } - - txBuilder - .txInScript(scriptCbor) - .txOut("addr_test1vpvx0sacufuypa2k4sngk7q40zc5c4npl337uusdh64kv0c7e4cxr", [ - { unit: "lovelace", quantity: amount }, - ]) - .changeAddress(scriptAddress) - .selectUtxosFrom(selectedUtxos); - - const unsignedTx = await txBuilder.complete(); - console.log("unsignedTx", unsignedTx); - - const signedTx = walletsSign(unsignedTx); - - const txHash = await wallet.submitTx(signedTx); - console.log("txHash", txHash); -} - -export function getNativeScript() { - const { walletKeyHash: walletKeyHashA } = getWallet(walletASeed); - const { walletKeyHash: walletKeyHashB } = getWallet(walletBSeed); - const { walletKeyHash: walletKeyHashC } = getWallet(walletCSeed); - - let nativeScript: NativeScript = { - type: "atLeast", - required: 2, - scripts: [ - { - type: "sig", - keyHash: walletKeyHashA, - }, - { - type: "sig", - keyHash: walletKeyHashB, - }, - { - type: "sig", - keyHash: walletKeyHashC, - }, - ], - }; - - const dRepId = resolveScriptHashDRepId(resolveNativeScriptHash(nativeScript)); - const { address, scriptCbor } = serializeNativeScript(nativeScript); - - console.log("Native script address", address); - - return { nativeScript, address, dRepId, scriptCbor: scriptCbor! }; -} - -export function getWallet(seed: string[]) { - const blockchainProvider = getProvider(); - const wallet = new MeshWallet({ - networkId: network, - fetcher: blockchainProvider, - submitter: blockchainProvider, - key: { - type: "mnemonic", - words: seed, - }, - }); - const walletAddress = wallet.getChangeAddress(); - const walletKeyHash = resolvePaymentKeyHash(walletAddress); - return { wallet, walletAddress, walletKeyHash }; -} - -// const walletASeed = [ -// "better", -// "high", -// "alley", -// "magnet", -// "gorilla", -// "tip", -// "kidney", -// "nurse", -// "angry", -// "sweet", -// "scare", -// "cart", -// "also", -// "work", -// "priority", -// "try", -// "stem", -// "rice", -// "clutch", -// "soon", -// "practice", -// "amused", -// "toast", -// "exile", -// ]; -const walletASeed = [ - "culture", - "enroll", - "swim", - "cereal", - "nose", - "caution", - "quantum", - "sight", - "shield", - "audit", - "south", - "deputy", - "find", - "submit", - "sister", - "reduce", - "ten", - "prize", - "track", - "bird", - "spring", - "snap", - "unfair", - "word", -]; -const walletBSeed = [ - "chronic", - "bounce", - "dignity", - "swim", - "naive", - "spread", - "load", - "verify", - "nominee", - "element", - "junk", - "toe", - "carry", - "require", - "silent", - "this", - "shallow", - "hill", - "blade", - "jealous", - "raw", - "cause", - "october", - "until", -]; -const walletCSeed = [ - "cabin", - "bracket", - "empower", - "pottery", - "exhaust", - "rival", - "raccoon", - "pill", - "sniff", - "solar", - "together", - "fantasy", - "company", - "seek", - "output", - "sauce", - "either", - "goddess", - "miracle", - "aim", - "uncover", - "expect", - "joy", - "various", -]; - -export default function Placeholder() {} diff --git a/apps/playground/src/pages/apis/txbuilder/governance/vote.tsx b/apps/playground/src/pages/apis/txbuilder/governance/vote.tsx new file mode 100644 index 00000000..54d4bcd1 --- /dev/null +++ b/apps/playground/src/pages/apis/txbuilder/governance/vote.tsx @@ -0,0 +1,312 @@ +import { useWallet } from "@meshsdk/react"; + +// import { getProvider } from "~/components/cardano/mesh-wallet"; +import Link from "~/components/link"; +import LiveCodeDemo from "~/components/sections/live-code-demo"; +import TwoColumnsScroll from "~/components/sections/two-columns-scroll"; +import Codeblock from "~/components/text/codeblock"; +import { getTxBuilder } from "../common"; + +const govActionTxHash = + "aff2909f8175ee02a8c1bf96ff516685d25bf0c6b95aac91f4dfd53a5c0867cc"; +const govActionTxIndex = 0; + +export default function GovernanceVote() { + return ( + + ); +} + +function Left() { + let codeDrepId = ``; + codeDrepId += `const dRep = await wallet.getDRep();\n`; + codeDrepId += `const dRepId = dRep.dRepIDCip105;\n`; + + let codeWallet = ``; + codeWallet += `const utxos = await wallet.getUtxos();\n`; + codeWallet += `const changeAddress = await wallet.getChangeAddress();\n`; + + let codeTx = ``; + codeTx += `txBuilder\n`; + codeTx += ` .vote(\n`; + codeTx += ` {\n`; + codeTx += ` type: "DRep",\n`; + codeTx += ` drepId: dRepId,\n`; + codeTx += ` },\n`; + codeTx += ` {\n`; + codeTx += ` txHash: '${govActionTxHash}',\n`; + codeTx += ` txIndex: ${govActionTxIndex},\n`; + codeTx += ` },\n`; + codeTx += ` {\n`; + codeTx += ` voteKind: "Yes",\n`; + codeTx += ` },\n`; + codeTx += ` )\n`; + codeTx += ` .selectUtxosFrom(utxos)\n`; + codeTx += ` .changeAddress(changeAddress);\n`; + + let codeSign = `const unsignedTx = await txBuilder.complete();\n`; + codeSign += `const signedTx = await wallet.signTx(unsignedTx);\n`; + codeSign += `const txHash = await wallet.submitTx(signedTx);\n`; + + let codeExample1 = ``; + codeExample1 += `txBuilder\n`; + codeExample1 += ` .changeAddress(\n`; + codeExample1 += ` "addr_test1qpsmz8q2xj43wg597pnpp0ffnlvr8fpfydff0wcsyzqyrxguk5v6wzdvfjyy8q5ysrh8wdxg9h0u4ncse4cxhd7qhqjqk8pse6",\n`; + codeExample1 += ` )\n`; + codeExample1 += ` .txIn(\n`; + codeExample1 += ` "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85",\n`; + codeExample1 += ` 3,\n`; + codeExample1 += ` [\n`; + codeExample1 += ` {\n`; + codeExample1 += ` unit: "lovelace",\n`; + codeExample1 += ` quantity: "9891607895",\n`; + codeExample1 += ` },\n`; + codeExample1 += ` ],\n`; + codeExample1 += ` "addr_test1vru4e2un2tq50q4rv6qzk7t8w34gjdtw3y2uzuqxzj0ldrqqactxh",\n`; + codeExample1 += ` )\n`; + codeExample1 += ` .vote(\n`; + codeExample1 += ` {\n`; + codeExample1 += ` type: "DRep",\n`; + codeExample1 += ` drepId: "drep1j6257gz2swty9ut46lspyvujkt02pd82am2zq97p7p9pv2euzs7",\n`; + codeExample1 += ` },\n`; + codeExample1 += ` {\n`; + codeExample1 += ` txHash:\n`; + codeExample1 += ` "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85",\n`; + codeExample1 += ` txIndex: 3,\n`; + codeExample1 += ` },\n`; + codeExample1 += ` {\n`; + codeExample1 += ` voteKind: "Yes",\n`; + codeExample1 += ` anchor: {\n`; + codeExample1 += ` anchorUrl: "https://path-to.jsonld",\n`; + codeExample1 += ` anchorDataHash:\n`; + codeExample1 += ` "2aef51273a566e529a2d5958d981d7f0b3c7224fc2853b6c4922e019657b5060",\n`; + codeExample1 += ` },\n`; + codeExample1 += ` },\n`; + codeExample1 += ` )\n`; + + let codeExample2 = ``; + codeExample2 += `txBuilder\n`; + codeExample2 += ` .changeAddress(\n`; + codeExample2 += ` "addr_test1qpsmz8q2xj43wg597pnpp0ffnlvr8fpfydff0wcsyzqyrxguk5v6wzdvfjyy8q5ysrh8wdxg9h0u4ncse4cxhd7qhqjqk8pse6",\n`; + codeExample2 += ` )\n`; + codeExample2 += ` .txIn(\n`; + codeExample2 += ` "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85",\n`; + codeExample2 += ` 3,\n`; + codeExample2 += ` [\n`; + codeExample2 += ` {\n`; + codeExample2 += ` unit: "lovelace",\n`; + codeExample2 += ` quantity: "9891607895",\n`; + codeExample2 += ` },\n`; + codeExample2 += ` ],\n`; + codeExample2 += ` "addr_test1vru4e2un2tq50q4rv6qzk7t8w34gjdtw3y2uzuqxzj0ldrqqactxh",\n`; + codeExample2 += ` )\n`; + codeExample2 += ` .txInCollateral(\n`; + codeExample2 += ` "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85",\n`; + codeExample2 += ` 3,\n`; + codeExample2 += ` [\n`; + codeExample2 += ` {\n`; + codeExample2 += ` unit: "lovelace",\n`; + codeExample2 += ` quantity: "9891607895",\n`; + codeExample2 += ` },\n`; + codeExample2 += ` ],\n`; + codeExample2 += ` "addr_test1vru4e2un2tq50q4rv6qzk7t8w34gjdtw3y2uzuqxzj0ldrqqactxh",\n`; + codeExample2 += ` )\n`; + codeExample2 += ` .votePlutusScriptV3()\n`; + codeExample2 += ` .vote(\n`; + codeExample2 += ` {\n`; + codeExample2 += ` type: "DRep",\n`; + codeExample2 += ` drepId: resolveScriptHashDRepId(\n`; + codeExample2 += ` resolveScriptHash(\n`; + codeExample2 += ` applyCborEncoding(\n`; + codeExample2 += ` "5834010100323232322533300232323232324a260106012004600e002600e004600a00260066ea8004526136565734aae795d0aba201",\n`; + codeExample2 += ` ),\n`; + codeExample2 += ` "V3",\n`; + codeExample2 += ` ),\n`; + codeExample2 += ` ),\n`; + codeExample2 += ` },\n`; + codeExample2 += ` {\n`; + codeExample2 += ` txHash:\n`; + codeExample2 += ` "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85",\n`; + codeExample2 += ` txIndex: 3,\n`; + codeExample2 += ` },\n`; + codeExample2 += ` {\n`; + codeExample2 += ` voteKind: "Yes",\n`; + codeExample2 += ` anchor: {\n`; + codeExample2 += ` anchorUrl: "https://path-to.jsonld",\n`; + codeExample2 += ` anchorDataHash:\n`; + codeExample2 += ` "2aef51273a566e529a2d5958d981d7f0b3c7224fc2853b6c4922e019657b5060",\n`; + codeExample2 += ` },\n`; + codeExample2 += ` },\n`; + codeExample2 += ` )\n`; + codeExample2 += ` .voteScript(\n`; + codeExample2 += ` applyCborEncoding(\n`; + codeExample2 += ` "5834010100323232322533300232323232324a260106012004600e002600e004600a00260066ea8004526136565734aae795d0aba201",\n`; + codeExample2 += ` ),\n`; + codeExample2 += ` )\n`; + codeExample2 += ` .voteRedeemerValue("")\n`; + + return ( + <> +

Each vote transaction consists of the following:

+
    +
  • a governance action ID
  • +
  • a role - constitutional committee member, DRep, or SPO
  • +
  • a governance credential witness for the role
  • +
  • + an optional anchor (as defined above) for information that is relevant + to the vote +
  • +
  • a 'Yes'/'No'/'Abstain' vote
  • +
+

+ First, we get the DRep ID from the wallet, the DRep ID voting for this + governance action. +

+ +

Then we get the utxos and the change address from the wallet.

+ +

+ We then create the vote transaction using the vote(){" "} + function. +

+ +

+ The vote() takes 3 parameters: +

+
    +
  • + voter — The voter, can be a Constitutional Commitee, a DRep or a + StakePool +
  • +
  • + govActionId — The transaction hash and transaction id of the + governance action +
  • +
  • + votingProcedure — The voting kind (Yes, No, Abstain) with an optional + anchor +
  • +
+

+ Check the{" "} + + full documentation + {" "} + or the source code for more details. +

+

Finally, we sign the transaction and submit it to the blockchain.

+ + +

+ You can check{" "} + + here + {" "} + a successful vote transaction for this{" "} + + governance action + + . +

+ +

Here is another example of a vote transaction:

+ + +

+ And another example of a vote transaction with a Plutus script and a + redeemer: +

+ + + ); +} + +function Right() { + const { wallet, connected } = useWallet(); + + async function runDemo() { + // const blockchainProvider = getProvider(); + // const proposals = await blockchainProvider.get(`governance/proposals`); + + const dRep = await wallet.getDRep(); + + if (dRep === undefined) + throw new Error("No DRep key found, this wallet does not support CIP95"); + + const dRepId = dRep.dRepIDCip105; + + const utxos = await wallet.getUtxos(); + const changeAddress = await wallet.getChangeAddress(); + + const txBuilder = getTxBuilder(); + txBuilder + .vote( + { + type: "DRep", + drepId: dRepId, + }, + { + txHash: govActionTxHash, + txIndex: govActionTxIndex, + }, + { + voteKind: "Yes", + }, + ) + .selectUtxosFrom(utxos) + .changeAddress(changeAddress); + + const unsignedTx = await txBuilder.complete(); + const signedTx = await wallet.signTx(unsignedTx); + const txHash = await wallet.submitTx(signedTx); + return txHash; + } + + let codeSnippet = ``; + codeSnippet += `const dRep = await wallet.getDRep();\n`; + codeSnippet += `const dRepId = dRep.dRepIDCip105;\n`; + codeSnippet += `\n`; + codeSnippet += `const utxos = await wallet.getUtxos();\n`; + codeSnippet += `const changeAddress = await wallet.getChangeAddress();\n`; + codeSnippet += `\n`; + codeSnippet += `const txBuilder = getTxBuilder();\n`; + codeSnippet += `txBuilder\n`; + codeSnippet += ` .vote(\n`; + codeSnippet += ` {\n`; + codeSnippet += ` type: "DRep",\n`; + codeSnippet += ` drepId: dRepId,\n`; + codeSnippet += ` },\n`; + codeSnippet += ` {\n`; + codeSnippet += ` txHash: '${govActionTxHash}',\n`; + codeSnippet += ` txIndex: ${govActionTxIndex},\n`; + codeSnippet += ` },\n`; + codeSnippet += ` {\n`; + codeSnippet += ` voteKind: "Yes",\n`; + codeSnippet += ` },\n`; + codeSnippet += ` )\n`; + codeSnippet += ` .selectUtxosFrom(utxos)\n`; + codeSnippet += ` .changeAddress(changeAddress);\n`; + codeSnippet += `\n`; + codeSnippet += `const unsignedTx = await txBuilder.complete();\n`; + codeSnippet += `const signedTx = await wallet.signTx(unsignedTx);\n`; + codeSnippet += `const txHash = await wallet.submitTx(signedTx);\n`; + + return ( + + ); +} diff --git a/package-lock.json b/package-lock.json index fffb6f03..dbe77f24 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6993,14 +6993,16 @@ "dev": true }, "node_modules/@sidan-lab/sidan-csl-rs-browser": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/@sidan-lab/sidan-csl-rs-browser/-/sidan-csl-rs-browser-0.8.5.tgz", - "integrity": "sha512-3Fw4dI9i2Y1UXTa1Vm/fNSXDDyKhmV1tGCo8AY9FVrTmpc9Nz3pCNR3SX/fu2004h7i953eyIDogn10Il55Trw==" + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/@sidan-lab/sidan-csl-rs-browser/-/sidan-csl-rs-browser-0.8.7.tgz", + "integrity": "sha512-8Psoxptlv9tyFRXj5YNR+74zeMoMdoLkGLf6jjzlxlD1MnQhw3qlJ3cPNsicDVfffcNRsPMAhicoH5qVWN8AgQ==", + "license": "Apache-2.0" }, "node_modules/@sidan-lab/sidan-csl-rs-nodejs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/@sidan-lab/sidan-csl-rs-nodejs/-/sidan-csl-rs-nodejs-0.8.5.tgz", - "integrity": "sha512-EUs68Yp7pbvF2CYrNKERRVsVY9Z5JBMbEZOYb1NNQgAUyY3zfZ7wHbIM9LJ3RjTuvXtRtRlV+tgwlO+S4Ubz2w==" + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/@sidan-lab/sidan-csl-rs-nodejs/-/sidan-csl-rs-nodejs-0.8.7.tgz", + "integrity": "sha512-IAJyqDgKDesebJ/En4haphBO0zUEuz6mar3TDvtkqng/Kf6Pm7qBPp7vi5Yf2/A/S9Ik6gnIL8XflrGxNoqpVQ==", + "license": "Apache-2.0" }, "node_modules/@sinclair/typebox": { "version": "0.27.8", @@ -9478,6 +9480,7 @@ "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, "funding": [ { "type": "github", @@ -12934,7 +12937,8 @@ "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true }, "node_modules/html-escaper": { "version": "2.0.2", @@ -15800,6 +15804,7 @@ "version": "4.2.8", "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, "engines": { "node": ">=8" } @@ -16035,6 +16040,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -16046,6 +16052,7 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, "bin": { "semver": "bin/semver" } @@ -20458,6 +20465,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -20466,12 +20474,14 @@ "node_modules/spdx-exceptions": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==" + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true }, "node_modules/spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -20480,7 +20490,8 @@ "node_modules/spdx-license-ids": { "version": "3.0.20", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.20.tgz", - "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==" + "integrity": "sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==", + "dev": true }, "node_modules/split-ca": { "version": "1.0.1", @@ -22172,6 +22183,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -22525,6 +22537,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -22536,7 +22549,8 @@ "node_modules/write-file-atomic/node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true }, "node_modules/ws": { "version": "7.5.10", @@ -22729,7 +22743,7 @@ }, "packages/mesh-common": { "name": "@meshsdk/common", - "version": "1.7.5", + "version": "1.7.7", "license": "Apache-2.0", "dependencies": { "bech32": "^2.0.0", @@ -22746,14 +22760,14 @@ }, "packages/mesh-contract": { "name": "@meshsdk/contract", - "version": "1.7.5", + "version": "1.7.7", "license": "Apache-2.0", "dependencies": { - "@meshsdk/common": "1.7.5", - "@meshsdk/core": "1.7.5", - "@meshsdk/core-csl": "1.7.5", - "@meshsdk/core-cst": "1.7.5", - "@meshsdk/transaction": "1.7.5" + "@meshsdk/common": "1.7.7", + "@meshsdk/core": "1.7.7", + "@meshsdk/core-csl": "1.7.7", + "@meshsdk/core-cst": "1.7.7", + "@meshsdk/transaction": "1.7.7" }, "devDependencies": { "@meshsdk/configs": "*", @@ -22764,16 +22778,16 @@ }, "packages/mesh-core": { "name": "@meshsdk/core", - "version": "1.7.5", + "version": "1.7.7", "license": "Apache-2.0", "dependencies": { - "@meshsdk/common": "1.7.5", - "@meshsdk/core-csl": "1.7.5", - "@meshsdk/core-cst": "1.7.5", - "@meshsdk/provider": "1.7.5", - "@meshsdk/react": "1.7.5", - "@meshsdk/transaction": "1.7.5", - "@meshsdk/wallet": "1.7.5" + "@meshsdk/common": "1.7.7", + "@meshsdk/core-csl": "1.7.7", + "@meshsdk/core-cst": "1.7.7", + "@meshsdk/provider": "1.7.7", + "@meshsdk/react": "1.7.7", + "@meshsdk/transaction": "1.7.7", + "@meshsdk/wallet": "1.7.7" }, "devDependencies": { "@meshsdk/configs": "*", @@ -22784,12 +22798,12 @@ }, "packages/mesh-core-csl": { "name": "@meshsdk/core-csl", - "version": "1.7.5", + "version": "1.7.7", "license": "Apache-2.0", "dependencies": { - "@meshsdk/common": "1.7.5", - "@sidan-lab/sidan-csl-rs-browser": "0.8.5", - "@sidan-lab/sidan-csl-rs-nodejs": "0.8.5", + "@meshsdk/common": "1.7.7", + "@sidan-lab/sidan-csl-rs-browser": "0.8.7", + "@sidan-lab/sidan-csl-rs-nodejs": "0.8.7", "json-bigint": "^1.0.0" }, "devDependencies": { @@ -22803,7 +22817,7 @@ }, "packages/mesh-core-cst": { "name": "@meshsdk/core-cst", - "version": "1.7.5", + "version": "1.7.7", "license": "Apache-2.0", "dependencies": { "@cardano-sdk/core": "^0.35.4", @@ -22812,7 +22826,7 @@ "@harmoniclabs/cbor": "1.3.0", "@harmoniclabs/plutus-data": "1.2.4", "@harmoniclabs/uplc": "1.2.4", - "@meshsdk/common": "1.7.5", + "@meshsdk/common": "1.7.7", "@stricahq/bip32ed25519": "^1.1.0", "@stricahq/cbors": "^1.0.0", "pbkdf2": "^3.1.2" @@ -22829,11 +22843,11 @@ }, "packages/mesh-provider": { "name": "@meshsdk/provider", - "version": "1.7.5", + "version": "1.7.7", "license": "Apache-2.0", "dependencies": { - "@meshsdk/common": "1.7.5", - "@meshsdk/core-cst": "1.7.5", + "@meshsdk/common": "1.7.7", + "@meshsdk/core-cst": "1.7.7", "axios": "^1.7.2" }, "devDependencies": { @@ -22845,12 +22859,12 @@ }, "packages/mesh-react": { "name": "@meshsdk/react", - "version": "1.7.5", + "version": "1.7.7", "license": "Apache-2.0", "dependencies": { - "@meshsdk/common": "1.7.5", - "@meshsdk/transaction": "1.7.5", - "@meshsdk/wallet": "1.7.5", + "@meshsdk/common": "1.7.7", + "@meshsdk/transaction": "1.7.7", + "@meshsdk/wallet": "1.7.7", "react": "^18.2.0" }, "devDependencies": { @@ -22865,12 +22879,12 @@ }, "packages/mesh-transaction": { "name": "@meshsdk/transaction", - "version": "1.7.5", + "version": "1.7.7", "license": "Apache-2.0", "dependencies": { - "@meshsdk/common": "1.7.5", - "@meshsdk/core-csl": "1.7.5", - "@meshsdk/core-cst": "1.7.5", + "@meshsdk/common": "1.7.7", + "@meshsdk/core-csl": "1.7.7", + "@meshsdk/core-cst": "1.7.7", "json-bigint": "^1.0.0" }, "devDependencies": { @@ -22883,13 +22897,13 @@ }, "packages/mesh-wallet": { "name": "@meshsdk/wallet", - "version": "1.7.5", + "version": "1.7.7", "license": "Apache-2.0", "dependencies": { - "@meshsdk/common": "1.7.5", - "@meshsdk/core-csl": "1.7.5", - "@meshsdk/core-cst": "1.7.5", - "@meshsdk/transaction": "1.7.5", + "@meshsdk/common": "1.7.7", + "@meshsdk/core-csl": "1.7.7", + "@meshsdk/core-cst": "1.7.7", + "@meshsdk/transaction": "1.7.7", "@nufi/dapp-client-cardano": "^0.3.1", "@nufi/dapp-client-core": "^0.3.1" }, @@ -22903,7 +22917,7 @@ }, "scripts/mesh-cli": { "name": "meshjs", - "version": "1.7.5", + "version": "1.7.7", "license": "Apache-2.0", "dependencies": { "chalk": "5.3.0", diff --git a/packages/mesh-common/package.json b/packages/mesh-common/package.json index 24cc7fef..a5fc4f34 100644 --- a/packages/mesh-common/package.json +++ b/packages/mesh-common/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/common", - "version": "1.7.7", + "version": "1.7.8", "description": "", "main": "./dist/index.cjs", "browser": "./dist/index.js", diff --git a/packages/mesh-common/src/types/transaction-builder/credential.ts b/packages/mesh-common/src/types/transaction-builder/credential.ts new file mode 100644 index 00000000..105d6abc --- /dev/null +++ b/packages/mesh-common/src/types/transaction-builder/credential.ts @@ -0,0 +1,9 @@ +export type Credential = + | { + type: "ScriptHash"; + scriptHash: string; + } + | { + type: "KeyHash"; + keyHash: string; + }; diff --git a/packages/mesh-common/src/types/transaction-builder/index.ts b/packages/mesh-common/src/types/transaction-builder/index.ts index 4fe26add..fa7ac749 100644 --- a/packages/mesh-common/src/types/transaction-builder/index.ts +++ b/packages/mesh-common/src/types/transaction-builder/index.ts @@ -4,6 +4,7 @@ import { Certificate } from "./certificate"; import { MintItem } from "./mint"; import { Output } from "./output"; import { PubKeyTxIn, RefTxIn, TxIn } from "./txin"; +import { Vote } from "./vote"; import { Withdrawal } from "./withdrawal"; export * from "./data"; @@ -13,6 +14,7 @@ export * from "./script"; export * from "./txin"; export * from "./withdrawal"; export * from "./certificate"; +export * from "./vote"; export type MeshTxBuilderBody = { inputs: TxIn[]; @@ -26,6 +28,7 @@ export type MeshTxBuilderBody = { validityRange: ValidityRange; certificates: Certificate[]; withdrawals: Withdrawal[]; + votes: Vote[]; signingKey: string[]; extraInputs: UTxO[]; selectionConfig: { @@ -49,6 +52,7 @@ export const emptyTxBuilderBody = (): MeshTxBuilderBody => ({ validityRange: {}, certificates: [], withdrawals: [], + votes: [], signingKey: [], selectionConfig: { threshold: "0", diff --git a/packages/mesh-common/src/types/transaction-builder/vote.ts b/packages/mesh-common/src/types/transaction-builder/vote.ts new file mode 100644 index 00000000..de6700b9 --- /dev/null +++ b/packages/mesh-common/src/types/transaction-builder/vote.ts @@ -0,0 +1,52 @@ +import { Anchor } from "./certificate"; +import { Credential } from "./credential"; +import { Redeemer } from "./data"; +import { ScriptSource, SimpleScriptSourceInfo } from "./script"; +import { RefTxIn } from "./txin"; + +export type Vote = BasicVote | ScriptVote | SimpleScriptVote; + +export type BasicVote = { + type: "BasicVote"; + vote: VoteType; +}; + +export type SimpleScriptVote = { + type: "SimpleScriptVote"; + vote: VoteType; + simpleScriptSource: SimpleScriptSourceInfo; +}; + +export type ScriptVote = { + type: "ScriptVote"; + vote: VoteType; + redeemer?: Redeemer; + scriptSource?: ScriptSource; +}; + +export type VoteType = { + voter: Voter; + govActionId: RefTxIn; + votingProcedure: VotingProcedure; +}; + +export type Voter = + | { + type: "ConstitutionalCommittee"; + hotCred: Credential; + } + | { + type: "DRep"; + drepId: string; + } + | { + type: "StakingPool"; + keyHash: string; + }; + +export type VotingProcedure = { + voteKind: VoteKind; + anchor?: Anchor; +}; + +export type VoteKind = "Yes" | "No" | "Abstain"; diff --git a/packages/mesh-contract/package.json b/packages/mesh-contract/package.json index 62f79bd5..80b4aef2 100644 --- a/packages/mesh-contract/package.json +++ b/packages/mesh-contract/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/contract", - "version": "1.7.7", + "version": "1.7.8", "description": "", "main": "./dist/index.cjs", "browser": "./dist/index.js", @@ -34,11 +34,11 @@ "typescript": "^5.3.3" }, "dependencies": { - "@meshsdk/common": "1.7.7", - "@meshsdk/core": "1.7.7", - "@meshsdk/core-csl": "1.7.7", - "@meshsdk/core-cst": "1.7.7", - "@meshsdk/transaction": "1.7.7" + "@meshsdk/common": "1.7.8", + "@meshsdk/core": "1.7.8", + "@meshsdk/core-csl": "1.7.8", + "@meshsdk/core-cst": "1.7.8", + "@meshsdk/transaction": "1.7.8" }, "prettier": "@meshsdk/configs/prettier", "publishConfig": { diff --git a/packages/mesh-core-csl/package.json b/packages/mesh-core-csl/package.json index b55f42dd..4b2cb331 100644 --- a/packages/mesh-core-csl/package.json +++ b/packages/mesh-core-csl/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/core-csl", - "version": "1.7.7", + "version": "1.7.8", "description": "", "main": "./dist/index.cjs", "module": "./dist/index.js", @@ -38,9 +38,9 @@ "typescript": "^5.3.3" }, "dependencies": { - "@meshsdk/common": "1.7.7", - "@sidan-lab/sidan-csl-rs-browser": "0.8.5", - "@sidan-lab/sidan-csl-rs-nodejs": "0.8.5", + "@meshsdk/common": "1.7.8", + "@sidan-lab/sidan-csl-rs-browser": "0.8.7", + "@sidan-lab/sidan-csl-rs-nodejs": "0.8.7", "json-bigint": "^1.0.0" }, "prettier": "@meshsdk/configs/prettier", diff --git a/packages/mesh-core-csl/src/core/adaptor/index.ts b/packages/mesh-core-csl/src/core/adaptor/index.ts index ea20a77f..863ceab9 100644 --- a/packages/mesh-core-csl/src/core/adaptor/index.ts +++ b/packages/mesh-core-csl/src/core/adaptor/index.ts @@ -4,6 +4,7 @@ import { certificateToObj } from "./certificate"; import { mintItemToObj } from "./mint"; import { outputToObj } from "./output"; import { collateralTxInToObj, txInToObj } from "./txIn"; +import { voteToObj } from "./vote"; import { withdrawalToObj } from "./withdrawal"; export const meshTxBuilderBodyToObj = ({ @@ -19,6 +20,7 @@ export const meshTxBuilderBodyToObj = ({ certificates, signingKey, withdrawals, + votes, network, }: MeshTxBuilderBody) => { return { @@ -34,6 +36,7 @@ export const meshTxBuilderBodyToObj = ({ certificates: certificates.map(certificateToObj), signingKey: signingKey, withdrawals: withdrawals.map(withdrawalToObj), + votes: votes.map(voteToObj), network, }; }; diff --git a/packages/mesh-core-csl/src/core/adaptor/vote.ts b/packages/mesh-core-csl/src/core/adaptor/vote.ts new file mode 100644 index 00000000..cdcbb3c4 --- /dev/null +++ b/packages/mesh-core-csl/src/core/adaptor/vote.ts @@ -0,0 +1,109 @@ +import { Vote, VoteType } from "@meshsdk/common"; + +import { redeemerToObj } from "./data"; +import { scriptSourceToObj, simpleScriptSourceToObj } from "./script"; + +export const voteToObj = (vote: Vote): object => { + if (vote.type === "BasicVote") { + return { + basicVote: voteTypeToObj(vote.vote), + }; + } else if (vote.type === "ScriptVote") { + if (!vote.scriptSource) { + throw new Error("voteToObj: missing scriptSource in plutusScriptVote."); + } + if (!vote.redeemer) { + throw new Error("voteToObj: missing redeemer in plutusScriptVote."); + } + + return { + scriptVote: { + vote: voteTypeToObj(vote.vote), + redeemer: redeemerToObj(vote.redeemer), + scriptSource: scriptSourceToObj(vote.scriptSource), + }, + }; + } else { + if (!vote.simpleScriptSource) { + throw new Error("voteToObj: missing script source in simpleScriptVote"); + } + + return { + simpleScriptVote: { + vote: voteTypeToObj(vote.vote), + simpleScriptSource: simpleScriptSourceToObj(vote.simpleScriptSource), + }, + }; + } +}; + +const voteTypeToObj = (voteType: VoteType) => { + let voter = {}; + + switch (voteType.voter.type) { + case "ConstitutionalCommittee": { + let ccCred = {}; + switch (voteType.voter.hotCred.type) { + case "ScriptHash": { + ccCred = { + scriptHash: voteType.voter.hotCred.scriptHash, + }; + break; + } + case "KeyHash": { + ccCred = { + keyHash: voteType.voter.hotCred.keyHash, + }; + break; + } + } + voter = { + constitutionalCommitteeHotCred: ccCred, + }; + break; + } + case "DRep": { + voter = { + dRepId: voteType.voter.drepId, + }; + break; + } + case "StakingPool": { + voter = { + stakingPoolKeyHash: voteType.voter.keyHash, + }; + break; + } + } + + let votingProcedure = {}; + switch (voteType.votingProcedure.voteKind) { + case "Yes": { + votingProcedure = { + voteKind: "yes", + anchor: voteType.votingProcedure.anchor ?? null, + }; + break; + } + case "No": { + votingProcedure = { + voteKind: "no", + anchor: voteType.votingProcedure.anchor ?? null, + }; + break; + } + case "Abstain": { + votingProcedure = { + voteKind: "abstain", + anchor: voteType.votingProcedure.anchor ?? null, + }; + break; + } + } + + return { + voter, + votingProcedure, + govActionId: voteType.govActionId, + }; +}; diff --git a/packages/mesh-core-cst/package.json b/packages/mesh-core-cst/package.json index dd9b808e..81159f0b 100644 --- a/packages/mesh-core-cst/package.json +++ b/packages/mesh-core-cst/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/core-cst", - "version": "1.7.7", + "version": "1.7.8", "description": "", "main": "./dist/index.cjs", "browser": "./dist/index.js", @@ -42,7 +42,7 @@ "@harmoniclabs/cbor": "1.3.0", "@harmoniclabs/plutus-data": "1.2.4", "@harmoniclabs/uplc": "1.2.4", - "@meshsdk/common": "1.7.7", + "@meshsdk/common": "1.7.8", "@stricahq/bip32ed25519": "^1.1.0", "@stricahq/cbors": "^1.0.0", "pbkdf2": "^3.1.2" diff --git a/packages/mesh-core/README.md b/packages/mesh-core/README.md index 2b93ca0c..fbd9beec 100644 --- a/packages/mesh-core/README.md +++ b/packages/mesh-core/README.md @@ -1,8 +1,10 @@
- - - + + + + mesh logo +

Mesh TypeScript SDK

diff --git a/packages/mesh-core/package.json b/packages/mesh-core/package.json index 94295ae2..5d3d3ef7 100644 --- a/packages/mesh-core/package.json +++ b/packages/mesh-core/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/core", - "version": "1.7.7", + "version": "1.7.8", "description": "", "main": "./dist/index.cjs", "browser": "./dist/index.js", @@ -33,13 +33,13 @@ "typescript": "^5.3.3" }, "dependencies": { - "@meshsdk/common": "1.7.7", - "@meshsdk/core-csl": "1.7.7", - "@meshsdk/core-cst": "1.7.7", - "@meshsdk/provider": "1.7.7", - "@meshsdk/react": "1.7.7", - "@meshsdk/transaction": "1.7.7", - "@meshsdk/wallet": "1.7.7" + "@meshsdk/common": "1.7.8", + "@meshsdk/core-csl": "1.7.8", + "@meshsdk/core-cst": "1.7.8", + "@meshsdk/provider": "1.7.8", + "@meshsdk/react": "1.7.8", + "@meshsdk/transaction": "1.7.8", + "@meshsdk/wallet": "1.7.8" }, "prettier": "@meshsdk/configs/prettier", "publishConfig": { diff --git a/packages/mesh-provider/package.json b/packages/mesh-provider/package.json index 8ef1ddeb..ca122b7a 100644 --- a/packages/mesh-provider/package.json +++ b/packages/mesh-provider/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/provider", - "version": "1.7.7", + "version": "1.7.8", "description": "", "main": "./dist/index.cjs", "browser": "./dist/index.js", @@ -34,8 +34,8 @@ "typescript": "^5.3.3" }, "dependencies": { - "@meshsdk/common": "1.7.7", - "@meshsdk/core-cst": "1.7.7", + "@meshsdk/common": "1.7.8", + "@meshsdk/core-cst": "1.7.8", "axios": "^1.7.2" }, "prettier": "@meshsdk/configs/prettier", diff --git a/packages/mesh-react/package.json b/packages/mesh-react/package.json index 9ad7bb87..0e391ae5 100644 --- a/packages/mesh-react/package.json +++ b/packages/mesh-react/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/react", - "version": "1.7.7", + "version": "1.7.8", "description": "", "main": "./dist/index.cjs", "browser": "./dist/index.js", @@ -30,9 +30,9 @@ }, "dependencies": { "react": "^18.2.0", - "@meshsdk/common": "1.7.7", - "@meshsdk/transaction": "1.7.7", - "@meshsdk/wallet": "1.7.7" + "@meshsdk/common": "1.7.8", + "@meshsdk/transaction": "1.7.8", + "@meshsdk/wallet": "1.7.8" }, "devDependencies": { "@meshsdk/configs": "*", diff --git a/packages/mesh-transaction/package.json b/packages/mesh-transaction/package.json index 209b72f3..e8941969 100644 --- a/packages/mesh-transaction/package.json +++ b/packages/mesh-transaction/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/transaction", - "version": "1.7.7", + "version": "1.7.8", "description": "", "main": "./dist/index.cjs", "browser": "./dist/index.js", @@ -35,9 +35,9 @@ "typescript": "^5.3.3" }, "dependencies": { - "@meshsdk/common": "1.7.7", - "@meshsdk/core-csl": "1.7.7", - "@meshsdk/core-cst": "1.7.7", + "@meshsdk/common": "1.7.8", + "@meshsdk/core-csl": "1.7.8", + "@meshsdk/core-cst": "1.7.8", "json-bigint": "^1.0.0" }, "prettier": "@meshsdk/configs/prettier", diff --git a/packages/mesh-transaction/src/mesh-tx-builder/tx-builder-core.ts b/packages/mesh-transaction/src/mesh-tx-builder/tx-builder-core.ts index 97ec1069..6cf364a2 100644 --- a/packages/mesh-transaction/src/mesh-tx-builder/tx-builder-core.ts +++ b/packages/mesh-transaction/src/mesh-tx-builder/tx-builder-core.ts @@ -29,6 +29,9 @@ import { UTxO, UtxoSelection, UtxoSelectionStrategy, + Vote, + Voter, + VotingProcedure, Withdrawal, } from "@meshsdk/common"; @@ -41,6 +44,8 @@ export class MeshTxBuilderCore { private plutusMintingScriptVersion: LanguageVersion | undefined; private addingPlutusWithdrawal = false; private plutusWithdrawalScriptVersion: LanguageVersion | undefined; + private addingPlutusVote = false; + private plutusVoteScriptVersion: LanguageVersion | undefined; protected _protocolParams: Protocol = DEFAULT_PROTOCOL_PARAMETERS; @@ -50,6 +55,8 @@ export class MeshTxBuilderCore { protected withdrawalItem?: Withdrawal; + protected voteItem?: Vote; + protected collateralQueueItem?: PubKeyTxIn; protected refScriptTxInQueueItem?: RefTxIn; @@ -758,7 +765,7 @@ export class MeshTxBuilderCore { return this; }; /** - * Set the instruction that it is currently using V1 Plutus withdrawal scripts + * Set the instruction that it is currently using a Plutus withdrawal scripts * @returns The MeshTxBuilder instance */ withdrawalPlutusScriptV1 = () => { @@ -904,6 +911,181 @@ export class MeshTxBuilderCore { return this; }; + /** + * Set the instruction that it is currently using a Plutus voting scripts + * @param languageVersion The Plutus script version + * @returns The MeshTxBuilder instance + */ + votePlutusScript = (languageVersion: LanguageVersion) => { + this.addingPlutusVote = true; + this.plutusVoteScriptVersion = languageVersion; + return this; + }; + /** + * Set the instruction that it is currently using V1 Plutus voting scripts + * @returns The MeshTxBuilder instance + */ + votePlutusScriptV1 = () => { + this.addingPlutusVote = true; + this.plutusVoteScriptVersion = "V1"; + return this; + }; + + /** + * Set the instruction that it is currently using V2 Plutus voting scripts + * @returns The MeshTxBuilder instance + */ + votePlutusScriptV2 = () => { + this.addingPlutusVote = true; + this.plutusVoteScriptVersion = "V2"; + return this; + }; + + /** + * Set the instruction that it is currently using V3 Plutus voting scripts + * @returns The MeshTxBuilder instance + */ + votePlutusScriptV3 = () => { + this.addingPlutusVote = true; + this.plutusVoteScriptVersion = "V3"; + return this; + }; + + /** + * Add a vote in the MeshTxBuilder instance + * @param voter The voter, can be a ConstitutionalCommitee, a DRep or a StakePool + * @param govActionId - The transaction hash and transaction id of the governance action + * @param votingProcedure - The voting kind (Yes, No, Abstain) with an optional anchor + * @returns The MeshTxBuilder instance + */ + vote = ( + voter: Voter, + govActionId: RefTxIn, + votingProcedure: VotingProcedure, + ) => { + if (this.voteItem) { + this.queueVote(); + } + + if (this.addingPlutusVote) { + const vote: Vote = { + type: "ScriptVote", + vote: { + voter, + govActionId, + votingProcedure, + }, + }; + this.voteItem = vote; + } else { + const vote: Vote = { + type: "BasicVote", + vote: { + voter, + govActionId, + votingProcedure, + }, + }; + this.voteItem = vote; + } + return this; + }; + + /** + * Add a voting script to the MeshTxBuilder instance + * @param scriptCbor The script in CBOR format + * @returns The MeshTxBuilder instance + */ + voteScript = (scriptCbor: string) => { + if (!this.voteItem) throw Error("voteScript: Undefined vote"); + if (this.voteItem.type === "BasicVote") { + this.voteItem = { + type: "SimpleScriptVote", + vote: this.voteItem.vote, + simpleScriptSource: { + type: "Provided", + scriptCode: scriptCbor, + }, + }; + } else if (this.voteItem.type === "ScriptVote") { + this.voteItem.scriptSource = { + type: "Provided", + script: { + code: scriptCbor, + version: this.plutusVoteScriptVersion || "V2", + }, + }; + } else if (this.voteItem.type === "SimpleScriptVote") { + throw Error("voteScript: Script is already defined for current vote"); + } + return this; + }; + + /** + * Add a vote reference to the MeshTxBuilder instance + * @param txHash The transaction hash of reference UTxO + * @param txIndex The transaction index of reference UTxO + * @param scriptSize The script size in bytes of the vote script (can be obtained by script hex length / 2) + * @param scriptHash The script hash of the vote script + * @returns The MeshTxBuilder instance + */ + voteTxInReference = ( + txHash: string, + txIndex: number, + scriptSize?: string, + scriptHash?: string, + ) => { + if (!this.voteItem) throw Error("voteTxInReference: Undefined vote"); + if (this.voteItem.type === "BasicVote") + throw Error( + "voteTxInReference: Adding script reference to a basic vote", + ); + if (this.voteItem.type === "ScriptVote") { + this.voteItem.scriptSource = { + type: "Inline", + txHash, + txIndex, + scriptHash, + version: this.plutusWithdrawalScriptVersion || "V2", + scriptSize, + }; + } else if (this.voteItem.type === "SimpleScriptVote") { + this.voteItem.simpleScriptSource = { + type: "Inline", + txHash, + txIndex, + scriptSize, + simpleScriptHash: scriptHash, + }; + } + + return this; + }; + + /** + * Set the transaction vote redeemer value in the MeshTxBuilder instance + * @param redeemer The redeemer in Mesh Data type, JSON in raw constructor like format, or CBOR hex string + * @param type The redeemer data type, either Mesh Data type, JSON in raw constructor like format, or CBOR hex string + * @param exUnits The execution units budget for the redeemer + * @returns The MeshTxBuilder instance + */ + voteRedeemerValue = ( + redeemer: BuilderData["content"], + type: BuilderData["type"] = "Mesh", + exUnits = { ...DEFAULT_REDEEMER_BUDGET }, + ) => { + if (!this.voteItem) throw Error("voteRedeemerValue: Undefined vote"); + if (!(this.voteItem.type === "ScriptVote")) + throw Error("voteRedeemerValue: Adding redeemer to non plutus vote"); + this.voteItem.redeemer = this.castBuilderDataToRedeemer( + redeemer, + type, + exUnits, + ); + + return this; + }; + /** * Creates a pool registration certificate, and adds it to the transaction * @param poolParams Parameters for pool registration @@ -1304,6 +1486,9 @@ export class MeshTxBuilderCore { if (this.withdrawalItem) { this.queueWithdrawal(); } + if (this.voteItem) { + this.queueVote(); + } }; private queueInput = () => { @@ -1359,6 +1544,26 @@ export class MeshTxBuilderCore { this.withdrawalItem = undefined; }; + private queueVote = () => { + if (!this.voteItem) { + throw Error("queueVote: Undefined vote"); + } + if (this.voteItem.type === "ScriptVote") { + if (!this.voteItem.scriptSource) { + throw Error("queueVote: Missing vote script information"); + } + if (!this.voteItem.redeemer) { + throw Error("queueVote: Missing vote redeemer information"); + } + } else if (this.voteItem.type === "SimpleScriptVote") { + if (!this.voteItem.simpleScriptSource) { + throw Error("queueVote: Missing vote script information"); + } + } + this.meshTxBuilderBody.votes.push(this.voteItem); + this.voteItem = undefined; + }; + protected castRawDataToJsonString = (rawData: object | string) => { if (typeof rawData === "object") { return JSONBig.stringify(rawData); @@ -1586,11 +1791,13 @@ export class MeshTxBuilderCore { this.addingPlutusMint = false; this.plutusMintingScriptVersion = undefined; this.addingPlutusWithdrawal = false; + this.addingPlutusVote = false; this.plutusWithdrawalScriptVersion = undefined; this._protocolParams = DEFAULT_PROTOCOL_PARAMETERS; this.mintItem = undefined; this.txInQueueItem = undefined; this.withdrawalItem = undefined; + this.voteItem = undefined; this.collateralQueueItem = undefined; this.refScriptTxInQueueItem = undefined; }; diff --git a/packages/mesh-transaction/test/mesh-tx-builder/tx.test.ts b/packages/mesh-transaction/test/mesh-tx-builder/tx.test.ts index b5765fb6..88ce7d72 100644 --- a/packages/mesh-transaction/test/mesh-tx-builder/tx.test.ts +++ b/packages/mesh-transaction/test/mesh-tx-builder/tx.test.ts @@ -4,8 +4,10 @@ import { NativeScript, resolveNativeScriptHash, resolveNativeScriptHex, + resolveScriptHash, resolveScriptHashDRepId, } from "@meshsdk/core"; +import { applyCborEncoding } from "@meshsdk/core-csl"; import { MeshTxBuilder } from "@meshsdk/transaction"; describe("MeshTxBuilder transactions", () => { @@ -352,4 +354,161 @@ describe("MeshTxBuilder transactions", () => { console.log(txHex); expect(txHex !== "").toBeTruthy(); }); + + it("Drep vote", () => { + let mesh = new MeshTxBuilder(); + + let txHex = mesh + .changeAddress( + "addr_test1qpsmz8q2xj43wg597pnpp0ffnlvr8fpfydff0wcsyzqyrxguk5v6wzdvfjyy8q5ysrh8wdxg9h0u4ncse4cxhd7qhqjqk8pse6", + ) + .txIn( + "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85", + 3, + [ + { + unit: "lovelace", + quantity: "9891607895", + }, + ], + "addr_test1vru4e2un2tq50q4rv6qzk7t8w34gjdtw3y2uzuqxzj0ldrqqactxh", + ) + .vote( + { + type: "DRep", + drepId: "drep1j6257gz2swty9ut46lspyvujkt02pd82am2zq97p7p9pv2euzs7", + }, + { + txHash: + "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85", + txIndex: 3, + }, + { + voteKind: "Yes", + anchor: { + anchorUrl: "https://path-to.jsonld", + anchorDataHash: + "2aef51273a566e529a2d5958d981d7f0b3c7224fc2853b6c4922e019657b5060", + }, + }, + ) + .completeSync(); + + console.log(txHex); + expect(txHex !== "").toBeTruthy(); + }); + + it("Script drep vote", () => { + let mesh = new MeshTxBuilder(); + + let txHex = mesh + .changeAddress( + "addr_test1qpsmz8q2xj43wg597pnpp0ffnlvr8fpfydff0wcsyzqyrxguk5v6wzdvfjyy8q5ysrh8wdxg9h0u4ncse4cxhd7qhqjqk8pse6", + ) + .txIn( + "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85", + 3, + [ + { + unit: "lovelace", + quantity: "9891607895", + }, + ], + "addr_test1vru4e2un2tq50q4rv6qzk7t8w34gjdtw3y2uzuqxzj0ldrqqactxh", + ) + .txInCollateral( + "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85", + 3, + [ + { + unit: "lovelace", + quantity: "9891607895", + }, + ], + "addr_test1vru4e2un2tq50q4rv6qzk7t8w34gjdtw3y2uzuqxzj0ldrqqactxh", + ) + .votePlutusScriptV3() + .vote( + { + type: "DRep", + drepId: resolveScriptHashDRepId( + resolveScriptHash( + applyCborEncoding( + "5834010100323232322533300232323232324a260106012004600e002600e004600a00260066ea8004526136565734aae795d0aba201", + ), + "V3", + ), + ), + }, + { + txHash: + "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85", + txIndex: 3, + }, + { + voteKind: "Yes", + anchor: { + anchorUrl: "https://path-to.jsonld", + anchorDataHash: + "2aef51273a566e529a2d5958d981d7f0b3c7224fc2853b6c4922e019657b5060", + }, + }, + ) + .voteScript( + applyCborEncoding( + "5834010100323232322533300232323232324a260106012004600e002600e004600a00260066ea8004526136565734aae795d0aba201", + ), + ) + .voteRedeemerValue("") + .completeSync(); + + console.log(txHex); + expect(txHex !== "").toBeTruthy(); + }); + + it("CC vote", () => { + let mesh = new MeshTxBuilder(); + + let txHex = mesh + .changeAddress( + "addr_test1qpsmz8q2xj43wg597pnpp0ffnlvr8fpfydff0wcsyzqyrxguk5v6wzdvfjyy8q5ysrh8wdxg9h0u4ncse4cxhd7qhqjqk8pse6", + ) + .txIn( + "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85", + 3, + [ + { + unit: "lovelace", + quantity: "9891607895", + }, + ], + "addr_test1vru4e2un2tq50q4rv6qzk7t8w34gjdtw3y2uzuqxzj0ldrqqactxh", + ) + .vote( + { + type: "ConstitutionalCommittee", + hotCred: { + type: "KeyHash", + keyHash: "e3a4c41d67592a1b8d87c62e5c5d73f7e8db836171945412d13f40f8", + }, + }, + { + txHash: + "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85", + txIndex: 3, + }, + { + voteKind: "Yes", + anchor: { + anchorUrl: "https://path-to.jsonld", + anchorDataHash: + "2aef51273a566e529a2d5958d981d7f0b3c7224fc2853b6c4922e019657b5060", + }, + }, + ) + .completeSync(); + + console.log(txHex); + expect(txHex !== "").toBeTruthy(); + }); }); diff --git a/packages/mesh-wallet/package.json b/packages/mesh-wallet/package.json index 5d5b4c43..e8e68ef0 100644 --- a/packages/mesh-wallet/package.json +++ b/packages/mesh-wallet/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/wallet", - "version": "1.7.7", + "version": "1.7.8", "description": "", "main": "./dist/index.cjs", "browser": "./dist/index.js", @@ -35,10 +35,10 @@ "typescript": "^5.3.3" }, "dependencies": { - "@meshsdk/common": "1.7.7", - "@meshsdk/core-csl": "1.7.7", - "@meshsdk/core-cst": "1.7.7", - "@meshsdk/transaction": "1.7.7", + "@meshsdk/common": "1.7.8", + "@meshsdk/core-csl": "1.7.8", + "@meshsdk/core-cst": "1.7.8", + "@meshsdk/transaction": "1.7.8", "@nufi/dapp-client-cardano": "^0.3.1", "@nufi/dapp-client-core": "^0.3.1" }, diff --git a/scripts/mesh-cli/package.json b/scripts/mesh-cli/package.json index e2fec016..992365f4 100644 --- a/scripts/mesh-cli/package.json +++ b/scripts/mesh-cli/package.json @@ -3,7 +3,7 @@ "description": "A quick and easy way to bootstrap your dApps on Cardano using Mesh.", "homepage": "https://meshjs.dev", "author": "MeshJS", - "version": "1.7.7", + "version": "1.7.8", "license": "Apache-2.0", "type": "module", "main": "./dist/index.cjs",