diff --git a/apps/docs/src/app/layout.tsx b/apps/docs/src/app/layout.tsx index d49b2c70..cc0e10ed 100644 --- a/apps/docs/src/app/layout.tsx +++ b/apps/docs/src/app/layout.tsx @@ -27,7 +27,7 @@ export default async function RootLayout({ params: { package: string }; }) { // const {currentRoute} = useRouteContext(); - // console.log(2, currentRoute) + // let pages = await glob('**/*.mdx', { cwd: 'src/app' }) // let allSectionsEntries = (await Promise.all( // pages.map(async (filename) => [ diff --git a/apps/docs/src/app/page.tsx b/apps/docs/src/app/page.tsx index 877c5782..9af4dcbb 100644 --- a/apps/docs/src/app/page.tsx +++ b/apps/docs/src/app/page.tsx @@ -1,6 +1,6 @@ -import { CodeGroup } from '@/components/Code'; -import { Prose } from '@/components/Prose'; -import Markdown from 'react-markdown'; +import { CodeGroup } from "@/components/Code"; +import { Prose } from "@/components/Prose"; +import Markdown from "react-markdown"; export default function Home() { return ( @@ -35,8 +35,8 @@ export default function Home() { Mesh with npm:

- - npm install @meshsdk/core @meshsdk/react + + npm install @meshsdk/core {/* */} @@ -63,7 +63,6 @@ export default function Home() { // useEffect(() => { // const searchClasses = getClasses().map((meshClass: any) => { -// console.log(11, meshClass); // const _object: any = { url: `/classes/${meshClass.name}`, sections: [] }; @@ -75,17 +74,14 @@ export default function Home() { // _sections.push(_section); -// console.log(11, _section); // getClassGroups(meshClass.name).map((group: any) => { // group.children.map((item: any) => { -// console.log(22, item); // item.signatures?.map((signature: any) => { // const _sectionComments = getSectionComments(signature); // const _section = [item.name, item.name, _sectionComments]; // _sections.push(_section); -// console.log(33, _section); // }); // }); // }); @@ -95,5 +91,4 @@ export default function Home() { // return _object; // }); -// console.log(99, JSON.stringify(searchClasses)) // }, []); diff --git a/apps/playground/src/components/cardano/fetch-utxo-by-datum.ts b/apps/playground/src/components/cardano/fetch-utxo-by-datum.ts index c66a42f4..a6e17bc1 100644 --- a/apps/playground/src/components/cardano/fetch-utxo-by-datum.ts +++ b/apps/playground/src/components/cardano/fetch-utxo-by-datum.ts @@ -13,10 +13,13 @@ export async function fetchAssetUtxo({ }) { const blockchainProvider = getProvider(); const utxos = await blockchainProvider.fetchAddressUTxOs(address, asset); + console.log("utxos", utxos); + const dataHash = resolveDataHash(datum); let utxo = utxos.find((utxo: any) => { return utxo.output.dataHash == dataHash; }); + console.log("utxo", utxo); return utxo; } diff --git a/apps/playground/src/components/cardano/mesh-wallet.ts b/apps/playground/src/components/cardano/mesh-wallet.ts index 15c62efb..4667b024 100644 --- a/apps/playground/src/components/cardano/mesh-wallet.ts +++ b/apps/playground/src/components/cardano/mesh-wallet.ts @@ -6,7 +6,6 @@ export function getProvider(network = "preprod") { export function getMeshWallet() { const blockchainProvider = getProvider(); - const wallet = new MeshWallet({ networkId: 0, fetcher: blockchainProvider, diff --git a/apps/playground/src/components/cardano/mint-mesh-token.tsx b/apps/playground/src/components/cardano/mint-mesh-token.tsx new file mode 100644 index 00000000..cea8558a --- /dev/null +++ b/apps/playground/src/components/cardano/mint-mesh-token.tsx @@ -0,0 +1,61 @@ +import { MeshWallet, ForgeScript, Mint, Transaction } from "@meshsdk/core"; +import { useWallet } from "@meshsdk/react"; + +import { demoAssetMetadata, demoMnemonic } from "~/data/cardano"; +import LiveCodeDemo from "../sections/live-code-demo"; +import { getProvider } from "./mesh-wallet"; + +export default function MintMeshToken() { + const { wallet, connected } = useWallet(); + + async function runDemo() { + const blockchainProvider = getProvider(); + const mintingWallet = new MeshWallet({ + networkId: 0, + fetcher: blockchainProvider, + submitter: blockchainProvider, + key: { + type: "mnemonic", + words: demoMnemonic, + }, + }); + const forgingScript = ForgeScript.withOneSignature( + mintingWallet.getChangeAddress(), + ); + + const usedAddress = await wallet.getUsedAddresses(); + const address = usedAddress[0]; + + const asset: Mint = { + assetName: "MeshToken", + assetQuantity: "1", + metadata: demoAssetMetadata, + label: "721", + recipient: address, + }; + + const tx = new Transaction({ initiator: wallet }); + tx.mintAsset(forgingScript, asset); + + const unsignedTx = await tx.build(); + const signedTx = await wallet.signTx(unsignedTx, true); + const signedTx2 = await mintingWallet.signTx(signedTx, true); + const txHash = await wallet.submitTx(signedTx2); + return txHash; + } + + return ( + + ); +} diff --git a/apps/playground/src/components/sections/live-code-demo.tsx b/apps/playground/src/components/sections/live-code-demo.tsx index 882f809c..9b8ecc52 100644 --- a/apps/playground/src/components/sections/live-code-demo.tsx +++ b/apps/playground/src/components/sections/live-code-demo.tsx @@ -23,6 +23,8 @@ export default function LiveCodeDemo({ runDemoShowBrowseWalletConnect = false, runDemoShowProviderInit = false, runDemoProvider = undefined, + hideDemoButtonIfnotConnected = false, + hideConnectButtonIfConnected = false, }: { children?: React.ReactNode; title: string; @@ -36,6 +38,8 @@ export default function LiveCodeDemo({ runDemoShowBrowseWalletConnect?: boolean; runDemoShowProviderInit?: boolean; runDemoProvider?: string | undefined; + hideDemoButtonIfnotConnected?: boolean; + hideConnectButtonIfConnected?: boolean; }) { const { connected } = useWallet(); const [loading, setLoading] = useState(false); @@ -77,7 +81,7 @@ export default function LiveCodeDemo({ )} - {runCodeFunction && ( + {runCodeFunction && (connected || !hideDemoButtonIfnotConnected) && (
)} - {runDemoShowBrowseWalletConnect && ( -
- -
- )} + {runDemoShowBrowseWalletConnect && + (!connected || !hideConnectButtonIfConnected) && ( +
+ +
+ )} {children && childrenAfterCodeFunctions && (
{children}
diff --git a/apps/playground/src/components/sections/title-icon-description-body.tsx b/apps/playground/src/components/sections/title-icon-description-body.tsx index c19af17c..e4037c27 100644 --- a/apps/playground/src/components/sections/title-icon-description-body.tsx +++ b/apps/playground/src/components/sections/title-icon-description-body.tsx @@ -15,12 +15,12 @@ export default function TitleIconDescriptionBody({ heroicon?: any; }) { return ( - <> +
{title} {description && {description}}
{children}
- +
); } diff --git a/apps/playground/src/contexts/mesh-wallet.tsx b/apps/playground/src/contexts/mesh-wallet.tsx index eb48ce0b..8b93c50d 100644 --- a/apps/playground/src/contexts/mesh-wallet.tsx +++ b/apps/playground/src/contexts/mesh-wallet.tsx @@ -25,6 +25,7 @@ export const MeshWalletProvider = ({ if (!walletConnected) { const _wallet = getMeshWallet(); setWallet(_wallet); + return _wallet; } return wallet; } diff --git a/apps/playground/src/data/links-api.ts b/apps/playground/src/data/links-api.ts index b0975b52..35c0fabd 100644 --- a/apps/playground/src/data/links-api.ts +++ b/apps/playground/src/data/links-api.ts @@ -3,14 +3,14 @@ import { metaData } from "./links-data"; import { metaProviders } from "./links-providers"; import { metaReact } from "./links-react"; import { metaTransaction } from "./links-transactions"; -// import { metaTxbuilder } from "./links-txbuilders"; +import { metaTxbuilder } from "./links-txbuilders"; import { metaUtilities } from "./links-utilities"; import { metaWallets } from "./links-wallets"; export const linksApi: MenuItem[] = [ metaWallets, metaTransaction, - // metaTxbuilder, // todo, work on txbuilder docs + metaTxbuilder, // todo, work on txbuilder docs metaData, metaReact, metaProviders, diff --git a/apps/playground/src/data/links-txbuilders.ts b/apps/playground/src/data/links-txbuilders.ts index 430e0e86..64631a93 100644 --- a/apps/playground/src/data/links-txbuilders.ts +++ b/apps/playground/src/data/links-txbuilders.ts @@ -36,9 +36,9 @@ export const metaTxbuilderStaking = { export const linksTxbuilder = [ metaTxbuilderBasic, - metaTxbuilderMinting, - metaTxbuilderSmartContract, - metaTxbuilderStaking, + // metaTxbuilderMinting, + // metaTxbuilderSmartContract, + // metaTxbuilderStaking, ]; export const metaTxbuilder = { diff --git a/apps/playground/src/pages/about/support-us/donate-section.tsx b/apps/playground/src/pages/about/support-us/donate-section.tsx index 5931f7e7..c8350996 100644 --- a/apps/playground/src/pages/about/support-us/donate-section.tsx +++ b/apps/playground/src/pages/about/support-us/donate-section.tsx @@ -38,8 +38,7 @@ export default function SendPayment() { ); const signedTx = await wallet.signTx(unsignedTx, true); - const txHash = await wallet.submitTx(signedTx); - console.log({ txHash }); + await wallet.submitTx(signedTx); setLoading(false); setDone(true); diff --git a/apps/playground/src/pages/apis/data/utils/assets-to-plutus-value.tsx b/apps/playground/src/pages/apis/data/utils/assets-to-plutus-value.tsx index 5b67b31d..95b42f59 100644 --- a/apps/playground/src/pages/apis/data/utils/assets-to-plutus-value.tsx +++ b/apps/playground/src/pages/apis/data/utils/assets-to-plutus-value.tsx @@ -1,4 +1,4 @@ -import { Asset, parsePlutusValueToAssets, value, Value } from "@meshsdk/core"; +import { Asset, value, Value } from "@meshsdk/core"; import LiveCodeDemo from "~/components/sections/live-code-demo"; import TwoColumnsScroll from "~/components/sections/two-columns-scroll"; @@ -9,7 +9,7 @@ export default function DataAssetsToPlutusValue() { sidebarTo="DataAssetsToPlutusValue" title="Assets to Plutus Value" leftSection={Left()} - rightSection={Right()} + // rightSection={Right()} /> ); } @@ -35,109 +35,109 @@ function Left() { ); } -function Right() { - return ( - <> - - - - - ); -} - -function ADAValue() { - async function runDemo() { - const val: Asset[] = [{ unit: "lovelace", quantity: "1000000" }]; - const plutusValue: Value = value(val); - return plutusValue; - } - - let code = `import { Asset, parsePlutusValueToAssets, value, Value } from "@meshsdk/core";\n\n`; - code += `const val: Asset[] = [{ unit: "lovelace", quantity: "1000000" }];\n\n`; - code += `const plutusValue: Value = value(val);\n`; - - return ( - - ); -} - -function TokenValue() { - async function runDemo() { - const val: Asset[] = [ - { - unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", - quantity: "345", - }, - ]; - const plutusValue: Value = value(val); - return plutusValue; - } - - let code = `import { Asset, parsePlutusValueToAssets, value, Value } from "@meshsdk/core";\n\n`; - - code += `const val: Asset[] = [\n`; - code += ` {\n`; - code += ` unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461",\n`; - code += ` quantity: "345",\n`; - code += ` },\n`; - code += `];\n\n`; - - code += `const plutusValue: Value = value(val);\n`; - - return ( - - ); -} - -function MultipleValue() { - async function runDemo() { - const val: Asset[] = [ - { unit: "lovelace", quantity: "1000000" }, - { - unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc817001234", - quantity: "567", - }, - { - unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", - quantity: "345", - }, - ]; - const plutusValue: Value = value(val); - return plutusValue; - } - - let code = `import { Asset, parsePlutusValueToAssets, value, Value } from "@meshsdk/core";\n\n`; - - code += `const val: Asset[] = [\n`; - code += ` { unit: "lovelace", quantity: "1000000" },\n`; - code += ` {\n`; - code += ` unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc817001234",\n`; - code += ` quantity: "567",\n`; - code += ` },\n`; - code += ` {\n`; - code += ` unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461",\n`; - code += ` quantity: "345",\n`; - code += ` },\n`; - code += `];\n\n`; - - code += `const plutusValue: Value = value(val);\n`; - - return ( - - ); -} +// function Right() { +// return ( +// <> +// +// +// +// +// ); +// } + +// function ADAValue() { +// async function runDemo() { +// const val: Asset[] = [{ unit: "lovelace", quantity: "1000000" }]; +// const plutusValue: Value = value(val); +// return plutusValue; +// } + +// let code = `import { Asset, parsePlutusValueToAssets, value, Value } from "@meshsdk/core";\n\n`; +// code += `const val: Asset[] = [{ unit: "lovelace", quantity: "1000000" }];\n\n`; +// code += `const plutusValue: Value = value(val);\n`; + +// return ( +// +// ); +// } + +// function TokenValue() { +// async function runDemo() { +// const val: Asset[] = [ +// { +// unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", +// quantity: "345", +// }, +// ]; +// const plutusValue: Value = value(val); +// return plutusValue; +// } + +// let code = `import { Asset, parsePlutusValueToAssets, value, Value } from "@meshsdk/core";\n\n`; + +// code += `const val: Asset[] = [\n`; +// code += ` {\n`; +// code += ` unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461",\n`; +// code += ` quantity: "345",\n`; +// code += ` },\n`; +// code += `];\n\n`; + +// code += `const plutusValue: Value = value(val);\n`; + +// return ( +// +// ); +// } + +// function MultipleValue() { +// async function runDemo() { +// const val: Asset[] = [ +// { unit: "lovelace", quantity: "1000000" }, +// { +// unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc817001234", +// quantity: "567", +// }, +// { +// unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", +// quantity: "345", +// }, +// ]; +// const plutusValue: Value = value(val); +// return plutusValue; +// } + +// let code = `import { Asset, parsePlutusValueToAssets, value, Value } from "@meshsdk/core";\n\n`; + +// code += `const val: Asset[] = [\n`; +// code += ` { unit: "lovelace", quantity: "1000000" },\n`; +// code += ` {\n`; +// code += ` unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc817001234",\n`; +// code += ` quantity: "567",\n`; +// code += ` },\n`; +// code += ` {\n`; +// code += ` unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461",\n`; +// code += ` quantity: "345",\n`; +// code += ` },\n`; +// code += `];\n\n`; + +// code += `const plutusValue: Value = value(val);\n`; + +// return ( +// +// ); +// } diff --git a/apps/playground/src/pages/apis/data/utils/index.tsx b/apps/playground/src/pages/apis/data/utils/index.tsx index 57df7d4a..0a379479 100644 --- a/apps/playground/src/pages/apis/data/utils/index.tsx +++ b/apps/playground/src/pages/apis/data/utils/index.tsx @@ -4,9 +4,9 @@ import SidebarFullwidth from "~/components/layouts/sidebar-fullwidth"; import TitleIconDescriptionBody from "~/components/sections/title-icon-description-body"; import Metatags from "~/components/site/metatags"; import { metaDataUtils } from "~/data/links-data"; -import DataAssetsToPlutusValue from "./assets-to-plutus-value"; +// import DataAssetsToPlutusValue from "./assets-to-plutus-value"; import DataPlutusPlutusArrayString from "./plutus-array-to-string"; -import DataPlutusValueToAssets from "./plutus-value-to-assets"; +// import DataPlutusValueToAssets from "./plutus-value-to-assets"; import DataPlutusStringPlutusArray from "./string-to-plutus-array"; const ReactPage: NextPage = () => { @@ -55,8 +55,8 @@ const ReactPage: NextPage = () => { - - + {/* + */} ); diff --git a/apps/playground/src/pages/apis/data/utils/plutus-value-to-assets.tsx b/apps/playground/src/pages/apis/data/utils/plutus-value-to-assets.tsx index 4e4c2f4a..2231866b 100644 --- a/apps/playground/src/pages/apis/data/utils/plutus-value-to-assets.tsx +++ b/apps/playground/src/pages/apis/data/utils/plutus-value-to-assets.tsx @@ -1,4 +1,4 @@ -import { Asset, parsePlutusValueToAssets, value, Value } from "@meshsdk/core"; +import { Asset, value, Value } from "@meshsdk/core"; import LiveCodeDemo from "~/components/sections/live-code-demo"; import TwoColumnsScroll from "~/components/sections/two-columns-scroll"; @@ -9,7 +9,7 @@ export default function DataPlutusValueToAssets() { sidebarTo="DataPlutusValueToAssets" title="Plutus Value to Assets" leftSection={Left()} - rightSection={Right()} + // rightSection={Right()} /> ); } @@ -32,115 +32,115 @@ function Left() { ); } -function Right() { - return ( - <> - - - - - ); -} - -function ADAValue() { - async function runDemo() { - const val: Asset[] = [{ unit: "lovelace", quantity: "1000000" }]; - const plutusValue: Value = value(val); - const assets: Asset[] = parsePlutusValueToAssets(plutusValue); - return assets; - } - - let code = `import { Asset, parsePlutusValueToAssets, value, Value } from "@meshsdk/core";\n\n`; - code += `const val: Asset[] = [{ unit: "lovelace", quantity: "1000000" }];\n\n`; - code += `const plutusValue: Value = value(val);\n`; - code += `parsePlutusValueToAssets(plutusValue);\n`; - - return ( - - ); -} - -function TokenValue() { - async function runDemo() { - const val: Asset[] = [ - { - unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", - quantity: "345", - }, - ]; - const plutusValue: Value = value(val); - const assets: Asset[] = parsePlutusValueToAssets(plutusValue); - return assets; - } - - let code = `import { Asset, parsePlutusValueToAssets, value, Value } from "@meshsdk/core";\n\n`; - - code += `const val: Asset[] = [\n`; - code += ` {\n`; - code += ` unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461",\n`; - code += ` quantity: "345",\n`; - code += ` },\n`; - code += `];\n\n`; - - code += `const plutusValue: Value = value(val);\n`; - code += `parsePlutusValueToAssets(plutusValue);\n`; - - return ( - - ); -} - -function MultipleValue() { - async function runDemo() { - const val: Asset[] = [ - { unit: "lovelace", quantity: "1000000" }, - { - unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc817001234", - quantity: "567", - }, - { - unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", - quantity: "345", - }, - ]; - const plutusValue: Value = value(val); - const assets: Asset[] = parsePlutusValueToAssets(plutusValue); - return assets; - } - - let code = `import { Asset, parsePlutusValueToAssets, value, Value } from "@meshsdk/core";\n\n`; - - code += `const val: Asset[] = [\n`; - code += ` { unit: "lovelace", quantity: "1000000" },\n`; - code += ` {\n`; - code += ` unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc817001234",\n`; - code += ` quantity: "567",\n`; - code += ` },\n`; - code += ` {\n`; - code += ` unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461",\n`; - code += ` quantity: "345",\n`; - code += ` },\n`; - code += `];\n\n`; - - code += `const plutusValue: Value = value(val);\n`; - code += `parsePlutusValueToAssets(plutusValue);\n`; - - return ( - - ); -} +// function Right() { +// return ( +// <> +// +// +// +// +// ); +// } + +// function ADAValue() { +// async function runDemo() { +// const val: Asset[] = [{ unit: "lovelace", quantity: "1000000" }]; +// const plutusValue: Value = value(val); +// const assets: Asset[] = parsePlutusValueToAssets(plutusValue); +// return assets; +// } + +// let code = `import { Asset, parsePlutusValueToAssets, value, Value } from "@meshsdk/core";\n\n`; +// code += `const val: Asset[] = [{ unit: "lovelace", quantity: "1000000" }];\n\n`; +// code += `const plutusValue: Value = value(val);\n`; +// code += `parsePlutusValueToAssets(plutusValue);\n`; + +// return ( +// +// ); +// } + +// function TokenValue() { +// async function runDemo() { +// const val: Asset[] = [ +// { +// unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", +// quantity: "345", +// }, +// ]; +// const plutusValue: Value = value(val); +// const assets: Asset[] = parsePlutusValueToAssets(plutusValue); +// return assets; +// } + +// let code = `import { Asset, parsePlutusValueToAssets, value, Value } from "@meshsdk/core";\n\n`; + +// code += `const val: Asset[] = [\n`; +// code += ` {\n`; +// code += ` unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461",\n`; +// code += ` quantity: "345",\n`; +// code += ` },\n`; +// code += `];\n\n`; + +// code += `const plutusValue: Value = value(val);\n`; +// code += `parsePlutusValueToAssets(plutusValue);\n`; + +// return ( +// +// ); +// } + +// function MultipleValue() { +// async function runDemo() { +// const val: Asset[] = [ +// { unit: "lovelace", quantity: "1000000" }, +// { +// unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc817001234", +// quantity: "567", +// }, +// { +// unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", +// quantity: "345", +// }, +// ]; +// const plutusValue: Value = value(val); +// const assets: Asset[] = parsePlutusValueToAssets(plutusValue); +// return assets; +// } + +// let code = `import { Asset, parsePlutusValueToAssets, value, Value } from "@meshsdk/core";\n\n`; + +// code += `const val: Asset[] = [\n`; +// code += ` { unit: "lovelace", quantity: "1000000" },\n`; +// code += ` {\n`; +// code += ` unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc817001234",\n`; +// code += ` quantity: "567",\n`; +// code += ` },\n`; +// code += ` {\n`; +// code += ` unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461",\n`; +// code += ` quantity: "345",\n`; +// code += ` },\n`; +// code += `];\n\n`; + +// code += `const plutusValue: Value = value(val);\n`; +// code += `parsePlutusValueToAssets(plutusValue);\n`; + +// return ( +// +// ); +// } diff --git a/apps/playground/src/pages/apis/transaction/basics/coin-selection.tsx b/apps/playground/src/pages/apis/transaction/basics/coin-selection.tsx index 0a11e986..a2e271c3 100644 --- a/apps/playground/src/pages/apis/transaction/basics/coin-selection.tsx +++ b/apps/playground/src/pages/apis/transaction/basics/coin-selection.tsx @@ -107,20 +107,20 @@ function Left() { then it will try to also pick up another UTxO from the wallet, containing the largest amount of lovelace.

- +

Here is an example how you can use keepRelevant():

- +

Largest First

To select UTXOs for transaction that only requires lovelace, use{" "} largestFirst.

- +

For example, selecting the UTXOs for sending 10000000 lovelace:

- +

Largest First Multi-Asset

@@ -128,7 +128,7 @@ function Left() { assets you require for sending out by defining a Map. The Map is matches the Unit with the quantity of each asset.

- +

Note that if lovelace, aside from the "minimum Ada" which in any case needs to accompany the other assets, this must be explicitly specified. @@ -137,7 +137,7 @@ function Left() { all multiasset UTxOs from the selection, which can result in more efficient selection of the required UTxOs.

- +

The third parameter is includeTxFees. If True, Mesh will calculate the fees required for the transaction, and include diff --git a/apps/playground/src/pages/apis/transaction/basics/index.tsx b/apps/playground/src/pages/apis/transaction/basics/index.tsx index b4aa4193..59c88e0d 100644 --- a/apps/playground/src/pages/apis/transaction/basics/index.tsx +++ b/apps/playground/src/pages/apis/transaction/basics/index.tsx @@ -3,13 +3,13 @@ import type { NextPage } from "next"; import SidebarFullwidth from "~/components/layouts/sidebar-fullwidth"; import TitleIconDescriptionBody from "~/components/sections/title-icon-description-body"; import Metatags from "~/components/site/metatags"; -import Codeblock from "~/components/text/codeblock"; import { metaTransactionBasic } from "~/data/links-transactions"; import { Intro } from "../common"; import TransactionBegin from "./begin"; import TransactionCip20 from "./cip20"; import TransactionCoinSelection from "./coin-selection"; import TransactionHandle from "./handle"; +import TransactionMultisig from "./multisig"; import TransactionSendAssets from "./send-assets"; import TransactionSendLovelace from "./send-lovelace"; import TransactionSendValue from "./send-value"; @@ -23,6 +23,7 @@ const ReactPage: NextPage = () => { { label: "Send lovelace", to: "sendLovelace" }, { label: "Send assets", to: "sendAssets" }, { label: "Send value", to: "sendValue" }, + { label: "Multi-signature", to: "multisig" }, { label: "Send assets to Handle", to: "handler" }, { label: "Send assets to Begin ID", to: "begin" }, @@ -64,6 +65,7 @@ const ReactPage: NextPage = () => { + diff --git a/apps/playground/src/pages/apis/transaction/basics/multisig.tsx b/apps/playground/src/pages/apis/transaction/basics/multisig.tsx new file mode 100644 index 00000000..979eb550 --- /dev/null +++ b/apps/playground/src/pages/apis/transaction/basics/multisig.tsx @@ -0,0 +1,136 @@ +import { MeshWallet, ForgeScript, Mint, Transaction } from "@meshsdk/core"; +import { useWallet } from "@meshsdk/react"; + +import { getProvider } from "~/components/cardano/mesh-wallet"; +import LiveCodeDemo from "~/components/sections/live-code-demo"; +import TwoColumnsScroll from "~/components/sections/two-columns-scroll"; +import Codeblock from "~/components/text/codeblock"; +import { demoAssetMetadata, demoMnemonic } from "~/data/cardano"; + +export default function TransactionMultisig() { + return ( + + ); +} + +function Left() { + let codeTx = ``; + codeTx += `const tx = new Transaction({ initiator: wallet });\n`; + codeTx += `tx.mintAsset(forgingScript, asset);\n`; + codeTx += `\n`; + codeTx += `const unsignedTx = await tx.build();\n`; + codeTx += `const signedTx = await wallet.signTx(unsignedTx, true);\n`; + codeTx += `const signedTx2 = await mintingWallet.signTx(signedTx, true);\n`; + + let codeSign = `await wallet.signTx(unsignedTx, true);`; + + return ( + <> +

+ The main idea of a multi-signature transaction is to have multiple + signatures to authorize a transaction. +

+ +

+ In the above code snippet, we are signing the transaction with the user + wallet and then signing the transaction with the minting wallet. The + signTx function is used to sign the transaction. The second + argument is a boolean value that indicates whether the transaction is a + multi-signature transaction. +

+ + + ); +} + +function Right() { + const { wallet, connected } = useWallet(); + + async function runDemo() { + const blockchainProvider = getProvider(); + const mintingWallet = new MeshWallet({ + networkId: 0, + fetcher: blockchainProvider, + submitter: blockchainProvider, + key: { + type: "mnemonic", + words: demoMnemonic, + }, + }); + const forgingScript = ForgeScript.withOneSignature( + mintingWallet.getChangeAddress(), + ); + + const usedAddress = await wallet.getUsedAddresses(); + const address = usedAddress[0]; + + const asset: Mint = { + assetName: "MeshToken", + assetQuantity: "1", + metadata: demoAssetMetadata, + label: "721", + recipient: address, + }; + + const tx = new Transaction({ initiator: wallet }); + tx.mintAsset(forgingScript, asset); + + const unsignedTx = await tx.build(); + const signedTx = await wallet.signTx(unsignedTx, true); + const signedTx2 = await mintingWallet.signTx(signedTx, true); + const txHash = await wallet.submitTx(signedTx2); + return txHash; + } + + let codeSnippet = `import { MeshWallet, ForgeScript, Mint, Transaction } from '@meshsdk/core';\n\n`; + codeSnippet += `const mintingWallet = new MeshWallet({\n`; + codeSnippet += ` networkId: 0,\n`; + codeSnippet += ` fetcher: blockchainProvider,\n`; + codeSnippet += ` submitter: blockchainProvider,\n`; + codeSnippet += ` key: {\n`; + codeSnippet += ` type: "mnemonic",\n`; + codeSnippet += ` words: demoMnemonic,\n`; + codeSnippet += ` },\n`; + codeSnippet += `});\n`; + codeSnippet += `const forgingScript = ForgeScript.withOneSignature(\n`; + codeSnippet += ` mintingWallet.getChangeAddress(),\n`; + codeSnippet += `);\n`; + codeSnippet += `\n`; + codeSnippet += `const usedAddress = await wallet.getUsedAddresses();\n`; + codeSnippet += `const address = usedAddress[0];\n`; + codeSnippet += `\n`; + codeSnippet += `const asset: Mint = {\n`; + codeSnippet += ` assetName: "MeshToken",\n`; + codeSnippet += ` assetQuantity: "1",\n`; + codeSnippet += ` metadata: demoAssetMetadata,\n`; + codeSnippet += ` label: "721",\n`; + codeSnippet += ` recipient: address,\n`; + codeSnippet += `};\n`; + codeSnippet += `\n`; + codeSnippet += `const tx = new Transaction({ initiator: wallet });\n`; + codeSnippet += `tx.mintAsset(forgingScript, asset);\n`; + codeSnippet += `\n`; + codeSnippet += `const unsignedTx = await tx.build();\n`; + codeSnippet += `const signedTx = await wallet.signTx(unsignedTx, true);\n`; + codeSnippet += `const signedTx2 = await mintingWallet.signTx(signedTx, true);\n`; + codeSnippet += `const txHash = await wallet.submitTx(signedTx2);\n`; + + return ( + + ); +} diff --git a/apps/playground/src/pages/apis/transaction/minting/burning-one-signature.tsx b/apps/playground/src/pages/apis/transaction/minting/burning-one-signature.tsx index ebc24c5f..69b77ab8 100644 --- a/apps/playground/src/pages/apis/transaction/minting/burning-one-signature.tsx +++ b/apps/playground/src/pages/apis/transaction/minting/burning-one-signature.tsx @@ -63,13 +63,13 @@ function Left(userInput: string) { "minting address". Note that, assets can only be burned by its minting address.

- +

Then, we define Asset and set tx.burnAsset()

- +

Here is the full code:

- + ); } diff --git a/apps/playground/src/pages/apis/transaction/minting/index.tsx b/apps/playground/src/pages/apis/transaction/minting/index.tsx index 69e44880..b348f370 100644 --- a/apps/playground/src/pages/apis/transaction/minting/index.tsx +++ b/apps/playground/src/pages/apis/transaction/minting/index.tsx @@ -3,7 +3,6 @@ import type { NextPage } from "next"; import SidebarFullwidth from "~/components/layouts/sidebar-fullwidth"; import TitleIconDescriptionBody from "~/components/sections/title-icon-description-body"; import Metatags from "~/components/site/metatags"; -import Codeblock from "~/components/text/codeblock"; import { metaMinting } from "~/data/links-transactions"; import { Intro } from "../common"; import BurningOneSignature from "./burning-one-signature"; diff --git a/apps/playground/src/pages/apis/transaction/minting/minting-plutus-script.tsx b/apps/playground/src/pages/apis/transaction/minting/minting-plutus-script.tsx index 8a23af9f..dcdcfc7f 100644 --- a/apps/playground/src/pages/apis/transaction/minting/minting-plutus-script.tsx +++ b/apps/playground/src/pages/apis/transaction/minting/minting-plutus-script.tsx @@ -187,8 +187,8 @@ function Right(userInput: string, setUserInput: (value: string) => void) { setUserInput(e.target.value)} - placeholder="Datum value" - label="Datum value" + placeholder="Redeemer value" + label="Redeemer value" key={0} />, ]} diff --git a/apps/playground/src/pages/apis/transaction/minting/minting-royalty-token.tsx b/apps/playground/src/pages/apis/transaction/minting/minting-royalty-token.tsx index 6b1d1446..93de6f3b 100644 --- a/apps/playground/src/pages/apis/transaction/minting/minting-royalty-token.tsx +++ b/apps/playground/src/pages/apis/transaction/minting/minting-royalty-token.tsx @@ -76,7 +76,7 @@ function Left() {

Here is the full code:

- + ); } diff --git a/apps/playground/src/pages/apis/transaction/smart-contract/designing-datum.tsx b/apps/playground/src/pages/apis/transaction/smart-contract/designing-datum.tsx index e0679719..f48ec10f 100644 --- a/apps/playground/src/pages/apis/transaction/smart-contract/designing-datum.tsx +++ b/apps/playground/src/pages/apis/transaction/smart-contract/designing-datum.tsx @@ -103,28 +103,28 @@ function Left() {

A string

A datum as simple as just a string, preferably a hex string.

- +

A number

It can also be a number.

- +

An array

Or an array, where each item can be either a string, number, a list, or a map.

- +

A Map

It can also be a map, where both the keys and its values can be a string, number, a list, or a map.

- +

With constructor

Or a datum with a constructor, where alternative is a number, and fields is an array.

- + ); } diff --git a/apps/playground/src/pages/apis/transaction/smart-contract/inline-datum.tsx b/apps/playground/src/pages/apis/transaction/smart-contract/inline-datum.tsx index fe20ef1b..88f17896 100644 --- a/apps/playground/src/pages/apis/transaction/smart-contract/inline-datum.tsx +++ b/apps/playground/src/pages/apis/transaction/smart-contract/inline-datum.tsx @@ -48,7 +48,7 @@ function Left() { .

Here's an example of creating a UTxO with inline datum:

- +

As you can see, you simply have to define the datum field in the Recipient input parameter, including a ( diff --git a/apps/playground/src/pages/apis/transaction/smart-contract/reference-script.tsx b/apps/playground/src/pages/apis/transaction/smart-contract/reference-script.tsx index 80b1926e..6c4c7cf3 100644 --- a/apps/playground/src/pages/apis/transaction/smart-contract/reference-script.tsx +++ b/apps/playground/src/pages/apis/transaction/smart-contract/reference-script.tsx @@ -43,7 +43,7 @@ function Left() { us to send (for example) multiple scripts within one transaction without exceeding the maximum transaction size.

- +

Simply define the script as the Recipient{" "} input parameter. This works for every{" "} diff --git a/apps/playground/src/pages/apis/transaction/smart-contract/unlock-assets.tsx b/apps/playground/src/pages/apis/transaction/smart-contract/unlock-assets.tsx index 31f1aa76..91982f13 100644 --- a/apps/playground/src/pages/apis/transaction/smart-contract/unlock-assets.tsx +++ b/apps/playground/src/pages/apis/transaction/smart-contract/unlock-assets.tsx @@ -96,7 +96,7 @@ function Left() { any of the providers which are implemented by Mesh can be used (see{" "} Providers).

- +

For this demo, we search for the UTxO by using the datum that we have set in the previous step. In fact, depends on the redeemer logic of the @@ -104,7 +104,7 @@ function Left() { unlock the assets. We query the script address for the UTxO that contains the correct data hash:

- +

Then, we create the transaction to unlock the asset. We use the{" "} redeemValue method. The method takes the asset UTxO, the @@ -113,12 +113,12 @@ function Left() { address. The setRequiredSigners method is used to set the required signers for the transaction.

- +

Lastly, we build and sign the transaction. Note that here we need to set the 'partial sign' parameter to true.

- + ); } diff --git a/apps/playground/src/pages/apis/transaction/smart-contract/using-redeemer.tsx b/apps/playground/src/pages/apis/transaction/smart-contract/using-redeemer.tsx index fb4bc3c8..a857b2c4 100644 --- a/apps/playground/src/pages/apis/transaction/smart-contract/using-redeemer.tsx +++ b/apps/playground/src/pages/apis/transaction/smart-contract/using-redeemer.tsx @@ -70,21 +70,21 @@ function Left() { StartRedeemer as defined above with the first Used Address as input:

- +

Supplying the SecondRedeemer as defined above:

- +

Supplying the EndRedeemer as defined above:

- +

Transaction construction

Within the transaction, we can include the redeemer within{" "} redeemValue:

- + ); } diff --git a/apps/playground/src/pages/apis/transaction/staking/deregister-stake.tsx b/apps/playground/src/pages/apis/transaction/staking/deregister-stake.tsx index 3af16314..2791adf1 100644 --- a/apps/playground/src/pages/apis/transaction/staking/deregister-stake.tsx +++ b/apps/playground/src/pages/apis/transaction/staking/deregister-stake.tsx @@ -30,7 +30,7 @@ function Left() { rewardAddress (string) - the reward address to deregister - + ); } diff --git a/apps/playground/src/pages/apis/transaction/staking/register-stake.tsx b/apps/playground/src/pages/apis/transaction/staking/register-stake.tsx index 4d19ed47..22f1c23e 100644 --- a/apps/playground/src/pages/apis/transaction/staking/register-stake.tsx +++ b/apps/playground/src/pages/apis/transaction/staking/register-stake.tsx @@ -55,12 +55,12 @@ function Left() { . For example this account information, active shows the address is registered.

- +

You can chain with delegateStake() to register and delegate to a stake pool.

- + ); } diff --git a/apps/playground/src/pages/apis/transaction/staking/withdraw-stake.tsx b/apps/playground/src/pages/apis/transaction/staking/withdraw-stake.tsx index 2cad6605..b9291ac9 100644 --- a/apps/playground/src/pages/apis/transaction/staking/withdraw-stake.tsx +++ b/apps/playground/src/pages/apis/transaction/staking/withdraw-stake.tsx @@ -36,7 +36,7 @@ function Left() { lovelace (number) - the amount to withdraw in Lovelace - + ); } diff --git a/apps/playground/src/pages/apis/txbuilder/basics/index.tsx b/apps/playground/src/pages/apis/txbuilder/basics/index.tsx index 8d7225d0..8d18386f 100644 --- a/apps/playground/src/pages/apis/txbuilder/basics/index.tsx +++ b/apps/playground/src/pages/apis/txbuilder/basics/index.tsx @@ -1,13 +1,16 @@ import type { NextPage } from "next"; +import Link from "next/link"; import SidebarFullwidth from "~/components/layouts/sidebar-fullwidth"; import TitleIconDescriptionBody from "~/components/sections/title-icon-description-body"; import Metatags from "~/components/site/metatags"; import { metaTxbuilderBasic } from "~/data/links-txbuilders"; +import { Intro } from "../common"; import TxbuilderBuildWithObject from "./build-with-object"; import TxbuilderCip20 from "./cip20"; import TxbuilderCommonFunctions from "./common-functions"; import TxbuilderInitializeTxbuilder from "./initialize-txbuilder"; +import TxbuilderMultisig from "./multisig"; import TxbuilderSendValues from "./send-values"; import TxbuilderSetCollateral from "./set-collateral"; import TxbuilderSetMetadata from "./set-metadata"; @@ -19,6 +22,7 @@ const ReactPage: NextPage = () => { { label: "Initialize Tx Builder", to: "initializeTxbuilder" }, { label: "Common functions", to: "commonFunctions" }, { label: "Send value", to: "sendValue" }, + { label: "Multi-signature", to: "multisig" }, { label: "Build with object", to: "buildWithObject" }, { label: "Set metadata", to: "metadata" }, { label: "Set transaction message", to: "cip20" }, @@ -40,11 +44,29 @@ const ReactPage: NextPage = () => { heroicon={metaTxbuilderBasic.icon} > <> +

- The MeshTxBuilder is a powerful low-level API that - allows you to build and sign transactions. Under the hood, it - interface with cardano-sdk and Whisky SDK to construct - transactions. + The MeshTxBuilder is a powerful interface where the + higher level Transaction class is indeed a pre-built + combination of the MeshTxBuilder APIs. With these + lower level APIs, it builds the object to be passing to the + serialization libraries like{" "} + + cardano-sdk + + {" and "} + + Whisky SDK + {" "} + to construct transactions.

In this page, we will cover how to initialize the{" "} @@ -57,6 +79,7 @@ const ReactPage: NextPage = () => { + diff --git a/apps/playground/src/pages/apis/txbuilder/basics/multisig.tsx b/apps/playground/src/pages/apis/txbuilder/basics/multisig.tsx new file mode 100644 index 00000000..c3b26d1c --- /dev/null +++ b/apps/playground/src/pages/apis/txbuilder/basics/multisig.tsx @@ -0,0 +1,147 @@ +import { + AppWallet, + ForgeScript, + Mint, + resolveScriptHash, + stringToHex, + Transaction, +} from "@meshsdk/core"; +import { useWallet } from "@meshsdk/react"; + +import { getProvider } from "~/components/cardano/mesh-wallet"; +import LiveCodeDemo from "~/components/sections/live-code-demo"; +import TwoColumnsScroll from "~/components/sections/two-columns-scroll"; +import Codeblock from "~/components/text/codeblock"; +import { demoAssetMetadata, demoMnemonic } from "~/data/cardano"; +import { getTxBuilder } from "../common"; + +export default function TxbuilderMultisig() { + return ( + + ); +} + +function Left() { + let codeTx = ``; + codeTx += `const tx = new Transaction({ initiator: wallet });\n`; + codeTx += `tx.mintAsset(forgingScript, asset);\n`; + codeTx += `\n`; + codeTx += `const unsignedTx = await tx.build();\n`; + codeTx += `const signedTx = await wallet.signTx(unsignedTx, true);\n`; + codeTx += `const signedTx2 = await mintingWallet.signTx(signedTx, true);\n`; + + let codeSign = `await wallet.signTx(unsignedTx, true);`; + + return ( + <> +

+ The main idea of a multi-signature transaction is to have multiple + signatures to authorize a transaction. +

+ +

+ In the above code snippet, we are signing the transaction with the user + wallet and then signing the transaction with the minting wallet. The + signTx function is used to sign the transaction. The second + argument is a boolean value that indicates whether the transaction is a + multi-signature transaction. +

+ + + ); +} + +function Right() { + const { wallet, connected } = useWallet(); + + async function runDemo() { + const blockchainProvider = getProvider(); + const mintingWallet = new AppWallet({ + networkId: 0, + fetcher: blockchainProvider, + submitter: blockchainProvider, + key: { + type: "mnemonic", + words: demoMnemonic, + }, + }); + const forgingScript = ForgeScript.withOneSignature( + mintingWallet.getPaymentAddress(), + ); + const assetName = "MeshToken"; + const policyId = resolveScriptHash(forgingScript); + + const usedAddress = await wallet.getUsedAddresses(); + const utxos = await wallet.getUtxos(); + const address = usedAddress[0]!; + + const txBuilder = getTxBuilder(); + + const unsignedTx = await txBuilder + .mint("1", policyId, stringToHex("MeshToken")) + .mintingScript(forgingScript) + .metadataValue("721", { [policyId]: { [assetName]: demoAssetMetadata } }) + .changeAddress(address) + .selectUtxosFrom(utxos) + .complete(); + + const signedTx = await wallet.signTx(unsignedTx, true); + const signedTx2 = mintingWallet.signTx(signedTx, true); + const txHash = await wallet.submitTx(signedTx2); + return txHash; + } + + let codeSnippet = `import { AppWallet, ForgeScript, Mint, Transaction } from '@meshsdk/core';\n\n`; + codeSnippet += `const mintingWallet = new AppWallet({\n`; + codeSnippet += ` networkId: 0,\n`; + codeSnippet += ` fetcher: blockchainProvider,\n`; + codeSnippet += ` submitter: blockchainProvider,\n`; + codeSnippet += ` key: {\n`; + codeSnippet += ` type: "mnemonic",\n`; + codeSnippet += ` words: demoMnemonic,\n`; + codeSnippet += ` },\n`; + codeSnippet += `});\n`; + codeSnippet += `const forgingScript = ForgeScript.withOneSignature(\n`; + codeSnippet += ` mintingWallet.getPaymentAddress(),\n`; + codeSnippet += `);\n`; + codeSnippet += `\n`; + codeSnippet += `const assetName = "MeshToken";\n`; + codeSnippet += `const policyId = resolveScriptHash(forgingScript);\n`; + codeSnippet += `\n`; + codeSnippet += `const usedAddress = await wallet.getUsedAddresses();\n`; + codeSnippet += `const utxos = await wallet.getUtxos();\n`; + codeSnippet += `const address = usedAddress[0]!;\n`; + codeSnippet += `\n`; + codeSnippet += `const txBuilder = getTxBuilder();\n`; + codeSnippet += `\n`; + codeSnippet += `const unsignedTx = await txBuilder\n`; + codeSnippet += ` .mint("1", policyId, stringToHex("MeshToken"))\n`; + codeSnippet += ` .mintingScript(forgingScript)\n`; + codeSnippet += ` .metadataValue("721", { [policyId]: { [assetName]: demoAssetMetadata } })\n`; + codeSnippet += ` .changeAddress(address)\n`; + codeSnippet += ` .selectUtxosFrom(utxos)\n`; + codeSnippet += ` .complete();\n`; + codeSnippet += `\n`; + codeSnippet += `const signedTx = await wallet.signTx(unsignedTx, true);\n`; + codeSnippet += `const signedTx2 = mintingWallet.signTx(signedTx, true);\n`; + codeSnippet += `const txHash = await wallet.submitTx(signedTx2);\n`; + + return ( + + ); +} diff --git a/apps/playground/src/pages/apis/txbuilder/basics/send-values.tsx b/apps/playground/src/pages/apis/txbuilder/basics/send-values.tsx index cd0d7476..1591aced 100644 --- a/apps/playground/src/pages/apis/txbuilder/basics/send-values.tsx +++ b/apps/playground/src/pages/apis/txbuilder/basics/send-values.tsx @@ -24,9 +24,10 @@ export default function TxbuilderSendValue() { function Left() { let code1 = ``; code1 += `txBuilder\n`; - code1 += ` .txIn(utxo.input.txHash, utxo.input.outputIndex)\n`; - code1 += ` .txOut(address, [{ unit: "lovelace", quantity: '1000000' }])\n`; - code1 += ` .changeAddress(await wallet.getChangeAddress());\n`; + code1 += ` .txOut(address, [{ unit: "lovelace", quantity: amount }])\n`; + code1 += ` .changeAddress(changeAddress)\n`; + code1 += ` .selectUtxosFrom(utxos)\n`; + code1 += ` .complete();\n`; return ( <> diff --git a/apps/playground/src/pages/apis/txbuilder/common.tsx b/apps/playground/src/pages/apis/txbuilder/common.tsx index 3e780b8f..2309af17 100644 --- a/apps/playground/src/pages/apis/txbuilder/common.tsx +++ b/apps/playground/src/pages/apis/txbuilder/common.tsx @@ -1,18 +1,24 @@ -import { - BrowserWallet, - keepRelevant, - MeshTxBuilder, - Quantity, - Unit, -} from "@meshsdk/core"; +import { MeshTxBuilder } from "@meshsdk/core"; import { getProvider } from "~/components/cardano/mesh-wallet"; export function getTxBuilder() { const blockchainProvider = getProvider(); return new MeshTxBuilder({ + evaluator: blockchainProvider, fetcher: blockchainProvider, }); } export default function Placeholder() {} + +export function Intro() { + return ( + <> +

+ The MeshTxBuilder is a powerful low-level APIs that allows + you to build and sign transactions. +

+ + ); +} diff --git a/apps/playground/src/pages/apis/txbuilder/minting/burning-one-signature.tsx b/apps/playground/src/pages/apis/txbuilder/minting/burning-one-signature.tsx index fe7f073f..132f1f18 100644 --- a/apps/playground/src/pages/apis/txbuilder/minting/burning-one-signature.tsx +++ b/apps/playground/src/pages/apis/txbuilder/minting/burning-one-signature.tsx @@ -70,13 +70,13 @@ function Left(userInput: string) { "minting address". Note that, assets can only be burned by its minting address.

- +

Then, we define Asset and set tx.burnAsset()

- +

Here is the full code:

- + ); } @@ -124,6 +124,24 @@ function Right(userInput: string, setUserInput: (value: string) => void) { // todo docs let code = ``; + code += `const utxos = await wallet.getUtxos();\n`; + code += `const changeAddress = await wallet.getChangeAddress();\n`; + code += `const txBuilder = getTxBuilder();\n`; + code += `\n`; + code += `const forgingScript = ForgeScript.withOneSignature(changeAddress);\n`; + code += `\n`; + code += `const policyId = resolveScriptHash(forgingScript);\n`; + code += `const tokenName = stringToHex("MeshToken");\n`; + code += `\n`; + code += `const unsignedTx = await txBuilder\n`; + code += ` .mint("-1", policyId, tokenName)\n`; + code += ` .mintingScript(forgingScript)\n`; + code += ` .changeAddress(changeAddress)\n`; + code += ` .selectUtxosFrom(utxos)\n`; + code += ` .complete();\n`; + code += `\n`; + code += `const signedTx = await wallet.signTx(unsignedTx);\n`; + code += `const txHash = await wallet.submitTx(signedTx);\n`; return ( { const sidebarItems = [ @@ -33,7 +35,16 @@ const ReactPage: NextPage = () => { heroicon={metaTxbuilderMinting.icon} > <> -

+

+ Minting and burning assets is a common operation in blockchain + applications. In the Cardano ecosystem, minting and burning are + achieved through Native Scripts and Plutus Scripts. +

+ +

+ In this page, you will find the APIs to create transactions for + minting and burning assets. +

@@ -42,6 +53,7 @@ const ReactPage: NextPage = () => { + ); diff --git a/apps/playground/src/pages/apis/txbuilder/minting/minting-plutus-script.tsx b/apps/playground/src/pages/apis/txbuilder/minting/minting-plutus-script.tsx index d7fdb871..4b115857 100644 --- a/apps/playground/src/pages/apis/txbuilder/minting/minting-plutus-script.tsx +++ b/apps/playground/src/pages/apis/txbuilder/minting/minting-plutus-script.tsx @@ -190,8 +190,8 @@ function Right(userInput: string, setUserInput: (value: string) => void) { setUserInput(e.target.value)} - placeholder="Datum value" - label="Datum value" + placeholder="Redeemer value" + label="Redeemer value" key={0} />, ]} diff --git a/apps/playground/src/pages/apis/txbuilder/minting/minting-royalty-token.tsx b/apps/playground/src/pages/apis/txbuilder/minting/minting-royalty-token.tsx new file mode 100644 index 00000000..b7050b19 --- /dev/null +++ b/apps/playground/src/pages/apis/txbuilder/minting/minting-royalty-token.tsx @@ -0,0 +1,186 @@ +import { useState } from "react"; +import Link from "next/link"; + +import { + ForgeScript, + MeshTxBuilder, + Mint, + resolveScriptHash, + RoyaltiesStandard, + Transaction, +} from "@meshsdk/core"; +import { useWallet } from "@meshsdk/react"; + +import Input from "~/components/form/input"; +import InputTable from "~/components/sections/input-table"; +import LiveCodeDemo from "~/components/sections/live-code-demo"; +import TwoColumnsScroll from "~/components/sections/two-columns-scroll"; +import Codeblock from "~/components/text/codeblock"; +import { demoAddresses } from "~/data/cardano"; + +export default function MintingRoyaltyToken() { + return ( + + ); +} + +function Left() { + let codeSnippet = ``; + codeSnippet += `const usedAddress = await wallet.getUsedAddresses();\n`; + codeSnippet += `const address = usedAddress[0];\n`; + codeSnippet += `\n`; + codeSnippet += `// create forgingScript, you can also use native script here\n`; + codeSnippet += `const forgingScript = ForgeScript.withOneSignature(address);\n`; + codeSnippet += `\n`; + codeSnippet += `const tx = new Transaction({ initiator: wallet });\n`; + codeSnippet += `\n`; + codeSnippet += `const _assetMetadata = {\n`; + codeSnippet += ` rate: '0.2',\n`; + codeSnippet += ` addr: '${demoAddresses.testnet}'\n`; + codeSnippet += `};\n`; + codeSnippet += `const asset: Mint = {\n`; + codeSnippet += ` assetName: '',\n`; + codeSnippet += ` assetQuantity: '1',\n`; + codeSnippet += ` metadata: _assetMetadata,\n`; + codeSnippet += ` label: '777',\n`; + codeSnippet += ` recipient: address,\n`; + codeSnippet += `};\n`; + codeSnippet += `\n`; + codeSnippet += `tx.mintAsset(forgingScript, asset);\n`; + codeSnippet += `\n`; + codeSnippet += `const unsignedTx = await tx.build();\n`; + codeSnippet += `const signedTx = await wallet.signTx(unsignedTx);\n`; + codeSnippet += `const txHash = await wallet.submitTx(signedTx);\n`; + + return ( + <> +

+ Royalty tokens is a special type of token that allows the creator to + collect a royalty fee, this proposed standard will allow for uniform + royalties' distributions across the secondary market space. Read{" "} + + CIP-27 + {" "} + for more information. +

+

+ The implementation of royalty tokens is very simple, minting a token + with 777 label, with "rate" and "addr" in the metadata. +

+ +

Here is the full code:

+ + + ); +} + +function Right() { + const { wallet, connected } = useWallet(); + const [userInput, setUserInput] = useState("0.2"); + const [userInput2, setUserInput2] = useState(demoAddresses.testnet); + + async function runDemo() { + const utxos = await wallet.getUtxos(); + const usedAddress = await wallet.getUsedAddresses(); + const address = usedAddress[0]; + + if (address === undefined) { + throw "No address found"; + } + + const forgingScript = ForgeScript.withOneSignature(address); + const policyId = resolveScriptHash(forgingScript); + + const assetMetadata: RoyaltiesStandard = { + rate: userInput, + address: userInput2, + }; + + const txBuilder = new MeshTxBuilder(); + + const unsignedTx = await txBuilder + .mint("1", policyId, "") + .mintingScript(forgingScript) + .metadataValue("777", assetMetadata) + .changeAddress(address) + .selectUtxosFrom(utxos) + .complete(); + + const signedTx = await wallet.signTx(unsignedTx); + const txHash = await wallet.submitTx(signedTx); + + return txHash; + } + + let code = ``; + code += `const usedAddress = await wallet.getUsedAddresses();\n`; + code += `const address = usedAddress[0];\n`; + code += `\n`; + code += `const forgingScript = ForgeScript.withOneSignature(address);\n`; + code += `\n`; + code += `const tx = new Transaction({ initiator: wallet });\n`; + code += `\n`; + code += `const _assetMetadata: RoyaltiesStandard = {\n`; + code += ` rate: '${userInput}',\n`; + code += ` address: '${userInput2}',\n`; + code += `};\n`; + code += `const asset: Mint = {\n`; + code += ` assetName: "",\n`; + code += ` assetQuantity: "1",\n`; + code += ` metadata: _assetMetadata,\n`; + code += ` label: "777",\n`; + code += ` recipient: address,\n`; + code += `};\n`; + code += `\n`; + code += `tx.mintAsset(forgingScript, asset);\n`; + code += `\n`; + code += `const unsignedTx = await tx.build();\n`; + code += `const signedTx = await wallet.signTx(unsignedTx);\n`; + code += `const txHash = await wallet.submitTx(signedTx);\n`; + + return ( + + setUserInput(e.target.value)} + placeholder="Rate" + label="Rate" + key={0} + />, + ]} + /> + setUserInput2(e.target.value)} + placeholder="Address" + label="Address" + key={1} + />, + ]} + /> + + ); +} diff --git a/apps/playground/src/pages/apis/txbuilder/smart-contract/index.tsx b/apps/playground/src/pages/apis/txbuilder/smart-contract/index.tsx index d6809774..d22ba02a 100644 --- a/apps/playground/src/pages/apis/txbuilder/smart-contract/index.tsx +++ b/apps/playground/src/pages/apis/txbuilder/smart-contract/index.tsx @@ -4,15 +4,15 @@ import SidebarFullwidth from "~/components/layouts/sidebar-fullwidth"; import TitleIconDescriptionBody from "~/components/sections/title-icon-description-body"; import Metatags from "~/components/site/metatags"; import { metaTxbuilderSmartContract } from "~/data/links-txbuilders"; +import TxbuilderContractPlutusMinting from "../minting/minting-plutus-script"; import TxbuilderContractLockAssets from "./lock-assets"; -import TxbuilderContractPlutusMinting from "./plutus-minting"; import TxbuilderContractUnlockAssets from "./unlock-assets"; const ReactPage: NextPage = () => { const sidebarItems = [ { label: "Lock assets", to: "TxbuilderContractLockAssets" }, { label: "Unlock assets", to: "TxbuilderContractUnlockAssets" }, - { label: "Plutus minting", to: "TxbuilderContractPlutusMinting" }, + { label: "Plutus minting", to: "mintingPlutusScript" }, ]; return ( diff --git a/apps/playground/src/pages/apis/txbuilder/smart-contract/lock-assets.tsx b/apps/playground/src/pages/apis/txbuilder/smart-contract/lock-assets.tsx index 87353eab..7b48edcf 100644 --- a/apps/playground/src/pages/apis/txbuilder/smart-contract/lock-assets.tsx +++ b/apps/playground/src/pages/apis/txbuilder/smart-contract/lock-assets.tsx @@ -6,6 +6,7 @@ import { PlutusScript, Quantity, resolvePlutusScriptAddress, + serializePlutusScript, Unit, } from "@meshsdk/core"; import { useWallet } from "@meshsdk/react"; @@ -56,13 +57,12 @@ function Right() { code: demoPlutusAlwaysSucceedScript, version: "V2", }; - const scriptAddress = resolvePlutusScriptAddress(script, 0); + const { address: scriptAddress } = serializePlutusScript(script); const txBuilder = getTxBuilder(); - // todo const unsignedTx = await txBuilder - .txOut(scriptAddress, []) + .txOut(scriptAddress, [{ unit: userInput, quantity: "1" }]) .txOutInlineDatumValue(userInput2) .changeAddress(changeAddress) .selectUtxosFrom(utxos) diff --git a/apps/playground/src/pages/apis/txbuilder/smart-contract/plutus-minting.tsx b/apps/playground/src/pages/apis/txbuilder/smart-contract/plutus-minting.tsx deleted file mode 100644 index 7df40ee8..00000000 --- a/apps/playground/src/pages/apis/txbuilder/smart-contract/plutus-minting.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import { useState } from "react"; - -import { - keepRelevant, - MeshTxBuilder, - PlutusScript, - Quantity, - Unit, -} from "@meshsdk/core"; -import { useWallet } from "@meshsdk/react"; - -import { getProvider } from "~/components/cardano/mesh-wallet"; -import Input from "~/components/form/input"; -import InputTable from "~/components/sections/input-table"; -import LiveCodeDemo from "~/components/sections/live-code-demo"; -import TwoColumnsScroll from "~/components/sections/two-columns-scroll"; -import Codeblock from "~/components/text/codeblock"; -import { demoPlutusMintingScript } from "~/data/cardano"; - -export default function TxbuilderContractPlutusMinting() { - return ( - - ); -} - -function Left() { - let code1 = ``; - - return ( - <> -

- - - ); -} - -function Right() { - const { wallet, connected } = useWallet(); - - const [userInput, setUserInput] = useState("mesh"); - - async function runDemo() { - const blockchainProvider = getProvider(); - - const walletAddress = await wallet.getChangeAddress(); - - // script - const script: PlutusScript = { - code: demoPlutusMintingScript, - version: "V2", - }; - - // get utxo - const assetMap = new Map(); - assetMap.set("lovelace", "5000000"); - - const walletUtxos = await wallet.getUtxos(); - const utxos = keepRelevant(assetMap, walletUtxos); - const utxo = utxos[0]; - - if (utxo === undefined) { - throw new Error("No utxo found"); - } - - // const signedTx = await wallet.signTx(unsignedTx); - // const txHash = await wallet.submitTx(signedTx); - return "txHash"; - } - - let codeSnippet = `import { keepRelevant, MeshTxBuilder, Quantity, Unit } from "@meshsdk/core";\n\n`; - - return ( - - setUserInput(e.target.value)} - placeholder="Datum" - label="Datum" - key={0} - />, - ]} - /> - - ); -} diff --git a/apps/playground/src/pages/apis/txbuilder/smart-contract/unlock-assets.tsx b/apps/playground/src/pages/apis/txbuilder/smart-contract/unlock-assets.tsx index 5e399583..3b481809 100644 --- a/apps/playground/src/pages/apis/txbuilder/smart-contract/unlock-assets.tsx +++ b/apps/playground/src/pages/apis/txbuilder/smart-contract/unlock-assets.tsx @@ -1,18 +1,14 @@ import { useState } from "react"; import { - keepRelevant, mConStr0, - MeshTxBuilder, PlutusScript, - Quantity, resolvePlutusScriptAddress, - Unit, + serializePlutusScript, } from "@meshsdk/core"; import { useWallet } from "@meshsdk/react"; import { fetchAssetUtxo } from "~/components/cardano/fetch-utxo-by-datum"; -import { getProvider } from "~/components/cardano/mesh-wallet"; import Input from "~/components/form/input"; import InputTable from "~/components/sections/input-table"; import LiveCodeDemo from "~/components/sections/live-code-demo"; @@ -59,7 +55,9 @@ function Right() { code: demoPlutusAlwaysSucceedScript, version: "V2", }; - const scriptAddress = resolvePlutusScriptAddress(script, 0); + const { address: scriptAddress } = serializePlutusScript(script); + + console.log("scriptAddress", scriptAddress); const assetUtxo = await fetchAssetUtxo({ address: scriptAddress, @@ -78,12 +76,13 @@ function Right() { .txIn(assetUtxo.input.txHash, assetUtxo.input.outputIndex) .txInInlineDatumPresent() .txInRedeemerValue(mConStr0([])) - // .txInScript(getScriptCbor("Spending")) // todo - .txOut(changeAddress, []) + .txInScript(demoPlutusAlwaysSucceedScript) .changeAddress(changeAddress) .txInCollateral( collateral[0]?.input.txHash!, collateral[0]?.input.outputIndex!, + collateral[0]?.output.amount!, + collateral[0]?.output.address!, ) .selectUtxosFrom(utxos) .complete(); diff --git a/apps/playground/src/pages/apis/txbuilder/staking/delegate-stake.tsx b/apps/playground/src/pages/apis/txbuilder/staking/delegate-stake.tsx index f630445a..ba4bdc89 100644 --- a/apps/playground/src/pages/apis/txbuilder/staking/delegate-stake.tsx +++ b/apps/playground/src/pages/apis/txbuilder/staking/delegate-stake.tsx @@ -1,21 +1,25 @@ import { useState } from "react"; -import { keepRelevant, MeshTxBuilder, Quantity, Unit } from "@meshsdk/core"; +import { + deserializePoolId, + resolveStakeKeyHash, + Transaction, +} from "@meshsdk/core"; import { useWallet } from "@meshsdk/react"; -import { getProvider } from "~/components/cardano/mesh-wallet"; import Input from "~/components/form/input"; import InputTable from "~/components/sections/input-table"; import LiveCodeDemo from "~/components/sections/live-code-demo"; import TwoColumnsScroll from "~/components/sections/two-columns-scroll"; import Codeblock from "~/components/text/codeblock"; -import { demoAddresses } from "~/data/cardano"; +import { demoPool } from "~/data/cardano"; +import { getTxBuilder } from "../common"; -export default function TxbuilderSendValues() { +export default function StakingDelegate() { return ( @@ -23,63 +27,46 @@ export default function TxbuilderSendValues() { } function Left() { - let code1 = ``; - code1 += `const txBuilder = new MeshTxBuilder({\n`; - code1 += ` fetcher: blockchainProvider,\n`; - code1 += `});\n`; - code1 += `\n`; - code1 += `const unsignedTx = await txBuilder\n`; - code1 += ` .txIn(utxo.input.txHash, utxo.input.outputIndex)\n`; - code1 += ` .txOut(address, [{ unit: "lovelace", quantity: '1000000' }])\n`; - code1 += ` .changeAddress(await wallet.getChangeAddress())\n`; - code1 += ` .complete();\n`; + let codeSnippet = `const addresses = await wallet.getRewardAddresses();\n`; + codeSnippet += `const rewardAddress = addresses[0];\n\n`; + codeSnippet += `const tx = new Transaction({ initiator: wallet });\n`; + codeSnippet += `tx.delegateStake(rewardAddress, '${demoPool}');`; return ( <>

- Sending values to a recipient is a common operation in blockchain - transactions. The Mesh SDK provides a simple way to build a transaction - to send values to a recipient. + Delegation is the process by which ADA holders delegate the stake + associated with their ADA to a stake pool. Doing so, this allows ADA + holders to participate in the network and be rewarded in proportion to + the amount of stake delegated.

-

- The following shows a simple example of building a transaction to send - values to a recipient: -

- + ); } function Right() { const { wallet, connected } = useWallet(); - - const [address, setAddress] = useState(demoAddresses.testnet); - const [amount, setAmount] = useState("2000000"); + const [userInput, setUserInput] = useState(demoPool); async function runDemo() { - const blockchainProvider = getProvider(); - - // get utxo - const assetMap = new Map(); - assetMap.set("lovelace", amount); - - const walletUtxos = await wallet.getUtxos(); - const utxos = keepRelevant(assetMap, walletUtxos); - const utxo = utxos[0]; - - if (utxo === undefined) { - throw new Error("No utxo found"); + const utxos = await wallet.getUtxos(); + const address = await wallet.getChangeAddress(); + const addresses = await wallet.getRewardAddresses(); + const rewardAddress = addresses[0]!; + const stakeKeyHash = resolveStakeKeyHash(rewardAddress); + const poolIdHash = deserializePoolId(userInput); + + if (rewardAddress === undefined) { + throw "No address found"; } - // transaction - const txBuilder = new MeshTxBuilder({ - fetcher: blockchainProvider, - }); + const txBuilder = getTxBuilder(); const unsignedTx = await txBuilder - .txIn(utxo.input.txHash, utxo.input.outputIndex) - .txOut(address, [{ unit: "lovelace", quantity: amount }]) - .changeAddress(await wallet.getChangeAddress()) + .delegateStakeCertificate(stakeKeyHash, poolIdHash) + .selectUtxosFrom(utxos) + .changeAddress(address) .complete(); const signedTx = await wallet.signTx(unsignedTx); @@ -87,36 +74,38 @@ function Right() { return txHash; } - let codeSnippet = `import { keepRelevant, MeshTxBuilder, Quantity, Unit } from "@meshsdk/core";\n\n`; + let code = ``; + code += `const addresses = await wallet.getRewardAddresses();\n`; + code += `const rewardAddress = addresses[0];\n`; + code += `\n`; + code += `const tx = new Transaction({ initiator: wallet });\n`; + code += `tx.delegateStake(rewardAddress, '${userInput}');\n`; + code += `\n`; + code += `const unsignedTx = await tx.build();\n`; + code += `const signedTx = await wallet.signTx(unsignedTx);\n`; + code += `const txHash = await wallet.submitTx(signedTx);\n`; return ( setAddress(e.target.value)} - placeholder="Address" - label="Address" + value={userInput} + onChange={(e) => setUserInput(e.target.value)} + placeholder="Pool ID" + label="Pool ID" key={0} />, - setAmount(e.target.value)} - placeholder="Amount" - label="Amount" - key={1} - />, ]} /> diff --git a/apps/playground/src/pages/apis/txbuilder/staking/deregister-stake.tsx b/apps/playground/src/pages/apis/txbuilder/staking/deregister-stake.tsx new file mode 100644 index 00000000..0db5360a --- /dev/null +++ b/apps/playground/src/pages/apis/txbuilder/staking/deregister-stake.tsx @@ -0,0 +1,90 @@ +import { resolveStakeKeyHash, Transaction } from "@meshsdk/core"; +import { useWallet } from "@meshsdk/react"; + +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"; + +export default function StakingDeregister() { + return ( + + ); +} + +function Left() { + let codeSnippet = `deregisterStake(rewardAddress: string)`; + + return ( + <> +

+ Deregister a stake address. The function accepts the following + parameters: +

+
    +
  • + rewardAddress (string) - the reward address to deregister +
  • +
+ + + ); +} + +function Right() { + const { wallet, connected } = useWallet(); + + async function runDemo() { + const utxos = await wallet.getUtxos(); + const address = await wallet.getChangeAddress(); + const addresses = await wallet.getRewardAddresses(); + const rewardAddress = addresses[0]!; + const stakeKeyHash = resolveStakeKeyHash(rewardAddress); + + if (rewardAddress === undefined) { + throw "No address found"; + } + + const txBuilder = getTxBuilder(); + + const unsignedTx = await txBuilder + .deregisterStakeCertificate(stakeKeyHash) + .selectUtxosFrom(utxos) + .changeAddress(address) + .complete(); + + const signedTx = await wallet.signTx(unsignedTx); + const txHash = await wallet.submitTx(signedTx); + return txHash; + } + + let code = ``; + code += `const addresses = await wallet.getRewardAddresses();\n`; + code += `const rewardAddress = addresses[0];\n`; + code += `\n`; + code += `const tx = new Transaction({ initiator: wallet });\n`; + code += `tx.deregisterStake(rewardAddress);\n`; + code += `\n`; + code += `const unsignedTx = await tx.build();\n`; + code += `const signedTx = await wallet.signTx(unsignedTx);\n`; + code += `const txHash = await wallet.submitTx(signedTx);\n`; + + return ( + + ); +} diff --git a/apps/playground/src/pages/apis/txbuilder/staking/index.tsx b/apps/playground/src/pages/apis/txbuilder/staking/index.tsx index 1d906730..63518a9a 100644 --- a/apps/playground/src/pages/apis/txbuilder/staking/index.tsx +++ b/apps/playground/src/pages/apis/txbuilder/staking/index.tsx @@ -4,11 +4,17 @@ import SidebarFullwidth from "~/components/layouts/sidebar-fullwidth"; import TitleIconDescriptionBody from "~/components/sections/title-icon-description-body"; import Metatags from "~/components/site/metatags"; import { metaTxbuilderStaking } from "~/data/links-txbuilders"; +import StakingDelegate from "./delegate-stake"; +import StakingDeregister from "./deregister-stake"; +import StakingRegister from "./register-stake"; +import StakingWithdraw from "./withdraw-stake"; const ReactPage: NextPage = () => { const sidebarItems = [ - { label: "Send values", to: "sendValues" }, - { label: "Build with Object", to: "buildWithObject" }, + { label: "Register Stake", to: "registerStake" }, + { label: "Delegate Stake", to: "delegateStake" }, + { label: "Withdraw Rewards", to: "withdrawRewards" }, + { label: "Deregister Stake", to: "deregisterStake" }, ]; return ( @@ -25,6 +31,10 @@ const ReactPage: NextPage = () => { > <> + + + + ); diff --git a/apps/playground/src/pages/apis/txbuilder/staking/register-stake.tsx b/apps/playground/src/pages/apis/txbuilder/staking/register-stake.tsx index 0c4114ba..3f78dacc 100644 --- a/apps/playground/src/pages/apis/txbuilder/staking/register-stake.tsx +++ b/apps/playground/src/pages/apis/txbuilder/staking/register-stake.tsx @@ -1,28 +1,26 @@ import { useState } from "react"; -import Link from "next/link"; import { - keepRelevant, - MeshTxBuilder, - MeshTxBuilderBody, - Quantity, - Unit, + deserializePoolId, + resolveStakeKeyHash, + Transaction, } from "@meshsdk/core"; +import { CSLSerializer } from "@meshsdk/core-csl"; import { useWallet } from "@meshsdk/react"; -import { getProvider } from "~/components/cardano/mesh-wallet"; import Input from "~/components/form/input"; import InputTable from "~/components/sections/input-table"; import LiveCodeDemo from "~/components/sections/live-code-demo"; import TwoColumnsScroll from "~/components/sections/two-columns-scroll"; import Codeblock from "~/components/text/codeblock"; -import { demoAddresses } from "~/data/cardano"; +import { demoPool } from "~/data/cardano"; +import { getTxBuilder } from "../common"; -export default function TxbuilderBuildWithObject() { +export default function StakingRegister() { return ( @@ -30,119 +28,112 @@ export default function TxbuilderBuildWithObject() { } function Left() { - let code1 = ``; + let codeSnippet = `import { Transaction } from '@meshsdk/core';\n\n`; + + codeSnippet += `const addresses = await wallet.getRewardAddresses();\n`; + codeSnippet += `const rewardAddress = addresses[0];\n\n`; + + codeSnippet += `const tx = new Transaction({ initiator: wallet });\n`; + codeSnippet += `tx.registerStake(rewardAddress);\n`; + codeSnippet += `tx.delegateStake(rewardAddress, '${demoPool}');\n\n`; + + codeSnippet += `const unsignedTx = await tx.build();\n`; + codeSnippet += `const signedTx = await wallet.signTx(unsignedTx);\n`; + codeSnippet += `const txHash = await wallet.submitTx(signedTx);`; + + let code2 = ``; + code2 += `{\n`; + code2 += ` "active": true,\n`; + code2 += ` "poolId": "${demoPool}",\n`; + code2 += ` "balance": "389290551",\n`; + code2 += ` "rewards": "0",\n`; + code2 += ` "withdrawals": "0"\n`; + code2 += `}\n`; return ( <>

- One alternative to use the lower level APIs is to build the transaction - with an object. + New address must "register" before they can delegate to stakepools. To + check if a reward address has been register, use{" "} + + blockchainProvider.fetchAccountInfo(rewardAddress) + + . For example this account information, active shows the + address is registered.

+

- The following shows a simple example of building a transaction to send - values to a recipient: -

- -

- - Full Code Snippet in Github - + You can chain with delegateStake() to register and delegate + to a stake pool.

+ ); } function Right() { const { wallet, connected } = useWallet(); - - const [address, setAddress] = useState(demoAddresses.testnet); - const [amount, setAmount] = useState("2000000"); + const [userInput, setUserInput] = useState(demoPool); async function runDemo() { - const blockchainProvider = getProvider(); - - const changeAddress = await wallet.getChangeAddress(); - - // get utxo - const assetMap = new Map(); - assetMap.set("lovelace", amount); + const utxos = await wallet.getUtxos(); + const address = await wallet.getChangeAddress(); + const addresses = await wallet.getRewardAddresses(); + const rewardAddress = addresses[0]!; + const stakeKeyHash = resolveStakeKeyHash(rewardAddress); + const poolIdHash = deserializePoolId(userInput); + + if (rewardAddress === undefined) { + throw "No address found"; + } - const walletUtxos = await wallet.getUtxos(); - const utxos = keepRelevant(assetMap, walletUtxos); - const utxo = utxos[0]; + const txBuilder = getTxBuilder(); - if (utxo === undefined) { - throw new Error("No utxo found"); - } + const unsignedTx = await txBuilder + .registerStakeCertificate(stakeKeyHash) + .delegateStakeCertificate(stakeKeyHash, poolIdHash) + .selectUtxosFrom(utxos) + .changeAddress(address) + .complete(); - // transaction - const txBuilder = new MeshTxBuilder({ - fetcher: blockchainProvider, - }); - - // const meshTxBody: MeshTxBuilderBody = { - // inputs: [ - // { - // type: "PubKey", - // txIn: { - // txHash: utxo.input.txHash, - // txIndex: utxo.input.outputIndex, - // }, - // }, - // ], - // outputs: [ - // { - // address: address, - // amount: [{ unit: "lovelace", quantity: amount }], - // }, - // ], - // collaterals: [], - // requiredSignatures: [], - // referenceInputs: [], - // mints: [], - // changeAddress: changeAddress, - // metadata: [], - // validityRange: {}, - // signingKey: [], - // }; - - // const unsignedTx = await mesh.complete(meshTxBody); - - // const signedTx = await wallet.signTx(unsignedTx); - // const txHash = await wallet.submitTx(signedTx); - return 'txHash'; + const signedTx = await wallet.signTx(unsignedTx); + const txHash = await wallet.submitTx(signedTx); + return txHash; } - let codeSnippet = `import { keepRelevant, MeshTxBuilder, Quantity, Unit } from "@meshsdk/core";\n\n`; + let code = ``; + code += `const addresses = await wallet.getRewardAddresses();\n`; + code += `const rewardAddress = addresses[0];\n`; + code += `\n`; + code += `const tx = new Transaction({ initiator: wallet });\n`; + code += `tx.registerStake(rewardAddress);\n`; + code += `tx.delegateStake(rewardAddress, '${userInput}');\n`; + code += `\n`; + code += `const unsignedTx = await tx.build();\n`; + code += `const signedTx = await wallet.signTx(unsignedTx);\n`; + code += `const txHash = await wallet.submitTx(signedTx);\n`; return ( setAddress(e.target.value)} - placeholder="Address" - label="Address" + value={userInput} + onChange={(e) => setUserInput(e.target.value)} + placeholder="Pool ID" + label="Pool ID" key={0} />, - setAmount(e.target.value)} - placeholder="Amount" - label="Amount" - key={1} - />, ]} /> diff --git a/apps/playground/src/pages/apis/txbuilder/staking/withdraw-stake.tsx b/apps/playground/src/pages/apis/txbuilder/staking/withdraw-stake.tsx new file mode 100644 index 00000000..30cba1de --- /dev/null +++ b/apps/playground/src/pages/apis/txbuilder/staking/withdraw-stake.tsx @@ -0,0 +1,108 @@ +import { useState } from "react"; + +import { Transaction } from "@meshsdk/core"; +import { useWallet } from "@meshsdk/react"; + +import Input from "~/components/form/input"; +import InputTable from "~/components/sections/input-table"; +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"; + +export default function StakingWithdraw() { + return ( + + ); +} + +function Left() { + let codeSnippet = `tx.withdrawRewards(rewardAddress, lovelace);`; + + return ( + <> +

+ Withdraw staking rewards. The function accepts the following parameters: +

+
    +
  • + rewardAddress (string) - the reward address to withdraw from +
  • +
  • + lovelace (number) - the amount to withdraw in Lovelace +
  • +
+ + + ); +} + +function Right() { + const { wallet, connected } = useWallet(); + const [userInput, setUserInput] = useState("1000000"); + + async function runDemo() { + const utxos = await wallet.getUtxos(); + const address = await wallet.getChangeAddress(); + const addresses = await wallet.getRewardAddresses(); + const rewardAddress = addresses[0]!; + + if (rewardAddress === undefined) { + throw "No address found"; + } + + const txBuilder = getTxBuilder(); + + const unsignedTx = await txBuilder + .withdrawal(rewardAddress, userInput) + .selectUtxosFrom(utxos) + .changeAddress(address) + .complete(); + + const signedTx = await wallet.signTx(unsignedTx); + const txHash = await wallet.submitTx(signedTx); + return txHash; + } + + let code = ``; + code += `const addresses = await wallet.getRewardAddresses();\n`; + code += `const rewardAddress = addresses[0];\n`; + code += `\n`; + code += `const tx = new Transaction({ initiator: wallet });\n`; + code += `tx.withdrawRewards(rewardAddress, '${userInput}');\n`; + code += `\n`; + code += `const unsignedTx = await tx.build();\n`; + code += `const signedTx = await wallet.signTx(unsignedTx);\n`; + code += `const txHash = await wallet.submitTx(signedTx);\n`; + + return ( + + setUserInput(e.target.value)} + placeholder="Amount in lovelace" + label="Amount in lovelace" + key={0} + />, + ]} + /> + + ); +} diff --git a/apps/playground/src/pages/apis/wallets/browserwallet/connect-wallet.tsx b/apps/playground/src/pages/apis/wallets/browserwallet/connect-wallet.tsx index 6e2adf7b..40b35646 100644 --- a/apps/playground/src/pages/apis/wallets/browserwallet/connect-wallet.tsx +++ b/apps/playground/src/pages/apis/wallets/browserwallet/connect-wallet.tsx @@ -26,7 +26,7 @@ function Left() { dApp to use.

- Query BrowserWallet.getInstalledWallets() to get a list of + Query BrowserWallet.getAvailableWallets() to get a list of available wallets, then provide the wallet name for which wallet the user would like to connect with.

diff --git a/apps/playground/src/pages/apis/wallets/browserwallet/get-available-wallets.tsx b/apps/playground/src/pages/apis/wallets/browserwallet/get-available-wallets.tsx new file mode 100644 index 00000000..7d48bb45 --- /dev/null +++ b/apps/playground/src/pages/apis/wallets/browserwallet/get-available-wallets.tsx @@ -0,0 +1,94 @@ +import { BrowserWallet } from "@meshsdk/core"; + +import LiveCodeDemo from "~/components/sections/live-code-demo"; +import TwoColumnsScroll from "~/components/sections/two-columns-scroll"; +import Codeblock from "~/components/text/codeblock"; + +export default function BrowserWalletGetAvailableWallets() { + return ( + + ); +} + +function Left() { + let example = ``; + example += `[\n`; + example += ` {\n`; + example += ` "id": "nufiSnap",\n`; + example += ` "name": "MetaMask",\n`; + example += ` "icon": "data:image/svg+xml;base64,ICONBASE64HERE",\n`; + example += ` "version": "1.1.0"\n`; + example += ` },\n`; + example += ` {\n`; + example += ` "name": "eternl",\n`; + example += ` "icon": "data:image/png;base64,ICONBASE64HERE",\n`; + example += ` "version": "0.1.0"\n`; + example += ` }\n`; + example += `]\n`; + + return ( + <> +

+ Returns a list of wallets available on user's device. Each wallet is an + object with the following properties: +

+
    +
  • + A name is provided to display wallet's name on the user interface. +
  • +
  • + A version is provided to display wallet's version on the user + interface. +
  • +
  • + An icon is provided to display wallet's icon on the user interface. +
  • +
+

Example:

+ + +

+ With NuFi's support, you can specify the network to connect to. By + default, it is set to "preprod". To define the nufiNetwork: +

+ +

Available networks are:

+
    +
  • production: https://wallet.nu.fi
  • +
  • mainnet: https://wallet-staging.nu.fi
  • +
  • preprod: https://wallet-testnet-staging.nu.fi
  • +
  • preview: https://wallet-preview-staging.nu.fi
  • +
+

You can also specify the network by providing the URL:

+ + + ); +} + +function Right() { + async function runDemo() { + return await BrowserWallet.getAvailableWallets(); + } + + let codeSnippet = ""; + codeSnippet += `import { BrowserWallet } from '@meshsdk/core';\n\n`; + codeSnippet += `const wallets = await BrowserWallet.getAvailableWallets()`; + + return ( + + ); +} diff --git a/apps/playground/src/pages/apis/wallets/browserwallet/index.tsx b/apps/playground/src/pages/apis/wallets/browserwallet/index.tsx index 935ef35d..4ab9b7bf 100644 --- a/apps/playground/src/pages/apis/wallets/browserwallet/index.tsx +++ b/apps/playground/src/pages/apis/wallets/browserwallet/index.tsx @@ -7,10 +7,10 @@ import Metatags from "~/components/site/metatags"; import { metaBrowserwallet } from "~/data/links-wallets"; import BrowserWalletConnectWallet from "./connect-wallet"; import BrowserWalletGetAssets from "./get-assets"; +import BrowserWalletGetAvailableWallets from "./get-available-wallets"; import BrowserWalletGetBalance from "./get-balance"; import BrowserWalletGetChangeAddress from "./get-change-address"; import BrowserWalletGetCollateral from "./get-collateral"; -import BrowserWalletGetInstalledWallets from "./get-installed-wallets"; import BrowserWalletGetLovelace from "./get-lovelace"; import BrowserWalletGetNetworkId from "./get-networkid"; import BrowserWalletGetPolicyIdAssets from "./get-policyid-assets"; @@ -25,7 +25,7 @@ import BrowserWalletSubmitTransaction from "./submit-tx"; const ReactPage: NextPage = () => { const sidebarItems = [ - { label: "Get installed wallets", to: "getInstallWallets" }, + { label: "Get available wallets", to: "getAvailableWallets" }, { label: "Connect wallet", to: "connectWallet" }, { label: "Get balance", to: "getBalance" }, { label: "Get change address", to: "getChangeAddress" }, @@ -76,7 +76,7 @@ const ReactPage: NextPage = () => {

- + diff --git a/apps/playground/src/pages/apis/wallets/browserwallet/sign-data.tsx b/apps/playground/src/pages/apis/wallets/browserwallet/sign-data.tsx index cfb9c5d8..db18bca6 100644 --- a/apps/playground/src/pages/apis/wallets/browserwallet/sign-data.tsx +++ b/apps/playground/src/pages/apis/wallets/browserwallet/sign-data.tsx @@ -116,7 +116,7 @@ function Right() { // placeholder="Payload" // label="Payload" // /> - // + // // - + ); } @@ -192,7 +192,7 @@ function Right( try { if (_mnemonic.length) { const _wallet = new MeshWallet({ - networkId: network, + networkId: network as 0 | 1, fetcher: blockchainProvider, submitter: blockchainProvider, key: { @@ -212,7 +212,7 @@ function Right( if (demoMethod == 1) { try { const _wallet = new MeshWallet({ - networkId: network, + networkId: network as 0 | 1, fetcher: blockchainProvider, submitter: blockchainProvider, key: { @@ -232,7 +232,7 @@ function Right( try { const stake = stakeSkey?.length > 0 ? stakeSkey : undefined; const _wallet = new MeshWallet({ - networkId: network, + networkId: network as 0 | 1, fetcher: blockchainProvider, submitter: blockchainProvider, key: { diff --git a/apps/playground/src/pages/guides/aiken.mdx b/apps/playground/src/pages/guides/aiken.mdx index c69a5e30..e7c55a14 100644 --- a/apps/playground/src/pages/guides/aiken.mdx +++ b/apps/playground/src/pages/guides/aiken.mdx @@ -248,7 +248,6 @@ const assetUtxo = await _getAssetUtxo({ asset: "lovelace", datum: datum, }); -console.log("assetUtxo", assetUtxo); const redeemer = { data: { alternative: 0, fields: ['Hello, World!'] } }; diff --git a/apps/playground/src/pages/guides/standalone.mdx b/apps/playground/src/pages/guides/standalone.mdx index b381083c..506f0e65 100644 --- a/apps/playground/src/pages/guides/standalone.mdx +++ b/apps/playground/src/pages/guides/standalone.mdx @@ -111,7 +111,6 @@ const tx = new Transaction({ initiator: wallet }).sendLovelace( const unsignedTx = await tx.build(); const signedTx = await wallet.signTx(unsignedTx); const txHash = await wallet.submitTx(signedTx); -console.log(txHash); ``` Explanation: diff --git a/apps/playground/src/pages/providers/blockfrost.tsx b/apps/playground/src/pages/providers/blockfrost.tsx index 1c21a2ab..e2c0ee6d 100644 --- a/apps/playground/src/pages/providers/blockfrost.tsx +++ b/apps/playground/src/pages/providers/blockfrost.tsx @@ -73,7 +73,7 @@ const ReactPage: NextPage = () => { If you are using a privately hosted Blockfrost instance, you can set the URL in the parameter:

- + - +

Example responses from unlocking assets from the always succeed smart contract.

- +

With the mem and steps, you can refine the budget for the redeemer. For example:

- + ); } diff --git a/apps/playground/src/pages/providers/listeners/on-transaction-confirmed.tsx b/apps/playground/src/pages/providers/listeners/on-transaction-confirmed.tsx index c7486710..a33b7019 100644 --- a/apps/playground/src/pages/providers/listeners/on-transaction-confirmed.tsx +++ b/apps/playground/src/pages/providers/listeners/on-transaction-confirmed.tsx @@ -38,7 +38,7 @@ function Left() { code += `const txHash = await wallet.submitTx(signedTx);\n`; code += `\n`; code += `blockchainProvider.onTxConfirmed(txHash, () => {\n`; - code += ` console.log('Transaction confirmed');\n`; + code += ` // Transaction confirmed\n`; code += `});\n`; return ( @@ -47,7 +47,7 @@ function Left() { Allow you to listen to a transaction confirmation. Upon confirmation, the callback will be called.

- + ); } diff --git a/apps/playground/src/pages/react/ui-components/connect-wallet.tsx b/apps/playground/src/pages/react/ui-components/connect-wallet.tsx index d5c32d6c..fc5c2089 100644 --- a/apps/playground/src/pages/react/ui-components/connect-wallet.tsx +++ b/apps/playground/src/pages/react/ui-components/connect-wallet.tsx @@ -77,6 +77,12 @@ function Left() { The above code will log "Hello, World!" to the console when the wallet is connected.

+ +

+ You can define the NuFi network to connect to by adding the nufiNetwork prop. +

+ + `} /> ); } diff --git a/apps/playground/src/pages/react/wallet-hooks/use-address.tsx b/apps/playground/src/pages/react/wallet-hooks/use-address.tsx index 1c9b2da4..9dc74b4c 100644 --- a/apps/playground/src/pages/react/wallet-hooks/use-address.tsx +++ b/apps/playground/src/pages/react/wallet-hooks/use-address.tsx @@ -25,7 +25,7 @@ function Left() { accountId is an optional parameter, that allows you to choose which address to return.

- + ); } diff --git a/apps/playground/src/pages/react/wallet-hooks/use-assets.tsx b/apps/playground/src/pages/react/wallet-hooks/use-assets.tsx index de26f001..975849d2 100644 --- a/apps/playground/src/pages/react/wallet-hooks/use-assets.tsx +++ b/apps/playground/src/pages/react/wallet-hooks/use-assets.tsx @@ -21,7 +21,7 @@ function Left() { return ( <>

Return a list of assets in connected wallet from all UTXOs.

- + ); } diff --git a/apps/playground/src/pages/react/wallet-hooks/use-lovelace.tsx b/apps/playground/src/pages/react/wallet-hooks/use-lovelace.tsx index b243ce5b..0a95f51e 100644 --- a/apps/playground/src/pages/react/wallet-hooks/use-lovelace.tsx +++ b/apps/playground/src/pages/react/wallet-hooks/use-lovelace.tsx @@ -21,7 +21,7 @@ function Left() { return ( <>

Return amount of lovelace in wallet.

- + ); } diff --git a/apps/playground/src/pages/react/wallet-hooks/use-network.tsx b/apps/playground/src/pages/react/wallet-hooks/use-network.tsx index 39c5ce03..b50176fb 100644 --- a/apps/playground/src/pages/react/wallet-hooks/use-network.tsx +++ b/apps/playground/src/pages/react/wallet-hooks/use-network.tsx @@ -21,7 +21,7 @@ function Left() { return ( <>

Return the network of connected wallet.

- + ); } diff --git a/apps/playground/src/pages/react/wallet-hooks/use-wallet-list.tsx b/apps/playground/src/pages/react/wallet-hooks/use-wallet-list.tsx index 7cf22026..9bd9dc4d 100644 --- a/apps/playground/src/pages/react/wallet-hooks/use-wallet-list.tsx +++ b/apps/playground/src/pages/react/wallet-hooks/use-wallet-list.tsx @@ -16,18 +16,23 @@ export default function ReactHookUseWalletList() { } function Left() { - let code1 = `const wallets = useWalletList();`; - return ( <>

Returns a list of wallets installed on user's device.

- + +

+ You can define the NuFi network to connect to by adding the{" "} + nufiNetwork prop. +

+ ); } function Right() { - const wallets = useWalletList(); + const wallets = useWalletList({ nufiNetwork: "preprod" }); let code3 = `import { useWalletList } from '@meshsdk/react';\n\n`; code3 += `export default function Page() {\n`; @@ -50,13 +55,13 @@ function Right() { <> - + {wallets.map((wallet, i) => { return ( diff --git a/apps/playground/src/pages/smart-contracts/common.tsx b/apps/playground/src/pages/smart-contracts/common.tsx index 30699bd4..bed6602f 100644 --- a/apps/playground/src/pages/smart-contracts/common.tsx +++ b/apps/playground/src/pages/smart-contracts/common.tsx @@ -7,7 +7,7 @@ export function InstallSmartContract() {

First you can to install the @meshsdk/contracts package:

- + ); } diff --git a/apps/playground/src/pages/smart-contracts/escrow/index.tsx b/apps/playground/src/pages/smart-contracts/escrow/index.tsx index 79e1444c..179c7568 100644 --- a/apps/playground/src/pages/smart-contracts/escrow/index.tsx +++ b/apps/playground/src/pages/smart-contracts/escrow/index.tsx @@ -1,6 +1,7 @@ import type { NextPage } from "next"; import Link from "next/link"; +import MintMeshToken from "~/components/cardano/mint-mesh-token"; import SidebarFullwidth from "~/components/layouts/sidebar-fullwidth"; import TitleIconDescriptionBody from "~/components/sections/title-icon-description-body"; import Metatags from "~/components/site/metatags"; @@ -73,14 +74,16 @@ const ReactPage: NextPage = () => { provider,{" "} MeshTxBuilder and MeshEscrowContract.

- +

Both on-chain and off-chain codes are open-source and available on{" "} - + Mesh Github Repository .

+ + diff --git a/apps/playground/src/pages/smart-contracts/giftcard/index.tsx b/apps/playground/src/pages/smart-contracts/giftcard/index.tsx index c806e018..edd48305 100644 --- a/apps/playground/src/pages/smart-contracts/giftcard/index.tsx +++ b/apps/playground/src/pages/smart-contracts/giftcard/index.tsx @@ -72,10 +72,10 @@ const ReactPage: NextPage = () => { provider,{" "} MeshTxBuilder and MeshGiftCardContract.

- +

Both on-chain and off-chain codes are open-source and available on{" "} - + Mesh Github Repository . diff --git a/apps/playground/src/pages/smart-contracts/marketplace/index.tsx b/apps/playground/src/pages/smart-contracts/marketplace/index.tsx index 7caf6d36..b9bc024a 100644 --- a/apps/playground/src/pages/smart-contracts/marketplace/index.tsx +++ b/apps/playground/src/pages/smart-contracts/marketplace/index.tsx @@ -1,6 +1,7 @@ import type { NextPage } from "next"; import Link from "next/link"; +import MintMeshToken from "~/components/cardano/mint-mesh-token"; import SidebarFullwidth from "~/components/layouts/sidebar-fullwidth"; import TitleIconDescriptionBody from "~/components/sections/title-icon-description-body"; import Metatags from "~/components/site/metatags"; @@ -81,7 +82,7 @@ const ReactPage: NextPage = () => { and a connected browser wallet. Here is an example how we can initialize the Marketplace.

- +

To initialize the Marketplace, we import the{" "} MeshMarketplaceContract. The first JSON object is the{" "} @@ -102,11 +103,13 @@ const ReactPage: NextPage = () => {

Both on-chain and off-chain codes are open-source and available on{" "} - + Mesh Github Repository .

+ + diff --git a/apps/playground/src/pages/smart-contracts/marketplace/list-asset.tsx b/apps/playground/src/pages/smart-contracts/marketplace/list-asset.tsx index aa7c5107..53d50d00 100644 --- a/apps/playground/src/pages/smart-contracts/marketplace/list-asset.tsx +++ b/apps/playground/src/pages/smart-contracts/marketplace/list-asset.tsx @@ -2,6 +2,7 @@ import { useState } from "react"; import { useWallet } from "@meshsdk/react"; +import MintMeshToken from "~/components/cardano/mint-mesh-token"; import Input from "~/components/form/input"; import InputTable from "~/components/sections/input-table"; import LiveCodeDemo from "~/components/sections/live-code-demo"; diff --git a/apps/playground/src/pages/smart-contracts/payment-splitter/index.tsx b/apps/playground/src/pages/smart-contracts/payment-splitter/index.tsx index 8d68e67c..b07edc41 100644 --- a/apps/playground/src/pages/smart-contracts/payment-splitter/index.tsx +++ b/apps/playground/src/pages/smart-contracts/payment-splitter/index.tsx @@ -92,10 +92,10 @@ const ReactPage: NextPage = () => { payees is required to define the allowed payout addresses for the contract.

- +

Both on-chain and off-chain codes are open-source and available on{" "} - + Mesh Github Repository . diff --git a/apps/playground/src/pages/smart-contracts/swap/index.tsx b/apps/playground/src/pages/smart-contracts/swap/index.tsx index 968da425..f496e18d 100644 --- a/apps/playground/src/pages/smart-contracts/swap/index.tsx +++ b/apps/playground/src/pages/smart-contracts/swap/index.tsx @@ -1,6 +1,7 @@ import type { NextPage } from "next"; import Link from "next/link"; +import MintMeshToken from "~/components/cardano/mint-mesh-token"; import SidebarFullwidth from "~/components/layouts/sidebar-fullwidth"; import TitleIconDescriptionBody from "~/components/sections/title-icon-description-body"; import Metatags from "~/components/site/metatags"; @@ -73,14 +74,16 @@ const ReactPage: NextPage = () => { provider,{" "} MeshTxBuilder and MeshSwapContract.

- +

Both on-chain and off-chain codes are open-source and available on{" "} - + Mesh Github Repository .

+ + diff --git a/apps/playground/src/pages/smart-contracts/vesting/index.tsx b/apps/playground/src/pages/smart-contracts/vesting/index.tsx index 2e17713c..fe76191a 100644 --- a/apps/playground/src/pages/smart-contracts/vesting/index.tsx +++ b/apps/playground/src/pages/smart-contracts/vesting/index.tsx @@ -72,10 +72,10 @@ const ReactPage: NextPage = () => { provider,{" "} MeshTxBuilder and MeshVestingContract.

- +

Both on-chain and off-chain codes are open-source and available on{" "} - + Mesh Github Repository . diff --git a/package-lock.json b/package-lock.json index 8381022c..22a43665 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5795,6 +5795,14 @@ "resolved": "packages/mesh-wallet", "link": true }, + "node_modules/@metamask/detect-provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@metamask/detect-provider/-/detect-provider-2.0.0.tgz", + "integrity": "sha512-sFpN+TX13E9fdBDh9lvQeZdJn4qYoRb/6QF2oZZK/Pn559IhCFacPMU1rMuqyXoFQF3JSJfii2l98B87QDPeCQ==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@microsoft/tsdoc": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", @@ -6080,6 +6088,22 @@ "node": ">= 8" } }, + "node_modules/@nufi/dapp-client-cardano": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nufi/dapp-client-cardano/-/dapp-client-cardano-0.3.1.tgz", + "integrity": "sha512-9anqGHu+OP0U0po/Rk6thmR+qcgqtRY3bppudC3As0dgXIhSfsWJBKIXw2Q/byCYL5l/GsmyC9XgdEKB7+oVeQ==", + "dependencies": { + "@nufi/dapp-client-core": "0.3.1" + } + }, + "node_modules/@nufi/dapp-client-core": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nufi/dapp-client-core/-/dapp-client-core-0.3.1.tgz", + "integrity": "sha512-MexKhCE1dZGYTyxZuqQGCaZN0tZW0RyqDY/wzMafwuP5LUKxoxahCJ5U+SF37v4FrrDz6svNddV69aUSMIldag==", + "dependencies": { + "@metamask/detect-provider": "^2.0.0" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -8943,6 +8967,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", @@ -11877,7 +11902,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", @@ -14677,6 +14703,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", @@ -14688,6 +14715,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" } @@ -18874,6 +18902,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" @@ -18882,12 +18911,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" @@ -18896,7 +18927,8 @@ "node_modules/spdx-license-ids": { "version": "3.0.18", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", - "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==" + "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", + "dev": true }, "node_modules/split-ca": { "version": "1.0.1", @@ -20469,6 +20501,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" @@ -20824,6 +20857,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" @@ -20835,7 +20869,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", @@ -21029,7 +21064,7 @@ }, "packages/mesh-common": { "name": "@meshsdk/common", - "version": "1.5.32", + "version": "1.6.1", "license": "Apache-2.0", "dependencies": { "@emurgo/cip14-js": "3.0.1", @@ -21045,7 +21080,7 @@ }, "packages/mesh-contract": { "name": "@meshsdk/contract", - "version": "1.5.32", + "version": "1.6.1", "license": "Apache-2.0", "dependencies": { "@meshsdk/common": "*", @@ -21064,7 +21099,7 @@ }, "packages/mesh-core": { "name": "@meshsdk/core", - "version": "1.5.32", + "version": "1.6.1", "license": "Apache-2.0", "dependencies": { "@meshsdk/common": "*", @@ -21085,7 +21120,7 @@ }, "packages/mesh-core-csl": { "name": "@meshsdk/core-csl", - "version": "1.5.32", + "version": "1.6.1", "license": "Apache-2.0", "dependencies": { "@meshsdk/common": "*", @@ -21105,7 +21140,7 @@ }, "packages/mesh-core-cst": { "name": "@meshsdk/core-cst", - "version": "1.5.32", + "version": "1.6.1", "license": "Apache-2.0", "dependencies": { "@cardano-sdk/core": "^0.35.4", @@ -21128,7 +21163,7 @@ }, "packages/mesh-provider": { "name": "@meshsdk/provider", - "version": "1.5.32", + "version": "1.6.1", "license": "Apache-2.0", "dependencies": { "@meshsdk/common": "*", @@ -21144,7 +21179,7 @@ }, "packages/mesh-react": { "name": "@meshsdk/react", - "version": "1.5.32", + "version": "1.6.1", "license": "Apache-2.0", "dependencies": { "@meshsdk/common": "*", @@ -21166,7 +21201,7 @@ }, "packages/mesh-transaction": { "name": "@meshsdk/transaction", - "version": "1.5.32", + "version": "1.6.1", "license": "Apache-2.0", "dependencies": { "@meshsdk/common": "*", @@ -21184,12 +21219,14 @@ }, "packages/mesh-wallet": { "name": "@meshsdk/wallet", - "version": "1.5.32", + "version": "1.6.1", "license": "Apache-2.0", "dependencies": { "@meshsdk/common": "*", "@meshsdk/core-cst": "*", - "@meshsdk/transaction": "*" + "@meshsdk/transaction": "*", + "@nufi/dapp-client-cardano": "^0.3.1", + "@nufi/dapp-client-core": "^0.3.1" }, "devDependencies": { "@meshsdk/typescript-config": "*", diff --git a/packages/config-jest/jest.config.ts b/packages/config-jest/jest.config.ts index efbea431..9042e9fd 100644 --- a/packages/config-jest/jest.config.ts +++ b/packages/config-jest/jest.config.ts @@ -6,21 +6,14 @@ const jestConfig: Config = { testEnvironment: "node", testMatch: ["**/packages/**/*.test.ts"], setupFiles: ["dotenv/config"], - preset: "ts-jest/presets/default-esm", + preset: "ts-jest", moduleNameMapper: { "^(\\.{1,2}/.*)\\.js$": "$1", }, transform: { - "^.+\\.tsx?$": [ - "ts-jest", - { - useESM: true, - }, - ], + "^.+\\.[jt]s?$": "ts-jest", }, - transformIgnorePatterns: [ - "/node_modules/(?!@meshsdk/core-csl)", // Add exceptions for ESM packages - ], + transformIgnorePatterns: ["/node_modules/(?!@meshsdk/.*)"], }; export default jestConfig; diff --git a/packages/mesh-common/package.json b/packages/mesh-common/package.json index f2e6771e..56a93883 100644 --- a/packages/mesh-common/package.json +++ b/packages/mesh-common/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/common", - "version": "1.6.1", + "version": "1.6.2", "description": "", "main": "./dist/index.cjs", "module": "./dist/index.js", diff --git a/packages/mesh-common/src/data/value.ts b/packages/mesh-common/src/data/value.ts index f88b7089..cca749b0 100644 --- a/packages/mesh-common/src/data/value.ts +++ b/packages/mesh-common/src/data/value.ts @@ -4,6 +4,7 @@ */ import { Asset } from "../types"; +import { BigNum } from "../utils"; import { assocMap, AssocMap, @@ -15,56 +16,303 @@ import { tokenName, } from "./json"; +/** + * Aiken alias + * Value is the JSON representation of Cardano data Value + */ export type Value = AssocMap>; +/** + * Aiken alias + * MValue is the Cardano data Value in Mesh Data type + */ export type MValue = Map>; -export const value = (assets: Asset[]): Value => { - const valueMapToParse: [CurrencySymbol, AssocMap][] = []; - const valueMap: { [key: string]: { [key: string]: number } } = {}; +/** + * The utility function to convert assets into Cardano data Value in JSON + * @param assets The assets to convert + * @returns The Cardano data Value in JSON + */ +export const value = (assets: Asset[]) => { + return MeshValue.fromAssets(assets).toJSON(); +}; + +/** + * The utility function to convert assets into Cardano data Value in Mesh Data type + * @param assets The assets to convert + * @returns The Cardano data Value in Mesh Data type + */ +export const mValue = (assets: Asset[]) => { + return MeshValue.fromAssets(assets).toData(); +}; + +/** + * MeshValue provide utility to handle the Cardano value manipulation. It offers certain axioms: + * 1. No duplication of asset - adding assets with same asset name will increase the quantity of the asset in the same record. + * 2. No zero and negative entry - the quantity of the asset should not be zero or negative. + * 3. Sanitization of lovelace asset name - the class handle back and forth conversion of lovelace asset name to empty string. + * 4. Easy convertion to Cardano data - offer utility to convert into either Mesh Data type and JSON type for its Cardano data representation. + */ +export class MeshValue { + value: Record; + + constructor(value: Record = {}) { + this.value = value; + } + + /** + * Converting assets into MeshValue + * @param assets The assets to convert + * @returns MeshValue + */ + static fromAssets = (assets: Asset[]): MeshValue => { + const value = new MeshValue(); + value.addAssets(assets); + return value; + }; + + /** + * Converting Value (the JSON representation of Cardano data Value) into MeshValue + * @param plutusValue The Value to convert + * @returns MeshValue + */ + static fromValue = (plutusValue: Value): MeshValue => { + const assets: Asset[] = []; + + plutusValue.map.forEach((policyMap) => { + const policy = policyMap.k.bytes; + policyMap.v.map.forEach((tokenMap) => { + const token = tokenMap.k.bytes; + const quantity = tokenMap.v.int.toString(); + const unsanitizedUnit = policy + token; + const unit = unsanitizedUnit === "" ? "lovelace" : unsanitizedUnit; + assets.push({ unit, quantity }); + }); + }); + + return MeshValue.fromAssets(assets); + }; - assets.forEach((asset) => { - const sanitizedName = asset.unit.replace("lovelace", ""); - const policy = sanitizedName.slice(0, 56) || ""; - const token = sanitizedName.slice(56) || ""; + /** + * Add an asset to the Value class's value record. + * @param asset The asset to add + * @returns The updated MeshValue object + */ + addAsset = (asset: Asset): this => { + const quantity = BigInt(asset.quantity); + const { unit } = asset; - if (!valueMap[policy]) { - valueMap[policy] = {}; + if (this.value[unit]) { + this.value[unit] += quantity; + } else { + this.value[unit] = quantity; } + return this; + }; + + /** + * Add an array of assets to the Value class's value record. + * @param assets The assets to add + * @returns The updated MeshValue object + */ + addAssets = (assets: Asset[]): this => { + assets.forEach((asset) => { + this.addAsset(asset); + }); + return this; + }; - if (!valueMap[policy]![token]) { - valueMap[policy]![token] = Number(asset.quantity); + /** + * Substract an asset from the Value class's value record. + * @param asset The asset to subtract + * @returns The updated MeshValue object + */ + negateAsset = (asset: Asset): this => { + const { unit, quantity: assetQty } = asset; + const quantity = BigNum.new(this.value[unit]); + quantity.clampedSub(BigNum.new(assetQty)); + + if (quantity.value === BigInt(0)) { + delete this.value[unit]; } else { - valueMap[policy]![token] += Number(asset.quantity); + this.value[unit] = quantity.value; } - }); + return this; + }; - Object.keys(valueMap).forEach((policy) => { - const policyByte = currencySymbol(policy); - const tokens: [TokenName, Integer][] = Object.keys(valueMap[policy]!).map( - (name) => [tokenName(name), integer(valueMap[policy]![name]!)], - ); + /** + * Subtract an array of assets from the Value class's value record. + * @param assets The assets to subtract + * @returns The updated MeshValue object + */ + negateAssets = (assets: Asset[]): this => { + assets.forEach((asset) => { + this.negateAsset(asset); + }); + return this; + }; - const policyMap = assocMap(tokens); - valueMapToParse.push([policyByte, policyMap]); - }); + /** + * Get the quantity of asset object per unit + * @param unit The unit to get the quantity of + * @returns The quantity of the asset + */ + get = (unit: string): bigint => { + return this.value[unit] ? BigInt(this.value[unit]) : BigInt(0); + }; - return assocMap(valueMapToParse); -}; + /** + * Get all asset units + * @returns The asset units + */ + units = (): string[] => { + return Object.keys(this.value); + }; -export const parsePlutusValueToAssets = (plutusValue: Value): Asset[] => { - const assets: Asset[] = []; - - plutusValue.map.forEach((policyMap) => { - const policy = policyMap.k.bytes; - policyMap.v.map.forEach((tokenMap) => { - const token = tokenMap.k.bytes; - const quantity = tokenMap.v.int.toString(); - const unsanitizedUnit = policy + token; - const unit = unsanitizedUnit === "" ? "lovelace" : unsanitizedUnit; - assets.push({ unit, quantity }); + /** + * Check if the value is greater than or equal to another value + * @param other - The value to compare against + * @returns boolean + */ + geq = (other: MeshValue): boolean => { + return Object.keys(other.value).every((key) => this.geqUnit(key, other)); + }; + + /** + * Check if the specific unit of value is greater than or equal to that unit of another value + * @param unit - The unit to compare + * @param other - The value to compare against + * @returns boolean + */ + geqUnit = (unit: string, other: MeshValue): boolean => { + if (this.value[unit] === undefined || other.value[unit] === undefined) { + return false; + } + return BigInt(this.value[unit]) >= BigInt(other.value[unit]); + }; + + /** + * Check if the value is less than or equal to another value + * @param other - The value to compare against + * @returns boolean + */ + leq = (other: MeshValue): boolean => { + return Object.keys(other.value).every((key) => this.leqUnit(key, other)); + }; + + /** + * Check if the specific unit of value is less than or equal to that unit of another value + * @param unit - The unit to compare + * @param other - The value to compare against + * @returns boolean + */ + leqUnit = (unit: string, other: MeshValue): boolean => { + if (this.value[unit] === undefined || other.value[unit] === undefined) { + return false; + } + return BigInt(this.value[unit]) <= BigInt(other.value[unit]); + }; + + /** + * Check if the value is empty + * @returns boolean + */ + isEmpty = (): boolean => { + return Object.keys(this.value).length === 0; + }; + + /** + * Merge the given values + * @param values The other values to merge + * @returns this + */ + merge = (values: MeshValue | MeshValue[]): this => { + const valuesArray = Array.isArray(values) ? values : [values]; + + valuesArray.forEach((other) => { + Object.entries(other.value).forEach(([key, value]) => { + this.value[key] = + (this.value[key] !== undefined + ? BigInt(this.value[key]) + : BigInt(0)) + BigInt(value); + }); }); - }); - return assets; -}; + return this; + }; + + /** + * Convert the MeshValue object into an array of Asset + * @returns The array of Asset + */ + toAssets = (): Asset[] => { + const assets: Asset[] = []; + Object.entries(this.value).forEach(([unit, quantity]) => { + assets.push({ unit, quantity: quantity.toString() }); + }); + return assets; + }; + + /** + * Convert the MeshValue object into Cardano data Value in Mesh Data type + */ + toData = (): MValue => { + const valueMap: MValue = new Map(); + this.toAssets().forEach((asset) => { + const policy = asset.unit.slice(0, 56) || ""; + const token = asset.unit.slice(56) || ""; + + if (!valueMap.has(policy)) { + valueMap.set(policy, new Map()); + } + + const tokenMap = valueMap.get(policy)!; + const quantity = tokenMap?.get(token); + if (!quantity) { + tokenMap.set(token, BigInt(asset.quantity)); + } else { + tokenMap.set(token, quantity + BigInt(asset.quantity)); + } + }); + + return valueMap; + }; + + /** + * Convert the MeshValue object into a JSON representation of Cardano data Value + * @returns Cardano data Value in JSON + */ + toJSON = (): Value => { + const valueMapToParse: [CurrencySymbol, AssocMap][] = + []; + const valueMap: { [key: string]: { [key: string]: number } } = {}; + + this.toAssets().forEach((asset) => { + const sanitizedName = asset.unit.replace("lovelace", ""); + const policy = sanitizedName.slice(0, 56) || ""; + const token = sanitizedName.slice(56) || ""; + + if (!valueMap[policy]) { + valueMap[policy] = {}; + } + + if (!valueMap[policy]![token]) { + valueMap[policy]![token] = Number(asset.quantity); + } else { + valueMap[policy]![token] += Number(asset.quantity); + } + }); + + Object.keys(valueMap).forEach((policy) => { + const policyByte = currencySymbol(policy); + const tokens: [TokenName, Integer][] = Object.keys(valueMap[policy]!).map( + (name) => [tokenName(name), integer(valueMap[policy]![name]!)], + ); + + const policyMap = assocMap(tokens); + valueMapToParse.push([policyByte, policyMap]); + }); + + return assocMap(valueMapToParse); + }; +} diff --git a/packages/mesh-common/src/interfaces/serializer.ts b/packages/mesh-common/src/interfaces/serializer.ts index 924b120b..b89c6cad 100644 --- a/packages/mesh-common/src/interfaces/serializer.ts +++ b/packages/mesh-common/src/interfaces/serializer.ts @@ -19,6 +19,7 @@ export interface IMeshTxSerializer { deserializer: IDeserializer; serializeData(data: BuilderData): string; serializeAddress(address: DeserializedAddress, networkId?: 0 | 1): string; + serializePoolId(hash: string): string; } export interface IResolver { keys: { @@ -36,9 +37,6 @@ export interface IResolver { script: { resolveScriptRef(script: NativeScript | PlutusScript): string; }; - pool: { - resolvePoolId(hash: string): string; - }; } export interface IDeserializer { @@ -49,4 +47,7 @@ export interface IDeserializer { deserializeNativeScript(script: NativeScript): DeserializedScript; deserializePlutusScript(script: PlutusScript): DeserializedScript; }; + cert: { + deserializePoolId(poolId: string): string; + }; } diff --git a/packages/mesh-common/src/utils/asset-fingerprint.ts b/packages/mesh-common/src/utils/asset-fingerprint.ts index 2a8e353c..49861be7 100644 --- a/packages/mesh-common/src/utils/asset-fingerprint.ts +++ b/packages/mesh-common/src/utils/asset-fingerprint.ts @@ -5,7 +5,7 @@ import { toBytes } from "../data"; export const AssetFingerprint = CIP14; export const resolveFingerprint = (policyId: string, assetName: string) => { - return (AssetFingerprint as any).default + return (AssetFingerprint as any).default // todo: check the behaviour .fromParts(toBytes(policyId), toBytes(assetName)) .fingerprint(); }; diff --git a/packages/mesh-common/src/utils/bigNum.ts b/packages/mesh-common/src/utils/bigNum.ts index bbded1a0..b6acc44c 100644 --- a/packages/mesh-common/src/utils/bigNum.ts +++ b/packages/mesh-common/src/utils/bigNum.ts @@ -1,10 +1,21 @@ export class BigNum { value: bigint; - constructor(value: number | string) { + constructor(value?: bigint | number | string) { + if (!value) { + this.value = BigInt(0); + return; + } this.value = BigInt(value); } + static new(value: number | string | bigint | undefined): BigNum { + if (!value) { + return new BigNum(0); + } + return new BigNum(value); + } + // Operators divFloor(other: BigNum): BigNum { @@ -49,10 +60,6 @@ export class BigNum { } } - static new = (value: number | string): BigNum => { - return new BigNum(value); - }; - // Override toString(): string { diff --git a/packages/mesh-common/test/data/mesh/aliases.test.ts b/packages/mesh-common/test/data/mesh/aliases.test.ts index c9cb4d3a..fe07568f 100644 --- a/packages/mesh-common/test/data/mesh/aliases.test.ts +++ b/packages/mesh-common/test/data/mesh/aliases.test.ts @@ -5,7 +5,8 @@ import { mTxOutRef, outputReference, txOutRef, -} from "../../../src"; +} from "@meshsdk/common"; + import { serializeData } from "./common"; const testHash = "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc81700"; diff --git a/packages/mesh-common/test/data/mesh/common.ts b/packages/mesh-common/test/data/mesh/common.ts index b19bbac3..99f6336d 100644 --- a/packages/mesh-common/test/data/mesh/common.ts +++ b/packages/mesh-common/test/data/mesh/common.ts @@ -1,7 +1,6 @@ +import { Data } from "@meshsdk/common"; import { castDataToPlutusData } from "@meshsdk/core-csl"; -import { Data } from "../../../src"; - export const serializeData = (mesh: Data, json: any) => { const meshData = castDataToPlutusData({ type: "Mesh", diff --git a/packages/mesh-common/test/data/mesh/constructors.test.ts b/packages/mesh-common/test/data/mesh/constructors.test.ts index ab2c1820..46ea1350 100644 --- a/packages/mesh-common/test/data/mesh/constructors.test.ts +++ b/packages/mesh-common/test/data/mesh/constructors.test.ts @@ -4,12 +4,12 @@ import { conStr0, conStr1, conStr2, - Data, mConStr, mConStr0, mConStr1, mConStr2, -} from "../../../src"; +} from "@meshsdk/common"; + import { serializeData } from "./common"; const testByteString = "abcd"; diff --git a/packages/mesh-common/test/data/mesh/credentials.test.ts b/packages/mesh-common/test/data/mesh/credentials.test.ts index 097e393a..72db3cd8 100644 --- a/packages/mesh-common/test/data/mesh/credentials.test.ts +++ b/packages/mesh-common/test/data/mesh/credentials.test.ts @@ -1,15 +1,12 @@ import { - conStr0, - conStr1, maybeStakingHash, mMaybeStakingHash, mPubKeyAddress, mScriptAddress, pubKeyAddress, - pubKeyHash, scriptAddress, - scriptHash, -} from "../../../src"; +} from "@meshsdk/common"; + import { serializeData } from "./common"; const testKeyHash1 = "1e4eb194e3335a0dcc4f5c5d009318167c583bb3b0879d9f718cd9e0"; diff --git a/packages/mesh-common/test/data/mesh/primitives.test.ts b/packages/mesh-common/test/data/mesh/primitives.test.ts index aaebd06b..65e92aa6 100644 --- a/packages/mesh-common/test/data/mesh/primitives.test.ts +++ b/packages/mesh-common/test/data/mesh/primitives.test.ts @@ -3,7 +3,8 @@ import { mBool, mPlutusBSArrayToString, mStringToPlutusBSArray, -} from "../../../src"; +} from "@meshsdk/common"; + import { serializeData } from "./common"; describe("Plutus data type", () => { diff --git a/packages/mesh-common/test/data/value.test.ts b/packages/mesh-common/test/data/value.test.ts deleted file mode 100644 index 94d65ab5..00000000 --- a/packages/mesh-common/test/data/value.test.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { - Asset, - byteString, - ByteString, - dict, - Dict, - Integer, - integer, - parsePlutusValueToAssets, - Value, - value, -} from "../../src"; - -describe("value", () => { - test("Simple ADA Value", () => { - const val: Asset[] = [{ unit: "lovelace", quantity: "1000000" }]; - const datum: Value = value(val); - - const nameMap = dict([[byteString(""), integer(1000000)]]); - const valMap = dict>([[byteString(""), nameMap]]); - expect(JSON.stringify(datum)).toBe(JSON.stringify(valMap)); - }); - test("Simple token Value", () => { - const val: Asset[] = [ - { - unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", - quantity: "345", - }, - ]; - const datum: Value = value(val); - - const nameMap = dict([ - [byteString("74657374696e676e657777616c2e616461"), integer(345)], - ]); - const valMap = dict>([ - [ - byteString("baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc81700"), - nameMap, - ], - ]); - expect(JSON.stringify(datum)).toBe(JSON.stringify(valMap)); - }); - test("Complex Value", () => { - const val: Asset[] = [ - { unit: "lovelace", quantity: "1000000" }, - { - unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", - quantity: "345", - }, - { - unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc817001234", - quantity: "567", - }, - ]; - const datum: Value = value(val); - - const nameMap = dict([ - [byteString("1234"), integer(567)], - [byteString("74657374696e676e657777616c2e616461"), integer(345)], - ]); - const valMap = dict>([ - [byteString(""), dict([[byteString(""), integer(1000000)]])], - [ - byteString("baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc81700"), - nameMap, - ], - ]); - expect(JSON.stringify(datum)).toBe(JSON.stringify(valMap)); - }); -}); - -describe("Value", () => { - test("Simple ADA Value", () => { - const val: Asset[] = [{ unit: "lovelace", quantity: "1000000" }]; - const plutusValue: Value = value(val); - const assets: Asset[] = parsePlutusValueToAssets(plutusValue); - - expect(JSON.stringify(val)).toBe(JSON.stringify(assets)); - }); - test("Simple token Value", () => { - const val: Asset[] = [ - { - unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", - quantity: "345", - }, - ]; - const plutusValue: Value = value(val); - const assets: Asset[] = parsePlutusValueToAssets(plutusValue); - - expect(JSON.stringify(val)).toBe(JSON.stringify(assets)); - }); - test("Complex Value", () => { - const val: Asset[] = [ - { unit: "lovelace", quantity: "1000000" }, - { - unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc817001234", - quantity: "567", - }, - { - unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", - quantity: "345", - }, - ]; - const plutusValue: Value = value(val); - const assets: Asset[] = parsePlutusValueToAssets(plutusValue); - expect(JSON.stringify(val)).toBe(JSON.stringify(assets)); - }); -}); diff --git a/packages/mesh-common/test/data/value/accessor.test.ts b/packages/mesh-common/test/data/value/accessor.test.ts new file mode 100644 index 00000000..4e9e1573 --- /dev/null +++ b/packages/mesh-common/test/data/value/accessor.test.ts @@ -0,0 +1,68 @@ +import { MeshValue } from "@meshsdk/common"; + +import { mockUnit } from "./common"; + +describe("MeshValue class", () => { + describe("get", () => { + it("should return the quantity of an existing asset", () => { + const value = new MeshValue({ + lovelace: 20n, + [mockUnit]: 10n, + }); + expect(value.get("lovelace")).toEqual(BigInt(20)); + expect(value.get(mockUnit)).toEqual(BigInt(10)); + }); + + it("should return 0 for a non-existing asset", () => { + const value = new MeshValue({ lovelace: 20n }); + expect(value.get(mockUnit)).toEqual(BigInt(0)); + }); + + it("should handle an empty value object", () => { + const value = new MeshValue(); + expect(value.get("lovelace")).toEqual(BigInt(0)); + }); + + it("should return the correct quantity after adding assets", () => { + const value = new MeshValue({ lovelace: 20n }); + value.addAsset({ + unit: mockUnit, + quantity: "10", + }); + expect(value.get(mockUnit)).toEqual(BigInt(10)); + }); + + it("should return the correct quantity after subtracting assets", () => { + const value = new MeshValue({ + lovelace: 20n, + [mockUnit]: 10n, + }); + value.negateAssets([ + { + unit: mockUnit, + quantity: "5", + }, + ]); + expect(value.get(mockUnit)).toEqual(BigInt(5)); + }); + }); + describe("units", () => { + it("should return an empty object when value is empty", () => { + const value = new MeshValue(); + expect(value.units()).toEqual([]); + }); + + it("should return the correct structure for a single asset", () => { + const value = new MeshValue({ lovelace: 20n }); + expect(value.units()).toEqual(["lovelace"]); + }); + + it("should return the correct structure for multiple assets", () => { + const value = new MeshValue({ + lovelace: 20n, + [mockUnit]: 10n, + }); + expect(value.units()).toEqual(["lovelace", mockUnit]); + }); + }); +}); diff --git a/packages/mesh-common/test/data/value/common.ts b/packages/mesh-common/test/data/value/common.ts new file mode 100644 index 00000000..8c531bda --- /dev/null +++ b/packages/mesh-common/test/data/value/common.ts @@ -0,0 +1,4 @@ +export const mockPolicyId = + "c21d710605bb00e69f3c175150552fc498316d80e7efdb1b186db38c"; +export const mockAssetName = "000643b04d65736820676f6f64"; +export const mockUnit = mockPolicyId + mockAssetName; diff --git a/packages/mesh-common/test/data/value/comparator.test.ts b/packages/mesh-common/test/data/value/comparator.test.ts new file mode 100644 index 00000000..f035ca05 --- /dev/null +++ b/packages/mesh-common/test/data/value/comparator.test.ts @@ -0,0 +1,111 @@ +import { MeshValue } from "@meshsdk/common"; + +import { mockUnit } from "./common"; + +describe("MeshValue class", () => { + describe("geq", () => { + it("should return true if the value is greater than or equal to the target value for a specific unit", () => { + const value = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + const target = new MeshValue({ lovelace: 10n, [mockUnit]: 5n }); + expect(value.geq(target)).toBe(true); + }); + + it("should return false if the value is less than the target value for a specific unit", () => { + const value = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + const target = new MeshValue({ lovelace: 30n, [mockUnit]: 15n }); + expect(value.geq(target)).toBe(false); + }); + + it("should return true if the value is equal to the target value for a specific unit", () => { + const value = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + const target = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + expect(value.geq(target)).toBe(true); + }); + }); + describe("geqUnit", () => { + it("should return true if the value is greater than or equal to the target value for a specific unit", () => { + const value = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + const target = new MeshValue({ lovelace: 10n, [mockUnit]: 5n }); + expect(value.geqUnit("lovelace", target)).toBe(true); + expect(value.geqUnit(mockUnit, target)).toBe(true); + }); + + it("should return false if the value is less than the target value for a specific unit", () => { + const value = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + const target = new MeshValue({ lovelace: 30n, [mockUnit]: 15n }); + expect(value.geqUnit("lovelace", target)).toBe(false); + expect(value.geqUnit(mockUnit, target)).toBe(false); + }); + + it("should return true if the value is equal to the target value for a specific unit", () => { + const value = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + const target = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + expect(value.geqUnit("lovelace", target)).toBe(true); + expect(value.geqUnit(mockUnit, target)).toBe(true); + }); + + it("should return false if the unit does not exist in value.value", () => { + const value = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + const target = new MeshValue({ somethingElse: 5n }); + expect(value.geqUnit("somethingElse", target)).toBe(false); + }); + }); + describe("leq", () => { + it("should return true if the value is less than or equal to the target value for a specific unit", () => { + const value = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + const target = new MeshValue({ lovelace: 30n, [mockUnit]: 15n }); + expect(value.leq(target)).toBe(true); + }); + + it("should return false if the value is greater than the target value for a specific unit", () => { + const value = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + const target = new MeshValue({ lovelace: 10n, [mockUnit]: 5n }); + expect(value.leq(target)).toBe(false); + }); + + it("should return true if the value is equal to the target value for a specific unit", () => { + const value = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + const target = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + expect(value.leq(target)).toBe(true); + }); + }); + describe("leqUnit", () => { + it("should return true if the value is less than or equal to the target value for a specific unit", () => { + const value = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + const target = new MeshValue({ lovelace: 30n, [mockUnit]: 15n }); + expect(value.leqUnit("lovelace", target)).toBe(true); + expect(value.leqUnit(mockUnit, target)).toBe(true); + }); + + it("should return false if the value is greater than the target value for a specific unit", () => { + const value = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + const target = new MeshValue({ lovelace: 10n, [mockUnit]: 5n }); + expect(value.leqUnit("lovelace", target)).toBe(false); + expect(value.leqUnit(mockUnit, target)).toBe(false); + }); + + it("should return true if the value is equal to the target value for a specific unit", () => { + const value = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + const target = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + expect(value.leqUnit("lovelace", target)).toBe(true); + expect(value.leqUnit(mockUnit, target)).toBe(true); + }); + + it("should return false if the unit does not exist in value.value", () => { + const value = new MeshValue({ lovelace: 20n, [mockUnit]: 10n }); + const target = new MeshValue({ somethingElse: 5n }); + expect(value.leqUnit("somethingElse", target)).toBe(false); + }); + }); + describe("isEmpty", () => { + it("should return true if the value is empty", () => { + const value = new MeshValue(); + expect(value.isEmpty()).toBe(true); + }); + + it("should return false if the value is not empty", () => { + const value = new MeshValue({ lovelace: 20n }); + expect(value.isEmpty()).toBe(false); + }); + }); +}); diff --git a/packages/mesh-common/test/data/value/convertor.test.ts b/packages/mesh-common/test/data/value/convertor.test.ts new file mode 100644 index 00000000..bfff721f --- /dev/null +++ b/packages/mesh-common/test/data/value/convertor.test.ts @@ -0,0 +1,173 @@ +import { + Asset, + byteString, + dict, + Dict, + Integer, + integer, + MeshValue, + MValue, + mValue, + Value, + value, +} from "@meshsdk/common"; + +import { mockUnit } from "./common"; + +describe("value", () => { + it("should create a new Value instance with the correct value", () => { + const val: Asset[] = [{ unit: "lovelace", quantity: "1000000" }]; + const datum: Value = value(val); + const nameMap = dict([[byteString(""), integer(1000000)]]); + const valMap = dict>([[byteString(""), nameMap]]); + expect(JSON.stringify(datum)).toBe(JSON.stringify(valMap)); + }); + it("Simple token Value", () => { + const val: Asset[] = [ + { + unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", + quantity: "345", + }, + ]; + const datum: Value = value(val); + const nameMap = dict([ + [byteString("74657374696e676e657777616c2e616461"), integer(345)], + ]); + const valMap = dict>([ + [ + byteString("baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc81700"), + nameMap, + ], + ]); + expect(JSON.stringify(datum)).toBe(JSON.stringify(valMap)); + }); + it("Complex Value", () => { + const val: Asset[] = [ + { unit: "lovelace", quantity: "1000000" }, + { + unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", + quantity: "345", + }, + { + unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc817001234", + quantity: "567", + }, + ]; + const datum: Value = value(val); + + const nameMap = dict([ + [byteString("1234"), integer(567)], + [byteString("74657374696e676e657777616c2e616461"), integer(345)], + ]); + const valMap = dict>([ + [byteString(""), dict([[byteString(""), integer(1000000)]])], + [ + byteString("baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc81700"), + nameMap, + ], + ]); + expect(JSON.stringify(datum)).toBe(JSON.stringify(valMap)); + }); +}); + +describe("mValue", () => { + it("should create a new Value instance with the correct value", () => { + const val: Asset[] = [{ unit: "lovelace", quantity: "1000000" }]; + const datum: MValue = mValue(val); + const nameMap = new Map().set("", 1000000); + const valMap = new Map().set("", nameMap); + expect(JSON.stringify(datum)).toBe(JSON.stringify(valMap)); + }); + it("Simple token Value", () => { + const val: Asset[] = [ + { + unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", + quantity: "345", + }, + ]; + const datum: MValue = mValue(val); + const nameMap = new Map().set("74657374696e676e657777616c2e616461", 345); + const valMap = new Map().set( + "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc81700", + nameMap, + ); + expect(JSON.stringify(datum)).toBe(JSON.stringify(valMap)); + }); + it("Complex Value", () => { + const val: Asset[] = [ + { unit: "lovelace", quantity: "1000000" }, + { + unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", + quantity: "345", + }, + { + unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc817001234", + quantity: "567", + }, + ]; + const datum: MValue = mValue(val); + + const lovelaceMap = new Map().set("", 1000000); + const tokenMap = new Map() + .set("1234", 567) + .set("74657374696e676e657777616c2e616461", 345); + const valMap = new Map() + .set("", lovelaceMap) + .set( + "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc81700", + tokenMap, + ); + expect(JSON.stringify(datum)).toBe(JSON.stringify(valMap)); + }); +}); + +describe("MeshValue class", () => { + describe("fromAssets", () => { + it("should create a new Value instance with the correct value", () => { + const assets: Asset[] = [ + { unit: mockUnit, quantity: "100" }, + { unit: "lovelace", quantity: "10" }, + ]; + const value = MeshValue.fromAssets(assets); + expect(value.value).toEqual({ + [mockUnit]: BigInt(100), + lovelace: BigInt(10), + }); + }); + }); + describe("toAssets", () => { + test("Simple ADA Value", () => { + const val: Asset[] = [{ unit: "lovelace", quantity: "1000000" }]; + const plutusValue: Value = value(val); + const assets: Asset[] = MeshValue.fromValue(plutusValue).toAssets(); + expect(JSON.stringify(val)).toBe(JSON.stringify(assets)); + }); + test("Simple token Value", () => { + const val: Asset[] = [ + { + unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", + quantity: "345", + }, + ]; + const plutusValue: Value = value(val); + const assets: Asset[] = MeshValue.fromValue(plutusValue).toAssets(); + expect(JSON.stringify(val)).toBe(JSON.stringify(assets)); + }); + test("Complex Value", () => { + const val: Asset[] = [ + { unit: "lovelace", quantity: "1000000" }, + { + unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc817001234", + quantity: "567", + }, + { + unit: "baefdc6c5b191be372a794cd8d40d839ec0dbdd3c28957267dc8170074657374696e676e657777616c2e616461", + quantity: "345", + }, + ]; + const plutusValue: Value = value(val); + const assets: Asset[] = MeshValue.fromValue(plutusValue).toAssets(); + expect(JSON.stringify(val)).toBe(JSON.stringify(assets)); + }); + }); +}); diff --git a/packages/mesh-common/test/data/value/operators.test.ts b/packages/mesh-common/test/data/value/operators.test.ts new file mode 100644 index 00000000..aac75488 --- /dev/null +++ b/packages/mesh-common/test/data/value/operators.test.ts @@ -0,0 +1,153 @@ +import { Asset, MeshValue } from "@meshsdk/common"; + +import { mockUnit } from "./common"; + +describe("MeshValue class", () => { + describe("addAsset", () => { + it("should add a new asset correctly", () => { + const value = new MeshValue(); + const singleAsset: Asset = { unit: mockUnit, quantity: "100" }; + value.addAsset(singleAsset); + expect(value.value).toEqual({ [mockUnit]: BigInt(100) }); + }); + it("should add to an existing asset correctly", () => { + const value = new MeshValue(); + const singleAsset: Asset = { unit: mockUnit, quantity: "100" }; + value.addAsset(singleAsset); + value.addAsset(singleAsset); + expect(value.value).toEqual({ [mockUnit]: BigInt(200) }); + }); + it("should add multiple assets correctly", () => { + const value = new MeshValue(); + const assets: Asset[] = [ + { unit: mockUnit, quantity: "100" }, + { unit: "lovelace", quantity: "10" }, + ]; + value.addAsset(assets[0]!).addAsset(assets[1]!); + expect(value.value).toEqual({ + [mockUnit]: BigInt(100), + lovelace: BigInt(10), + }); + }); + }); + describe("addAssets", () => { + it("should add multiple assets correctly", () => { + const value = new MeshValue(); + const assets: Asset[] = [ + { unit: mockUnit, quantity: "100" }, + { unit: "lovelace", quantity: "10" }, + { unit: mockUnit, quantity: "100" }, + { unit: "lovelace", quantity: "10" }, + ]; + value.addAssets(assets); + expect(value.value).toEqual({ + [mockUnit]: BigInt(200), + lovelace: BigInt(20), + }); + }); + it("should add multiple assets correctly with different units", () => { + const value = new MeshValue(); + const assets: Asset[] = [ + { unit: mockUnit, quantity: "100" }, + { unit: "lovelace", quantity: "10" }, + { unit: "USDC", quantity: "100" }, + { unit: "lovelace", quantity: "10" }, + ]; + value.addAssets(assets); + expect(value.value).toEqual({ + [mockUnit]: BigInt(100), + lovelace: BigInt(20), + USDC: BigInt(100), + }); + }); + }); + describe("negateAsset", () => { + describe("negateAsset", () => { + it("should subtract quantity from an existing asset", () => { + const value = new MeshValue(); + value.value = { lovelace: 10n }; + value.negateAsset({ unit: "lovelace", quantity: "5" }); + expect(value.value).toEqual({ lovelace: BigInt(5) }); + }); + + it("should remove the asset if the resulting quantity is zero", () => { + const value = new MeshValue(); + value.value = { lovelace: 10n }; + value.negateAsset({ unit: "lovelace", quantity: "10" }); + expect(value.value.lovelace).toBeUndefined(); + }); + + it("should allow negative quantity if the subtraction results in negative value", () => { + const value = new MeshValue(); + value.value = { lovelace: 10n }; + value.negateAsset({ unit: "lovelace", quantity: "15" }); + expect(Object.keys(value.value).length).toBe(0); + }); + + it("should add a new asset with negative quantity if the asset does not exist", () => { + const value = new MeshValue(); + value.negateAsset({ unit: "lovelace", quantity: "5" }); + expect(Object.keys(value.value).length).toBe(0); + }); + }); + }); + describe("negateAssets", () => { + it("should subtract quantities from existing assets", () => { + const value = new MeshValue(); + value.value = { lovelace: 20n, [mockUnit]: 10n }; + value.negateAssets([ + { unit: "lovelace", quantity: "5" }, + { unit: mockUnit, quantity: "3" }, + ]); + expect(value.value).toEqual({ + lovelace: BigInt(15), + [mockUnit]: BigInt(7), + }); + }); + + it("should remove the asset if the resulting quantity is zero", () => { + const value = new MeshValue(); + value.value = { lovelace: 10n, [mockUnit]: 5n }; + value.negateAssets([ + { unit: "lovelace", quantity: "10" }, + { unit: mockUnit, quantity: "5" }, + ]); + expect(Object.keys(value.value).length).toBe(0); + }); + + it("should allow negative quantity if the subtraction results in negative value", () => { + const value = new MeshValue(); + value.value = { lovelace: 10n, [mockUnit]: 5n }; + value.negateAssets([ + { unit: "lovelace", quantity: "15" }, + { unit: mockUnit, quantity: "10" }, + ]); + expect(Object.keys(value.value).length).toBe(0); + }); + }); + + describe("merge", () => { + it("should merge two values correctly", () => { + const value1 = new MeshValue(); + value1.value = { lovelace: 20n, [mockUnit]: 10n }; + const value2 = new MeshValue(); + value2.value = { lovelace: 10n, [mockUnit]: 5n }; + expect(value1.merge(value2).value).toEqual({ + lovelace: 30n, + [mockUnit]: 15n, + }); + }); + + it("should merge two values correctly with different units", () => { + const value1 = new MeshValue(); + value1.value = { lovelace: 20n, [mockUnit]: 10n }; + const value2 = new MeshValue(); + value2.value = { ETH: 10n, [mockUnit]: 5n }; + expect(value1.merge(value2).value).toEqual({ + lovelace: 20n, + [mockUnit]: 15n, + ETH: 10n, + }); + }); + }); +}); diff --git a/packages/mesh-common/test/utils/bigNum.test.ts b/packages/mesh-common/test/utils/bigNum.test.ts new file mode 100644 index 00000000..22cd1109 --- /dev/null +++ b/packages/mesh-common/test/utils/bigNum.test.ts @@ -0,0 +1,157 @@ +import { BigNum } from "@meshsdk/common"; + +describe("BigNum class", () => { + describe("constructor", () => { + it("should get correct new BigNum with number", () => { + const bigNum = new BigNum(100); + expect(bigNum.value).toBe(BigInt(100)); + }); + it("should get correct new BigNum with string", () => { + const bigNum = new BigNum("100"); + expect(bigNum.value).toBe(BigInt(100)); + }); + it("should get correct new BigNum with bigint", () => { + const bigNum = new BigNum(BigInt(100)); + expect(bigNum.value).toBe(BigInt(100)); + }); + it("should get correct new BigNum without param", () => { + const bigNum = new BigNum(); + expect(bigNum.value).toBe(BigInt(0)); + }); + }); + describe("new", () => { + it("should get correct new BigNum with number", () => { + const bigNum = BigNum.new(100); + expect(bigNum.value).toBe(BigInt(100)); + }); + it("should get correct new BigNum with string", () => { + const bigNum = BigNum.new("100"); + expect(bigNum.value).toBe(BigInt(100)); + }); + it("should get correct new BigNum with bigint", () => { + const bigNum = BigNum.new(BigInt(100)); + expect(bigNum.value).toBe(BigInt(100)); + }); + it("should get correct new BigNum without param", () => { + const bigNum = BigNum.new(undefined); + expect(bigNum.value).toBe(BigInt(0)); + }); + }); + describe("divFloor", () => { + it("should get correct divFloor", () => { + const bigNum = new BigNum(100); + const other = new BigNum(10); + const result = bigNum.divFloor(other); + expect(result.value).toBe(BigInt(10)); + }); + it("should get correct divFloor with remainder", () => { + const bigNum = new BigNum(101); + const other = new BigNum(10); + const result = bigNum.divFloor(other); + expect(result.value).toBe(BigInt(10)); + }); + }); + describe("checkedMul", () => { + it("should get correct checkedMul", () => { + const bigNum = new BigNum(100); + const other = new BigNum(10); + const result = bigNum.checkedMul(other); + expect(result.value).toBe(BigInt(1000)); + }); + it("should get correct checkedMul with negative", () => { + const bigNum = new BigNum(100); + const other = new BigNum(-10); + const result = bigNum.checkedMul(other); + expect(result.value).toBe(BigInt(-1000)); + }); + }); + describe("checkedAdd", () => { + it("should get correct checkedAdd", () => { + const bigNum = new BigNum(100); + const other = new BigNum(10); + const result = bigNum.checkedAdd(other); + expect(result.value).toBe(BigInt(110)); + }); + it("should get correct checkedAdd with negative", () => { + const bigNum = new BigNum(100); + const other = new BigNum(-10); + const result = bigNum.checkedAdd(other); + expect(result.value).toBe(BigInt(90)); + }); + }); + describe("checkedSub", () => { + it("should get correct checkedSub", () => { + const bigNum = new BigNum(100); + const other = new BigNum(10); + const result = bigNum.checkedSub(other); + expect(result.value).toBe(BigInt(90)); + }); + it("should get correct checkedSub with negative", () => { + const bigNum = new BigNum(100); + const other = new BigNum(110); + const result = bigNum.checkedSub(other); + expect(result.value).toBe(BigInt(-10)); + }); + }); + describe("clampedSub", () => { + it("should get correct clampedSub", () => { + const bigNum = new BigNum(100); + const other = new BigNum(10); + const result = bigNum.clampedSub(other); + expect(result.value).toBe(BigInt(90)); + }); + it("should get correct clampedSub with negative", () => { + const bigNum = new BigNum(100); + const other = new BigNum(110); + const result = bigNum.clampedSub(other); + expect(result.value).toBe(BigInt(0)); + }); + }); + describe("lessThan", () => { + it("should get correct lessThan", () => { + const bigNum = new BigNum(100); + const other = new BigNum(110); + const result = bigNum.lessThan(other); + expect(result).toBe(true); + }); + it("should get correct lessThan with equal", () => { + const bigNum = new BigNum(100); + const other = new BigNum(100); + const result = bigNum.lessThan(other); + expect(result).toBe(false); + }); + it("should get correct lessThan with greater", () => { + const bigNum = new BigNum(100); + const other = new BigNum(90); + const result = bigNum.lessThan(other); + expect(result).toBe(false); + }); + }); + describe("compare", () => { + it("should get correct compare", () => { + const bigNum = new BigNum(100); + const other = new BigNum(110); + const result = bigNum.compare(other); + expect(result).toBe(-1); + }); + it("should get correct compare with equal", () => { + const bigNum = new BigNum(100); + const other = new BigNum(100); + const result = bigNum.compare(other); + expect(result).toBe(0); + }); + it("should get correct compare with greater", () => { + const bigNum = new BigNum(100); + const other = new BigNum(90); + const result = bigNum.compare(other); + expect(result).toBe(1); + }); + }); + describe("toString", () => { + it("should get correct toString", () => { + const bigNum = new BigNum(100); + const result = bigNum.toString(); + expect(result).toBe("100"); + }); + }); +}); diff --git a/packages/mesh-contract/package.json b/packages/mesh-contract/package.json index 135cc3d4..24d7121e 100644 --- a/packages/mesh-contract/package.json +++ b/packages/mesh-contract/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/contract", - "version": "1.6.1", + "version": "1.6.2", "description": "", "main": "./dist/index.cjs", "module": "./dist/index.js", diff --git a/packages/mesh-contract/src/common.ts b/packages/mesh-contract/src/common.ts index cb87309f..5562367f 100644 --- a/packages/mesh-contract/src/common.ts +++ b/packages/mesh-contract/src/common.ts @@ -164,20 +164,24 @@ export class MeshTxInitiator { }; protected _getUtxoByTxHash = async ( - scriptCbor: string, txHash: string, + scriptCbor?: string, ): Promise => { if (this.fetcher) { const utxos = await this.fetcher?.fetchUTxOs(txHash); - const scriptAddr = v2ScriptToBech32( - scriptCbor, - undefined, - this.networkId, - ); + let scriptUtxo = utxos[0]; - const scriptUtxo = - utxos.filter((utxo) => utxo.output.address === scriptAddr)[0] || - utxos[0]; + if (scriptCbor) { + const scriptAddr = v2ScriptToBech32( + scriptCbor, + undefined, + this.networkId, + ); + scriptUtxo = + utxos.filter((utxo) => utxo.output.address === scriptAddr)[0] || + utxos[0]; + } + return scriptUtxo; } diff --git a/packages/mesh-contract/src/escrow/offchain.ts b/packages/mesh-contract/src/escrow/offchain.ts index 892ed333..8530ef32 100644 --- a/packages/mesh-contract/src/escrow/offchain.ts +++ b/packages/mesh-contract/src/escrow/offchain.ts @@ -5,11 +5,11 @@ import { conStr1, mConStr1, mConStr2, - parsePlutusValueToAssets, PubKeyAddress, pubKeyAddress, Value, value, + MeshValue } from "@meshsdk/common"; import { Asset, @@ -113,8 +113,8 @@ export class MeshEscrowContract extends MeshTxInitiator { const initiatorAddress = serializeAddressObj(initiatorAddressObj); const recipientAddress = serializeAddressObj(recipientAddressObj!); - const initiatorToReceive = parsePlutusValueToAssets(initiatorAmount); - const recipientToReceive = parsePlutusValueToAssets(recipientAmount!); + const initiatorToReceive = MeshValue.fromValue(initiatorAmount).toAssets(); + const recipientToReceive = MeshValue.fromValue(recipientAmount!).toAssets(); this.mesh .txOut(initiatorAddress, initiatorToReceive) .txOut(recipientAddress, recipientToReceive); @@ -164,7 +164,7 @@ export class MeshEscrowContract extends MeshTxInitiator { depositAmount, ); - const inputAssets = parsePlutusValueToAssets(inputDatum.fields[1]); + const inputAssets = MeshValue.fromValue(inputDatum.fields[1]).toAssets(); const escrowAmount = mergeAssets([...depositAmount, ...inputAssets]); await this.mesh @@ -218,8 +218,8 @@ export class MeshEscrowContract extends MeshTxInitiator { ] = inputDatum.fields; const initiatorAddress = serializeAddressObj(initiatorAddressObj); const recipientAddress = serializeAddressObj(recipientAddressObj); - const initiatorToReceive = parsePlutusValueToAssets(recipientAmount); - const recipientToReceive = parsePlutusValueToAssets(initiatorAmount); + const initiatorToReceive = MeshValue.fromValue(recipientAmount).toAssets(); + const recipientToReceive = MeshValue.fromValue(initiatorAmount).toAssets(); await this.mesh .spendingPlutusScriptV2() @@ -249,6 +249,6 @@ export class MeshEscrowContract extends MeshTxInitiator { }; getUtxoByTxHash = async (txHash: string): Promise => { - return await this._getUtxoByTxHash(this.scriptCbor, txHash); + return await this._getUtxoByTxHash(txHash, this.scriptCbor); }; } diff --git a/packages/mesh-contract/src/giftcard/offchain.ts b/packages/mesh-contract/src/giftcard/offchain.ts index dae67bae..379edcf4 100644 --- a/packages/mesh-contract/src/giftcard/offchain.ts +++ b/packages/mesh-contract/src/giftcard/offchain.ts @@ -27,12 +27,17 @@ export class MeshGiftCardContract extends MeshTxInitiator { tokenNameHex: string = ""; paramUtxo: UTxO["input"] = { outputIndex: 0, txHash: "" }; - giftCardCbor = (tokenNameHex: string, utxoTxHash: string, utxoTxId: number) => - applyParamsToScript( + giftCardCbor = ( + tokenNameHex: string, + utxoTxHash: string, + utxoTxId: number, + ) => { + return applyParamsToScript( blueprint.validators[0]!.compiledCode, [builtinByteString(tokenNameHex), txOutRef(utxoTxHash, utxoTxId)], "JSON", ); + }; redeemCbor = (tokenNameHex: string, policyId: string) => applyParamsToScript(blueprint.validators[1]!.compiledCode, [ @@ -167,8 +172,7 @@ export class MeshGiftCardContract extends MeshTxInitiator { }; getUtxoByTxHash = async (txHash: string): Promise => { - const { redeemScript } = this.getScripts(); - return await this._getUtxoByTxHash(redeemScript, txHash); + return await this._getUtxoByTxHash(txHash); }; private getScripts = () => { diff --git a/packages/mesh-contract/src/hello-world/offchain.ts b/packages/mesh-contract/src/hello-world/offchain.ts index 8cbccf5f..df9048be 100644 --- a/packages/mesh-contract/src/hello-world/offchain.ts +++ b/packages/mesh-contract/src/hello-world/offchain.ts @@ -19,6 +19,6 @@ export class MeshHelloWorldContract extends MeshTxInitiator { } getUtxoByTxHash = async (txHash: string): Promise => { - return await this._getUtxoByTxHash(this.scriptCbor, txHash); + return await this._getUtxoByTxHash(txHash, this.scriptCbor); }; } diff --git a/packages/mesh-contract/src/marketplace/offchain.ts b/packages/mesh-contract/src/marketplace/offchain.ts index ab1fc487..7e943f3c 100644 --- a/packages/mesh-contract/src/marketplace/offchain.ts +++ b/packages/mesh-contract/src/marketplace/offchain.ts @@ -240,6 +240,6 @@ export class MeshMarketplaceContract extends MeshTxInitiator { }; getUtxoByTxHash = async (txHash: string): Promise => { - return await this._getUtxoByTxHash(this.scriptCbor, txHash); + return await this._getUtxoByTxHash(txHash, this.scriptCbor); }; } diff --git a/packages/mesh-contract/src/swap/offchain.ts b/packages/mesh-contract/src/swap/offchain.ts index 47c60874..40abc2b0 100644 --- a/packages/mesh-contract/src/swap/offchain.ts +++ b/packages/mesh-contract/src/swap/offchain.ts @@ -4,12 +4,12 @@ import { ConStr0, mConStr0, mConStr1, - parsePlutusValueToAssets, pubKeyAddress, PubKeyAddress, UTxO, value, Value, + MeshValue } from "@meshsdk/common"; import { deserializeAddress, @@ -89,7 +89,7 @@ export class MeshSwapContract extends MeshTxInitiator { .spendingReferenceTxInInlineDatumPresent() .spendingReferenceTxInRedeemerValue(mConStr1([])) .txInScript(this.scriptCbor) - .txOut(initiatorAddress, parsePlutusValueToAssets(initiatorToReceive)) + .txOut(initiatorAddress, MeshValue.fromValue(initiatorToReceive).toAssets()) .changeAddress(walletAddress) .txInCollateral( collateral.input.txHash, @@ -134,6 +134,6 @@ export class MeshSwapContract extends MeshTxInitiator { }; getUtxoByTxHash = async (txHash: string): Promise => { - return await this._getUtxoByTxHash(this.scriptCbor, txHash); + return await this._getUtxoByTxHash(txHash, this.scriptCbor); }; } diff --git a/packages/mesh-contract/src/vesting/offchain.ts b/packages/mesh-contract/src/vesting/offchain.ts index dea32460..c5ebe3c8 100644 --- a/packages/mesh-contract/src/vesting/offchain.ts +++ b/packages/mesh-contract/src/vesting/offchain.ts @@ -112,6 +112,6 @@ export class MeshVestingContract extends MeshTxInitiator { }; getUtxoByTxHash = async (txHash: string): Promise => { - return await this._getUtxoByTxHash(this.scriptCbor, txHash); + return await this._getUtxoByTxHash(txHash, this.scriptCbor); }; } diff --git a/packages/mesh-core-csl/package.json b/packages/mesh-core-csl/package.json index d212607d..808c36b9 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.6.1", + "version": "1.6.2", "description": "", "main": "./dist/index.cjs", "module": "./dist/index.js", @@ -20,10 +20,10 @@ "build:mesh": "tsup src/index.ts --format esm,cjs --dts", "dev": "tsup src/index.ts --format esm,cjs --watch --dts", "lint": "eslint", - "test": "jest --verbose", "clean": "rm -rf .turbo && rm -rf dist && rm -rf node_modules", "format": "prettier --check . --ignore-path ../../.gitignore", - "build:docs": "typedoc src/index.ts --json ../../apps/docs/src/data/mesh-core-csl.json" + "build:docs": "typedoc src/index.ts --json ../../apps/docs/src/data/mesh-core-csl.json", + "test": "jest" }, "browser": { "@sidan-lab/sidan-csl-rs-nodejs": "@sidan-lab/sidan-csl-rs-browser" diff --git a/packages/mesh-core-csl/src/core/serializer.ts b/packages/mesh-core-csl/src/core/serializer.ts index 97f07c59..c535498e 100644 --- a/packages/mesh-core-csl/src/core/serializer.ts +++ b/packages/mesh-core-csl/src/core/serializer.ts @@ -26,10 +26,10 @@ import { deserializePlutusScript, resolveDataHash, resolveEd25519KeyHash, - resolvePoolId, resolvePrivateKey, resolveRewardAddress, resolveScriptRef, + serializePoolId, toNativeScript, } from "../deser"; import { @@ -43,12 +43,17 @@ import { meshTxBuilderBodyToObj } from "./adaptor"; import { builderDataToCbor } from "./adaptor/data"; export class CSLSerializer implements IMeshTxSerializer { + /** + * Set to true to enable verbose logging for the txBodyJson prior going into build + */ + verbose: boolean; protocolParams: Protocol; meshTxBuilderBody: MeshTxBuilderBody = emptyTxBuilderBody(); - constructor(protocolParams?: Protocol) { + constructor(protocolParams?: Protocol, verbose = false) { this.protocolParams = protocolParams || DEFAULT_PROTOCOL_PARAMETERS; + this.verbose = verbose; } serializeTxBody( @@ -59,7 +64,9 @@ export class CSLSerializer implements IMeshTxSerializer { const params = JSONbig.stringify(protocolParams || this.protocolParams); - console.log("txBodyJson", txBodyJson); + if (this.verbose) { + console.log("txBodyJson", txBodyJson); + } const txBuildResult = csl.js_serialize_tx_body(txBodyJson, params); if (txBuildResult.get_status() !== "success") { throw new Error(txBuildResult.get_data()); @@ -85,6 +92,10 @@ export class CSLSerializer implements IMeshTxSerializer { return serialzeAddress(address, networkId); } + serializePoolId(hash: string): string { + return serializePoolId(hash); + } + deserializer: IDeserializer = { key: { deserializeAddress: function (bech32: string): DeserializedAddress { @@ -112,6 +123,11 @@ export class CSLSerializer implements IMeshTxSerializer { return { scriptHash, scriptCbor: script.code }; }, }, + cert: { + deserializePoolId: function (poolId: string): string { + return resolveEd25519KeyHash(poolId); + }, + }, }; resolver: IResolver = { @@ -147,10 +163,5 @@ export class CSLSerializer implements IMeshTxSerializer { return resolveScriptRef(script); }, }, - pool: { - resolvePoolId: function (hash: string): string { - return resolvePoolId(hash); - }, - }, }; } diff --git a/packages/mesh-core-csl/src/deser/resolver.ts b/packages/mesh-core-csl/src/deser/resolver.ts index efc11b80..6b9a6ffa 100644 --- a/packages/mesh-core-csl/src/deser/resolver.ts +++ b/packages/mesh-core-csl/src/deser/resolver.ts @@ -122,7 +122,7 @@ export const resolveNativeScriptHex = (script: NativeScript) => { return toNativeScript(script).to_hex(); }; -export const resolvePoolId = (hash: string) => { +export const serializePoolId = (hash: string) => { return csl.Ed25519KeyHash.from_hex(hash).to_bech32("pool1"); }; diff --git a/packages/mesh-core-csl/test/core/builder.test.ts b/packages/mesh-core-csl/test/core/builder.test.ts index 7c02467a..ed1836ca 100644 --- a/packages/mesh-core-csl/test/core/builder.test.ts +++ b/packages/mesh-core-csl/test/core/builder.test.ts @@ -3,8 +3,7 @@ import { DEFAULT_PROTOCOL_PARAMETERS, MeshTxBuilderBody, } from "@meshsdk/common"; - -import { CSLSerializer } from "../../src"; +import { CSLSerializer } from "@meshsdk/core-csl"; describe("Builder", () => { test("serializeTxBody - send lovelace", () => { diff --git a/packages/mesh-core-csl/test/utils/address.test.ts b/packages/mesh-core-csl/test/utils/address.test.ts index fb02f4c5..74c8f6db 100644 --- a/packages/mesh-core-csl/test/utils/address.test.ts +++ b/packages/mesh-core-csl/test/utils/address.test.ts @@ -1,10 +1,9 @@ import { pubKeyAddress, scriptAddress } from "@meshsdk/common"; - import { deserializeBech32Address, scriptHashToBech32, serializeAddressObj, -} from "../../src"; +} from "@meshsdk/core-csl"; describe("Address", () => { test("deserializeBech32Address", () => { diff --git a/packages/mesh-core-csl/test/utils/aiken.test.ts b/packages/mesh-core-csl/test/utils/aiken.test.ts index a77a39cf..24e89920 100644 --- a/packages/mesh-core-csl/test/utils/aiken.test.ts +++ b/packages/mesh-core-csl/test/utils/aiken.test.ts @@ -1,6 +1,8 @@ import { builtinByteString } from "@meshsdk/common"; - -import { applyParamsToScript, deserializeBech32Address } from "../../src"; +import { + applyParamsToScript, + deserializeBech32Address, +} from "@meshsdk/core-csl"; describe("Aiken", () => { test("applyParamsToScript 1", () => { diff --git a/packages/mesh-core-csl/test/utils/scripts.test.ts b/packages/mesh-core-csl/test/utils/scripts.test.ts index fe26894a..7204d523 100644 --- a/packages/mesh-core-csl/test/utils/scripts.test.ts +++ b/packages/mesh-core-csl/test/utils/scripts.test.ts @@ -1,4 +1,4 @@ -import { applyParamsToScript, getV2ScriptHash } from "../../src"; +import { applyParamsToScript, getV2ScriptHash } from "@meshsdk/core-csl"; describe("Scripts", () => { test("getV2ScriptHash", () => { diff --git a/packages/mesh-core-csl/test/utils/transaction.test.ts b/packages/mesh-core-csl/test/utils/transaction.test.ts index a377425d..f121b41b 100644 --- a/packages/mesh-core-csl/test/utils/transaction.test.ts +++ b/packages/mesh-core-csl/test/utils/transaction.test.ts @@ -1,4 +1,4 @@ -import { calculateTxHash } from "../../src"; +import { calculateTxHash } from "@meshsdk/core-csl"; describe("Transaction", () => { test("calculateTxHash", () => { diff --git a/packages/mesh-core-cst/package.json b/packages/mesh-core-cst/package.json index 3f816be1..ef2b784f 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.6.1", + "version": "1.6.2", "description": "", "main": "./dist/index.cjs", "module": "./dist/index.js", @@ -20,7 +20,7 @@ "build:mesh": "tsup src/index.ts --format esm,cjs --dts --minify", "dev": "tsup src/index.ts --format esm,cjs --watch --dts", "lint": "eslint", - "test": "jest --verbose", + "test": "jest", "clean": "rm -rf .turbo && rm -rf dist && rm -rf node_modules", "format": "prettier --check . --ignore-path ../../.gitignore" }, diff --git a/packages/mesh-core-cst/src/resolvers/index.ts b/packages/mesh-core-cst/src/resolvers/index.ts index 930970d1..a5fb4a05 100644 --- a/packages/mesh-core-cst/src/resolvers/index.ts +++ b/packages/mesh-core-cst/src/resolvers/index.ts @@ -93,7 +93,6 @@ export const resolvePoolId = (hash: string) => { }; export const resolvePrivateKey = (words: string[]) => { - console.log(words); return "not implemented"; }; diff --git a/packages/mesh-core-cst/src/serializer/index.ts b/packages/mesh-core-cst/src/serializer/index.ts index 3c85deaa..8536ee46 100644 --- a/packages/mesh-core-cst/src/serializer/index.ts +++ b/packages/mesh-core-cst/src/serializer/index.ts @@ -96,6 +96,9 @@ export class CardanoSDKSerializer implements IMeshTxSerializer { ); this.txWitnessSet = new TransactionWitnessSet(); } + serializePoolId(hash: string): string { + throw new Error("Method not implemented."); + } serializeAddress(address: DeserializedAddress, networkId?: 0 | 1): string { throw new Error("Method not implemented."); @@ -130,6 +133,11 @@ export class CardanoSDKSerializer implements IMeshTxSerializer { throw new Error("Function not implemented."); }, }, + cert: { + deserializePoolId: function (poolId: string): string { + throw new Error("Function not implemented."); + }, + }, }; resolver: IResolver = { @@ -192,11 +200,6 @@ export class CardanoSDKSerializer implements IMeshTxSerializer { throw new Error("Function not implemented."); }, }, - pool: { - resolvePoolId: function (hash: string): string { - throw new Error("Function not implemented."); - }, - }, }; serializeTxBody = ( @@ -647,21 +650,27 @@ export class CardanoSDKSerializer implements IMeshTxSerializer { case "V1": this.scriptsProvided.add( Script.newPlutusV1Script( - PlutusV1Script.fromCbor(HexBlob(plutusScriptSource.script.code)), + PlutusV1Script.fromCbor( + HexBlob(plutusScriptSource.script.code), + ), ), ); break; case "V2": this.scriptsProvided.add( Script.newPlutusV2Script( - PlutusV2Script.fromCbor(HexBlob(plutusScriptSource.script.code)), + PlutusV2Script.fromCbor( + HexBlob(plutusScriptSource.script.code), + ), ), ); break; case "V3": this.scriptsProvided.add( Script.newPlutusV3Script( - PlutusV3Script.fromCbor(HexBlob(plutusScriptSource.script.code)), + PlutusV3Script.fromCbor( + HexBlob(plutusScriptSource.script.code), + ), ), ); break; diff --git a/packages/mesh-core-cst/src/stricahq/index.ts b/packages/mesh-core-cst/src/stricahq/index.ts index b9910e05..7d5a7cb7 100644 --- a/packages/mesh-core-cst/src/stricahq/index.ts +++ b/packages/mesh-core-cst/src/stricahq/index.ts @@ -1,17 +1,4 @@ -import strica from "@stricahq/bip32ed25519"; // This works with broswer, but not node - -// import * as strica from "@stricahq/bip32ed25519"; // This works with node, but not browser - -// let strica: any; - -// if (typeof window !== "undefined") { -// // Browser environment -// strica = await import("@stricahq/bip32ed25519"); -// } else { -// // Node.js environment -// strica = require("@stricahq/bip32ed25519"); -// } - +import strica from "@stricahq/bip32ed25519"; import hash from "hash.js"; class PrivateKey extends strica.PrivateKey { diff --git a/packages/mesh-core-cst/test/resolvers.test.ts b/packages/mesh-core-cst/test/resolvers.test.ts index 94ab149b..115aef10 100644 --- a/packages/mesh-core-cst/test/resolvers.test.ts +++ b/packages/mesh-core-cst/test/resolvers.test.ts @@ -3,7 +3,6 @@ import { PlutusScript, resolveFingerprint, } from "@meshsdk/common"; - import { resolveDataHash, resolveNativeScriptAddress, @@ -11,10 +10,9 @@ import { resolvePaymentKeyHash, resolvePlutusScriptAddress, resolvePlutusScriptHash, - resolvePrivateKey, resolveRewardAddress, resolveStakeKeyHash, -} from "../src"; +} from "@meshsdk/core-cst"; describe("resolveDataHash", () => { it("should return correct data", () => { diff --git a/packages/mesh-core-cst/test/utils/converter.test.ts b/packages/mesh-core-cst/test/utils/converter.test.ts index bb57e248..076e83f4 100644 --- a/packages/mesh-core-cst/test/utils/converter.test.ts +++ b/packages/mesh-core-cst/test/utils/converter.test.ts @@ -1,6 +1,5 @@ import { PlutusScript } from "@meshsdk/common"; - -import { fromScriptRef } from "../../src/utils/converter"; +import { fromScriptRef } from "@meshsdk/core-cst"; describe("fromScriptRef", () => { // it("with native script cbor should return correct NativeScript", () => {}); diff --git a/packages/mesh-core/package.json b/packages/mesh-core/package.json index 2d4603e0..e2618ec0 100644 --- a/packages/mesh-core/package.json +++ b/packages/mesh-core/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/core", - "version": "1.6.1", + "version": "1.6.2", "description": "", "main": "./dist/index.cjs", "module": "./dist/index.js", diff --git a/packages/mesh-core/src/utils/deserializer.ts b/packages/mesh-core/src/utils/deserializer.ts index 9c6e0e18..db4db004 100644 --- a/packages/mesh-core/src/utils/deserializer.ts +++ b/packages/mesh-core/src/utils/deserializer.ts @@ -21,3 +21,11 @@ export const deserializeAddress = (bech32: string): DeserializedAddress => */ export const deserializeDatum = (datumCbor: string): T => core.parseDatumCbor(datumCbor); + +/** + * Deserialize a script from a poolxxxx to Ed25519 key hash + * @param poolId The poolxxxx bech32 pool id + * @returns The Ed25519 key hash + */ +export const deserializePoolId = (poolId: string): string => + core.resolveEd25519KeyHash(poolId); diff --git a/packages/mesh-core/src/utils/resolver.ts b/packages/mesh-core/src/utils/resolver.ts index 7434c787..03b589b1 100644 --- a/packages/mesh-core/src/utils/resolver.ts +++ b/packages/mesh-core/src/utils/resolver.ts @@ -56,13 +56,6 @@ export const resolveScriptHash = ( return core.deserializePlutusScript(scriptCode, version).hash().to_hex(); }; -/** - * Resolve the pool id from hash - * @param hash The pool hash - * @returns The pool id - */ -export const resolvePoolId = (hash: string) => core.resolvePoolId(hash); - /** * Resolve the Ed25519 key hash from bech32 address * @param bech32 The bech32 address @@ -71,6 +64,14 @@ export const resolvePoolId = (hash: string) => core.resolvePoolId(hash); export const resolveRewardAddress = (bech32: string) => core.resolveRewardAddress(bech32); +/** + * Resolve the stake key hash from bech32 address + * @param bech32 The bech32 address, either in addrxxx or stakexxx + * @returns The stake key hash + */ +export const resolveStakeKeyHash = (bech32: string) => + core.resolveStakeKeyHash(bech32); + // ------------------- Deprecated zone --------------------- /** @@ -107,12 +108,6 @@ export const resolvePaymentKeyHash = (bech32: string) => export const resolvePlutusScriptHash = (bech32: string) => core.deserializeBech32Address(bech32).scriptHash; -/** - * Deprecated - use `deserializeAddress` instead - */ -export const resolveStakeKeyHash = (bech32: string) => - core.deserializeBech32Address(bech32).stakeCredentialHash; - /** * Deprecated - this is more used with the low level process inside Mesh * @@ -120,3 +115,8 @@ export const resolveStakeKeyHash = (bech32: string) => */ export const resolveScriptRef = (script: NativeScript | PlutusScript) => core.resolveScriptRef(script); + +/** + * Deprecated - use `serializePoolId` instead + */ +export const resolvePoolId = (hash: string) => core.serializePoolId(hash); diff --git a/packages/mesh-core/src/utils/serializer.ts b/packages/mesh-core/src/utils/serializer.ts index 6dcd6da1..7cc2ba06 100644 --- a/packages/mesh-core/src/utils/serializer.ts +++ b/packages/mesh-core/src/utils/serializer.ts @@ -68,3 +68,10 @@ export const serializePlutusScript = ( export const serializeAddressObj = (address: PubKeyAddress | ScriptAddress) => { return core.serializeAddressObj(address); }; + +/** + * Resolve the pool id from hash + * @param hash The pool hash + * @returns The pool id + */ +export const serializePoolId = (hash: string) => core.serializePoolId(hash); diff --git a/.env.example b/packages/mesh-provider/.env.example similarity index 100% rename from .env.example rename to packages/mesh-provider/.env.example diff --git a/packages/mesh-provider/package.json b/packages/mesh-provider/package.json index e244c407..4449ea87 100644 --- a/packages/mesh-provider/package.json +++ b/packages/mesh-provider/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/provider", - "version": "1.6.1", + "version": "1.6.2", "description": "", "main": "./dist/index.cjs", "module": "./dist/index.js", @@ -21,7 +21,7 @@ "dev": "tsup src/index.ts --format esm,cjs --watch --dts", "lint": "eslint", "clean": "rm -rf .turbo && rm -rf dist && rm -rf node_modules", - "test": "jest --verbose", + "test": "jest", "format": "prettier --check . --ignore-path ../../.gitignore", "build:docs": "typedoc src/index.ts --json ../../apps/docs/src/data/mesh-providers.json" }, diff --git a/packages/mesh-provider/src/blockfrost.ts b/packages/mesh-provider/src/blockfrost.ts index 2444f143..8f8a3af9 100644 --- a/packages/mesh-provider/src/blockfrost.ts +++ b/packages/mesh-provider/src/blockfrost.ts @@ -99,7 +99,7 @@ export class BlockfrostProvider implements IFetcher, IListener, ISubmitter { throw parseHttpError(data); } catch (error) { - console.log("error", error); + console.error("error", error); throw parseHttpError(error); } } @@ -196,7 +196,6 @@ export class BlockfrostProvider implements IFetcher, IListener, ISubmitter { const { data, status } = await this._axiosInstance.get( `assets/${policyId}${assetName}`, ); - console.log(3, data) if (status === 200 || status == 202) return { ...data.onchain_metadata, diff --git a/packages/mesh-provider/src/koios.ts b/packages/mesh-provider/src/koios.ts index 1354c151..1e3cb847 100644 --- a/packages/mesh-provider/src/koios.ts +++ b/packages/mesh-provider/src/koios.ts @@ -325,8 +325,6 @@ export class KoiosProvider implements IFetcher, IListener, ISubmitter { _tx_hashes: [hash], }); - console.log(88, data); - if (status === 200) { const utxos = data[0].outputs.map((utxo: KoiosUTxO) => this.toUTxO(utxo, "undefined"), diff --git a/packages/mesh-provider/src/maestro.ts b/packages/mesh-provider/src/maestro.ts index 995dcd24..f1f4d1bd 100644 --- a/packages/mesh-provider/src/maestro.ts +++ b/packages/mesh-provider/src/maestro.ts @@ -200,8 +200,6 @@ export class MaestroProvider const { data: timestampedData, status } = await this._axiosInstance.get( `assets/${policyId}${assetName}`, ); - - console.log(2, timestampedData) if (status === 200) { const data = timestampedData.data; return { diff --git a/packages/mesh-provider/src/ogmios.ts b/packages/mesh-provider/src/ogmios.ts index 9705255c..502988bf 100644 --- a/packages/mesh-provider/src/ogmios.ts +++ b/packages/mesh-provider/src/ogmios.ts @@ -32,8 +32,6 @@ export class OgmiosProvider implements IEvaluator, ISubmitter { (response: MessageEvent) => { try { const { result } = JSON.parse(response.data); - console.log(1, 'result', result) - if (result.EvaluationResult) { resolve( Object.keys(result.EvaluationResult).map((key) => { diff --git a/packages/mesh-provider/src/yaci.ts b/packages/mesh-provider/src/yaci.ts index 8f6f581a..4cfd8e4d 100644 --- a/packages/mesh-provider/src/yaci.ts +++ b/packages/mesh-provider/src/yaci.ts @@ -380,7 +380,7 @@ export class YaciProvider implements IFetcher, IListener, ISubmitter { throw parseHttpError(data); } catch (error) { - console.log("error", error); + console.error("error", error); throw parseHttpError(error); } } @@ -402,7 +402,7 @@ export class YaciProvider implements IFetcher, IListener, ISubmitter { throw parseHttpError(data); } catch (error) { - console.log("error", error); + console.error("error", error); throw parseHttpError(error); } } diff --git a/packages/mesh-provider/test/blockfrost/evaluator.test.ts b/packages/mesh-provider/test/blockfrost/evaluator.test.ts index 2a9f6893..3322eb8f 100644 --- a/packages/mesh-provider/test/blockfrost/evaluator.test.ts +++ b/packages/mesh-provider/test/blockfrost/evaluator.test.ts @@ -1,6 +1,6 @@ import dotenv from "dotenv"; -import { BlockfrostProvider } from "../../src"; +import { BlockfrostProvider } from "@meshsdk/provider"; dotenv.config(); const apiKey = process.env.BLOCKFROST_API_KEY_PREPROD!; diff --git a/packages/mesh-provider/test/maestro/evaluator.test.ts b/packages/mesh-provider/test/maestro/evaluator.test.ts index d3cba2a1..7a92933a 100644 --- a/packages/mesh-provider/test/maestro/evaluator.test.ts +++ b/packages/mesh-provider/test/maestro/evaluator.test.ts @@ -1,6 +1,6 @@ import dotenv from "dotenv"; -import { MaestroProvider } from "../../src/maestro"; +import { MaestroProvider } from "@meshsdk/provider"; dotenv.config(); const apiKey = process.env.MAESTRO_API_KEY!; diff --git a/packages/mesh-react/package.json b/packages/mesh-react/package.json index ae04c77d..ef7fb748 100644 --- a/packages/mesh-react/package.json +++ b/packages/mesh-react/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/react", - "version": "1.6.1", + "version": "1.6.2", "description": "", "main": "./dist/index.cjs", "module": "./dist/index.js", diff --git a/packages/mesh-react/src/cardano-wallet/index.tsx b/packages/mesh-react/src/cardano-wallet/index.tsx index 0e925ce9..b69c3d8f 100644 --- a/packages/mesh-react/src/cardano-wallet/index.tsx +++ b/packages/mesh-react/src/cardano-wallet/index.tsx @@ -1,10 +1,7 @@ import { useEffect, useState } from "react"; -import { Wallet } from "@meshsdk/common"; -import { BrowserWallet } from "@meshsdk/wallet"; - import Button from "../common/button"; -import { useWallet } from "../hooks"; +import { useWallet, useWalletList } from "../hooks"; import { MenuItem } from "./menu-item"; import { WalletBalance } from "./wallet-balance"; @@ -12,18 +9,20 @@ interface ButtonProps { label?: string; onConnected?: Function; isDark?: boolean; + nufiNetwork?: string; } export const CardanoWallet = ({ label = "Connect Wallet", onConnected = undefined, isDark = false, + nufiNetwork = "preprod", }: ButtonProps) => { const [isDarkMode, setIsDarkMode] = useState(false); const [hideMenuList, setHideMenuList] = useState(true); - const [wallets, setWallets] = useState([]); const { connect, connecting, connected, disconnect, name } = useWallet(); + const wallets = useWalletList({ nufiNetwork }); useEffect(() => { if (connected && onConnected) { @@ -31,19 +30,15 @@ export const CardanoWallet = ({ } }, [connected]); - useEffect(() => { - setWallets(BrowserWallet.getInstalledWallets()); - }, []); - useEffect(() => { setIsDarkMode(isDark); }, [isDark]); return (

setHideMenuList(false)} onMouseLeave={() => setHideMenuList(true)} + style={{ width: "min-content", zIndex: 50 }} >
{ - connect(wallet.name); + connect(wallet.id); setHideMenuList(!hideMenuList); }} - active={name === wallet.name} + active={name === wallet.id} /> ))} {/* void; + onMouseEnter?: () => void; + onMouseLeave?: () => void; }) { return ( diff --git a/packages/mesh-react/src/hooks/useWalletList.ts b/packages/mesh-react/src/hooks/useWalletList.ts index 480f01e8..246707bd 100644 --- a/packages/mesh-react/src/hooks/useWalletList.ts +++ b/packages/mesh-react/src/hooks/useWalletList.ts @@ -3,11 +3,18 @@ import { useEffect, useState } from "react"; import type { Wallet } from "@meshsdk/common"; import { BrowserWallet } from "@meshsdk/wallet"; -export const useWalletList = () => { +export const useWalletList = ({ + nufiNetwork = "preprod", +}: { + nufiNetwork?: string; +} = {}) => { const [wallets, setWallets] = useState([]); useEffect(() => { - setWallets(BrowserWallet.getInstalledWallets()); + async function get() { + setWallets(await BrowserWallet.getAvailableWallets({ nufiNetwork })); + } + get(); }, []); return wallets; diff --git a/packages/mesh-transaction/package.json b/packages/mesh-transaction/package.json index a3fe0f6a..55201c07 100644 --- a/packages/mesh-transaction/package.json +++ b/packages/mesh-transaction/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/transaction", - "version": "1.6.1", + "version": "1.6.2", "description": "", "main": "./dist/index.cjs", "module": "./dist/index.js", diff --git a/packages/mesh-transaction/src/mesh-tx-builder/index.ts b/packages/mesh-transaction/src/mesh-tx-builder/index.ts index 547e774f..42d17e3a 100644 --- a/packages/mesh-transaction/src/mesh-tx-builder/index.ts +++ b/packages/mesh-transaction/src/mesh-tx-builder/index.ts @@ -105,7 +105,6 @@ export class MeshTxBuilder extends MeshTxBuilderCore { this._protocolParams, ); } - console.log(txHex); this.txHex = txHex; return txHex; diff --git a/packages/mesh-transaction/src/transaction/index.ts b/packages/mesh-transaction/src/transaction/index.ts index 0113311c..29c2d872 100644 --- a/packages/mesh-transaction/src/transaction/index.ts +++ b/packages/mesh-transaction/src/transaction/index.ts @@ -1,32 +1,34 @@ import { Action, Asset, + AssetMetadata, Budget, CIP68_100, CIP68_222, - DEFAULT_REDEEMER_BUDGET, Data, + DEFAULT_REDEEMER_BUDGET, + hexToString, IInitiator, + metadataToCip68, Mint, NativeScript, - POLICY_ID_LENGTH, PlutusScript, + POLICY_ID_LENGTH, PoolParams, Recipient, + stringToHex, SUPPORTED_TOKENS, Token, UTxO, - hexToString, - metadataToCip68, - stringToHex, } from "@meshsdk/common"; -import { MeshTxBuilder, MeshTxBuilderOptions } from "../mesh-tx-builder"; import { deserializeNativeScript, deserializePlutusScript, fromScriptRef, } from "@meshsdk/core-cst"; +import { MeshTxBuilder, MeshTxBuilderOptions } from "../mesh-tx-builder"; + export interface TransactionOptions extends MeshTxBuilderOptions { initiator: IInitiator; } @@ -145,7 +147,7 @@ export class Transaction { input.input.txHash, input.input.outputIndex, input.output.amount, - input.output.address + input.output.address, ); }); @@ -162,7 +164,7 @@ export class Transaction { inputs.forEach((input) => { this.txBuilder.readOnlyTxInReference( input.input.txHash, - input.input.outputIndex + input.input.outputIndex, ); }); @@ -178,14 +180,14 @@ export class Transaction { setNativeScriptInput(script: NativeScript, utxo: UTxO): Transaction { const { scriptCbor } = this.txBuilder.serializer.deserializer.script.deserializeNativeScript( - script + script, ); this.txBuilder .txIn( utxo.input.txHash, utxo.input.outputIndex, utxo.output.amount, - utxo.output.address + utxo.output.address, ) .txInScript(scriptCbor!); @@ -213,7 +215,7 @@ export class Transaction { value.input.txHash, value.input.outputIndex, value.output.amount, - value.output.address + value.output.address, ) .txInScript(script.code) .txInRedeemerValue(red.data, "Mesh", red.budget); @@ -235,12 +237,12 @@ export class Transaction { value.input.txHash, value.input.outputIndex, value.output.amount, - value.output.address + value.output.address, ) .spendingTxInReference( script.input.txHash, script.input.outputIndex, - script.output.scriptHash + script.output.scriptHash, ) .txInRedeemerValue(red.data, "Mesh", red.budget); } @@ -267,7 +269,7 @@ export class Transaction { mintAsset( forgeScript: string | PlutusScript | UTxO, mint: Mint, - redeemer?: Pick & { budget?: Budget } + redeemer?: Pick & { budget?: Budget }, ): Transaction { const assetQuantity = mint.assetQuantity; let assetNameHex = stringToHex(mint.assetName); @@ -293,13 +295,13 @@ export class Transaction { case "object": if (!redeemer) throw new Error( - "burnAsset: Redeemer data is required for Plutus minting" + "burnAsset: Redeemer data is required for Plutus minting", ); if ("code" in forgeScript) { // Burn plutus script assets with provided script policyId = deserializePlutusScript( forgeScript.code, - forgeScript.version + forgeScript.version, ) .hash() .toString(); @@ -337,7 +339,7 @@ export class Transaction { .mint(assetQuantity, policyId, assetNameHex) .mintTxInReference( forgeScript.input.txHash, - forgeScript.input.outputIndex + forgeScript.input.outputIndex, ) .mintRedeemerValue(redeemer.data, "Mesh", redeemer.budget); if (mint.cip68ScriptAddress) { @@ -345,7 +347,7 @@ export class Transaction { .mint(assetQuantity, policyId, referenceAssetNameHex) .mintTxInReference( forgeScript.input.txHash, - forgeScript.input.outputIndex + forgeScript.input.outputIndex, ) .mintRedeemerValue(redeemer.data, "Mesh", redeemer.budget); break; @@ -355,7 +357,7 @@ export class Transaction { } else { // TODO: to implement reference script minting for native script tokens throw new Error( - "mintAsset: Reference script minting not implemented" + "mintAsset: Reference script minting not implemented", ); // this.txBuilder // .mint(assetQuantity, policyId, assetName) @@ -368,14 +370,6 @@ export class Transaction { break; } - if (mint.metadata && mint.label) { - this.setMetadata(Number(mint.label), { - [policyId]: { - [mint.assetName]: mint.metadata, - }, - version: 1, - }); - } if (mint.recipient) { this.sendAssets(mint.recipient, [ { unit: policyId + assetNameHex, quantity: mint.assetQuantity }, @@ -392,9 +386,17 @@ export class Transaction { unit: policyId + referenceAssetNameHex, quantity: mint.assetQuantity, }, - ] + ], ); } + if (!mint.cip68ScriptAddress && mint.metadata && mint.label) { + if (mint.label === "721" || mint.label === "20") { + this.setMetadata(Number(mint.label), { + [policyId]: { [mint.assetName]: mint.metadata }, + }); + } + this.setMetadata(Number(mint.label), mint.metadata); + } return this; } @@ -404,7 +406,7 @@ export class Transaction { burnAsset( forgeScript: string | PlutusScript | UTxO, asset: Asset, - redeemer?: Pick & { budget?: Budget } + redeemer?: Pick & { budget?: Budget }, ): Transaction { const assetQuantity = "-" + asset.quantity; const mint: Mint = { @@ -443,7 +445,7 @@ export class Transaction { collateralUtxo.input.txHash, collateralUtxo.input.outputIndex, collateralUtxo.output.amount, - collateralUtxo.output.address + collateralUtxo.output.address, ); }); @@ -511,23 +513,27 @@ export class Transaction { delegateStake(rewardAddress: string, poolId: string): Transaction { this.txBuilder.delegateStakeCertificate( this.txBuilder.serializer.resolver.keys.resolveStakeKeyHash( - rewardAddress + rewardAddress, ), - this.txBuilder.serializer.resolver.keys.resolveEd25519KeyHash(poolId) + this.txBuilder.serializer.resolver.keys.resolveEd25519KeyHash(poolId), ); return this; } deregisterStake(rewardAddress: string): Transaction { this.txBuilder.deregisterStakeCertificate( - this.txBuilder.serializer.resolver.keys.resolveStakeKeyHash(rewardAddress) + this.txBuilder.serializer.resolver.keys.resolveStakeKeyHash( + rewardAddress, + ), ); return this; } registerStake(rewardAddress: string): Transaction { this.txBuilder.registerStakeCertificate( - this.txBuilder.serializer.resolver.keys.resolveStakeKeyHash(rewardAddress) + this.txBuilder.serializer.resolver.keys.resolveStakeKeyHash( + rewardAddress, + ), ); return this; } @@ -553,7 +559,7 @@ export class Transaction { return this.txBuilder.complete(); } catch (error) { throw new Error( - `[Transaction] An error occurred during build: ${error}.` + `[Transaction] An error occurred during build: ${error}.`, ); } } diff --git a/packages/mesh-wallet/package.json b/packages/mesh-wallet/package.json index d2a45f08..3c0403b8 100644 --- a/packages/mesh-wallet/package.json +++ b/packages/mesh-wallet/package.json @@ -1,6 +1,6 @@ { "name": "@meshsdk/wallet", - "version": "1.6.1", + "version": "1.6.2", "description": "", "main": "./dist/index.cjs", "module": "./dist/index.js", @@ -21,7 +21,7 @@ "dev": "tsup src/index.ts --format esm,cjs --watch --dts", "lint": "eslint", "clean": "rm -rf .turbo && rm -rf dist && rm -rf node_modules", - "test": "jest --verbose", + "test": "jest", "format": "prettier --check . --ignore-path ../../.gitignore", "build:docs": "typedoc src/index.ts --json ../../apps/docs/src/data/mesh-wallets.json" }, @@ -29,13 +29,15 @@ "@meshsdk/typescript-config": "*", "eslint": "^8.57.0", "tsup": "^8.0.2", - "typescript": "^5.3.3", - "typedoc": "^0.26.3" + "typedoc": "^0.26.3", + "typescript": "^5.3.3" }, "dependencies": { "@meshsdk/common": "*", "@meshsdk/core-cst": "*", - "@meshsdk/transaction": "*" + "@meshsdk/transaction": "*", + "@nufi/dapp-client-cardano": "^0.3.1", + "@nufi/dapp-client-core": "^0.3.1" }, "prettier": "@meshsdk/prettier-config", "publishConfig": { @@ -49,4 +51,4 @@ "blockchain", "sdk" ] -} \ No newline at end of file +} diff --git a/packages/mesh-wallet/src/browser/index.ts b/packages/mesh-wallet/src/browser/index.ts index 95341f58..a0fc9f10 100644 --- a/packages/mesh-wallet/src/browser/index.ts +++ b/packages/mesh-wallet/src/browser/index.ts @@ -30,6 +30,7 @@ import { } from "@meshsdk/core-cst"; import { Cardano, WalletInstance } from "../types"; +import { checkIfMetamaskInstalled } from "./metamask"; declare global { interface Window { @@ -69,7 +70,7 @@ export class BrowserWallet implements IInitiator, ISigner, ISubmitter { if (_wallet.apiVersion === undefined) continue; wallets.push({ id: key, - name: _wallet.name, + name: key == "nufiSnap" ? "MetaMask" : _wallet.name, icon: _wallet.icon, version: _wallet.apiVersion, }); @@ -79,6 +80,25 @@ export class BrowserWallet implements IInitiator, ISigner, ISubmitter { return wallets; } + /** + * Returns a list of wallets installed on user's device. Each wallet is an object with the following properties: + * - A name is provided to display wallet's name on the user interface. + * - A version is provided to display wallet's version on the user interface. + * - An icon is provided to display wallet's icon on the user interface. + * + * @returns a list of wallet names + */ + static async getAvailableWallets({ + nufiNetwork = "preprod", + }: { + nufiNetwork?: string; + } = {}): Promise { + if (window === undefined) return []; + await checkIfMetamaskInstalled(nufiNetwork); + const wallets = BrowserWallet.getInstalledWallets(); + return wallets; + } + /** * This is the entrypoint to start communication with the user's wallet. The wallet should request the user's permission to connect the web page to the user's wallet, and if permission has been granted, the wallet will be returned and exposing the full API for the dApp to use. * @@ -237,7 +257,6 @@ export class BrowserWallet implements IInitiator, ISigner, ISubmitter { */ async signTx(unsignedTx: string, partialSign = false): Promise { const witness = await this._walletInstance.signTx(unsignedTx, partialSign); - console.log("witness", witness); return BrowserWallet.addBrowserWitnesses(unsignedTx, witness); } diff --git a/packages/mesh-wallet/src/browser/metamask.ts b/packages/mesh-wallet/src/browser/metamask.ts new file mode 100644 index 00000000..58af1f56 --- /dev/null +++ b/packages/mesh-wallet/src/browser/metamask.ts @@ -0,0 +1,46 @@ +import { initNufiDappCardanoSdk } from "@nufi/dapp-client-cardano"; +import nufiCoreSdk from "@nufi/dapp-client-core"; + +import { Wallet } from "@meshsdk/common"; + +const nufiDomain: { [key: string]: string } = { + production: "https://wallet.nu.fi", + mainnet: "https://wallet-staging.nu.fi", + preprod: "https://wallet-testnet-staging.nu.fi", + preview: "https://wallet-preview-staging.nu.fi", +}; + +export function checkIfMetamaskInstalled( + network = "preprod", +): Promise { + try { + const _nufiCoreSdk = (nufiCoreSdk as any).default; + + if (Object.keys(nufiDomain).includes(network)) { + _nufiCoreSdk.init(nufiDomain[network]); + } else { + _nufiCoreSdk.init(network); + } + + return new Promise((resolve) => { + _nufiCoreSdk + .getApi() + .isMetamaskInstalled() + .then((isMetamaskInstalled: boolean) => { + if (isMetamaskInstalled) { + initNufiDappCardanoSdk(_nufiCoreSdk, "snap"); + resolve({ + id: "nufiSnap", + name: "MetaMask", + icon: "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0iTGF5ZXJfMiIgZGF0YS1uYW1lPSJMYXllciAyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNjkuMiAxNjMuNzEiPgogIDxkZWZzPgogICAgPHN0eWxlPgogICAgICAuY2xzLTEgewogICAgICAgIGZpbGw6ICNlMjc2MjU7CiAgICAgIH0KCiAgICAgIC5jbHMtMSwgLmNscy0yLCAuY2xzLTMsIC5jbHMtNCwgLmNscy01LCAuY2xzLTYsIC5jbHMtNywgLmNscy04LCAuY2xzLTkgewogICAgICAgIHN0cm9rZS13aWR0aDogMHB4OwogICAgICB9CgogICAgICAuY2xzLTIgewogICAgICAgIGZpbGw6ICM3NjNlMWE7CiAgICAgIH0KCiAgICAgIC5jbHMtMyB7CiAgICAgICAgZmlsbDogI2MwYWQ5ZTsKICAgICAgfQoKICAgICAgLmNscy00IHsKICAgICAgICBmaWxsOiAjMzQ2OGQxOwogICAgICB9CgogICAgICAuY2xzLTUgewogICAgICAgIGZpbGw6ICNjYzYyMjg7CiAgICAgIH0KCiAgICAgIC5jbHMtNiB7CiAgICAgICAgZmlsbDogI2Y1ODQxZjsKICAgICAgfQoKICAgICAgLmNscy03IHsKICAgICAgICBmaWxsOiAjZDdjMWIzOwogICAgICB9CgogICAgICAuY2xzLTggewogICAgICAgIGZpbGw6ICNmZmY7CiAgICAgICAgZmlsbC1ydWxlOiBldmVub2RkOwogICAgICB9CgogICAgICAuY2xzLTkgewogICAgICAgIGZpbGw6ICMyZjM0M2I7CiAgICAgIH0KICAgIDwvc3R5bGU+CiAgPC9kZWZzPgogIDxnIGlkPSJMYXllcl8xLTIiIGRhdGEtbmFtZT0iTGF5ZXIgMSI+CiAgICA8ZyBpZD0iTU1fSGVhZF9iYWNrZ3JvdW5kX0RvX25vdF9lZGl0XyIgZGF0YS1uYW1lPSJNTSBIZWFkIGJhY2tncm91bmQgKERvIG5vdCBlZGl0KSI+CiAgICAgIDxwYXRoIGNsYXNzPSJjbHMtNiIgZD0iTTE0MS44LDcwLjVsNi45LTguMS0zLTIuMiw0LjgtNC40LTMuNy0yLjgsNC44LTMuNi0zLjEtMi40LDUtMjQuNC03LjYtMjIuNk0xNDUuOSwwbC00OC44LDE4LjFoLTQwLjdMNy42LDBsLjMuMkw3LjYsMCwwLDIyLjZsNS4xLDI0LjQtMy4yLDIuNCw0LjksMy42LTMuNywyLjgsNC44LDQuNC0zLDIuMiw2LjksOC4xTDEuMywxMDIuOWgwbDkuNywzMy4xLDM0LjEtOS40di0uMS4xaDBsNi42LDUuNCwxMy41LDkuMmgyMy4xbDEzLjUtOS4yLDYuNi01LjRoMGwzNC4yLDkuNCw5LjgtMzMuMWgwbC0xMC42LTMyLjQiLz4KICAgIDwvZz4KICAgIDxnIGlkPSJMb2dvcyI+CiAgICAgIDxnPgogICAgICAgIDxwb2x5Z29uIGNsYXNzPSJjbHMtMSIgcG9pbnRzPSIxNDUuOSAwIDg2IDQ0LjEgOTcuMSAxOC4xIDE0NS45IDAiLz4KICAgICAgICA8cG9seWdvbiBjbGFzcz0iY2xzLTEiIHBvaW50cz0iNy42IDAgNjcgNDQuNSA1Ni40IDE4LjEgNy42IDAiLz4KICAgICAgICA8cG9seWdvbiBjbGFzcz0iY2xzLTEiIHBvaW50cz0iMTI0LjQgMTAyLjMgMTA4LjQgMTI2LjUgMTQyLjYgMTM1LjkgMTUyLjQgMTAyLjggMTI0LjQgMTAyLjMiLz4KICAgICAgICA8cG9seWdvbiBjbGFzcz0iY2xzLTEiIHBvaW50cz0iMS4zIDEwMi44IDExIDEzNS45IDQ1LjEgMTI2LjUgMjkuMiAxMDIuMyAxLjMgMTAyLjgiLz4KICAgICAgICA8cG9seWdvbiBjbGFzcz0iY2xzLTEiIHBvaW50cz0iNDMuMyA2MS4zIDMzLjggNzUuNiA2Ny42IDc3LjEgNjYuNSA0MC45IDQzLjMgNjEuMyIvPgogICAgICAgIDxwb2x5Z29uIGNsYXNzPSJjbHMtMSIgcG9pbnRzPSIxMTAuMyA2MS4zIDg2LjcgNDAuNSA4NiA3Ny4xIDExOS44IDc1LjYgMTEwLjMgNjEuMyIvPgogICAgICAgIDxwb2x5Z29uIGNsYXNzPSJjbHMtMSIgcG9pbnRzPSI0NS4xIDEyNi41IDY1LjYgMTE2LjcgNDcuOSAxMDMuMSA0NS4xIDEyNi41Ii8+CiAgICAgICAgPHBvbHlnb24gY2xhc3M9ImNscy0xIiBwb2ludHM9Ijg4IDExNi43IDEwOC40IDEyNi41IDEwNS42IDEwMy4xIDg4IDExNi43Ii8+CiAgICAgICAgPHBvbHlnb24gY2xhc3M9ImNscy03IiBwb2ludHM9IjEwOC40IDEyNi41IDg4IDExNi43IDg5LjcgMTI5LjkgODkuNSAxMzUuNSAxMDguNCAxMjYuNSIvPgogICAgICAgIDxwb2x5Z29uIGNsYXNzPSJjbHMtNyIgcG9pbnRzPSI0NS4xIDEyNi41IDY0LjEgMTM1LjUgNjQgMTI5LjkgNjUuNiAxMTYuNyA0NS4xIDEyNi41Ii8+CiAgICAgICAgPHBvbHlnb24gY2xhc3M9ImNscy05IiBwb2ludHM9IjY0LjQgOTQuMyA0Ny41IDg5LjQgNTkuNSA4My45IDY0LjQgOTQuMyIvPgogICAgICAgIDxwb2x5Z29uIGNsYXNzPSJjbHMtOSIgcG9pbnRzPSI4OS4xIDk0LjMgOTQuMSA4My45IDEwNi4xIDg5LjQgODkuMSA5NC4zIi8+CiAgICAgICAgPHBvbHlnb24gY2xhc3M9ImNscy01IiBwb2ludHM9IjQ1LjEgMTI2LjUgNDguMSAxMDIuMyAyOS4yIDEwMi44IDQ1LjEgMTI2LjUiLz4KICAgICAgICA8cG9seWdvbiBjbGFzcz0iY2xzLTUiIHBvaW50cz0iMTA1LjUgMTAyLjMgMTA4LjQgMTI2LjUgMTI0LjQgMTAyLjggMTA1LjUgMTAyLjMiLz4KICAgICAgICA8cG9seWdvbiBjbGFzcz0iY2xzLTUiIHBvaW50cz0iMTE5LjggNzUuNiA4NiA3Ny4xIDg5LjEgOTQuMyA5NC4xIDgzLjkgMTA2LjEgODkuNCAxMTkuOCA3NS42Ii8+CiAgICAgICAgPHBvbHlnb24gY2xhc3M9ImNscy01IiBwb2ludHM9IjQ3LjUgODkuNCA1OS41IDgzLjkgNjQuNCA5NC4zIDY3LjYgNzcuMSAzMy44IDc1LjYgNDcuNSA4OS40Ii8+CiAgICAgICAgPHBvbHlnb24gY2xhc3M9ImNscy0xIiBwb2ludHM9IjMzLjggNzUuNiA0Ny45IDEwMy4xIDQ3LjUgODkuNCAzMy44IDc1LjYiLz4KICAgICAgICA8cG9seWdvbiBjbGFzcz0iY2xzLTEiIHBvaW50cz0iMTA2LjEgODkuNCAxMDUuNiAxMDMuMSAxMTkuOCA3NS42IDEwNi4xIDg5LjQiLz4KICAgICAgICA8cG9seWdvbiBjbGFzcz0iY2xzLTEiIHBvaW50cz0iNjcuNiA3Ny4xIDY0LjQgOTQuMyA2OC40IDExNC43IDY5LjMgODcuOSA2Ny42IDc3LjEiLz4KICAgICAgICA8cG9seWdvbiBjbGFzcz0iY2xzLTEiIHBvaW50cz0iODYgNzcuMSA4NC4zIDg3LjggODUuMSAxMTQuNyA4OS4xIDk0LjMgODYgNzcuMSIvPgogICAgICAgIDxwb2x5Z29uIGNsYXNzPSJjbHMtNiIgcG9pbnRzPSI4OS4xIDk0LjMgODUuMSAxMTQuNyA4OCAxMTYuNyAxMDUuNiAxMDMuMSAxMDYuMSA4OS40IDg5LjEgOTQuMyIvPgogICAgICAgIDxwb2x5Z29uIGNsYXNzPSJjbHMtNiIgcG9pbnRzPSI0Ny41IDg5LjQgNDcuOSAxMDMuMSA2NS42IDExNi43IDY4LjQgMTE0LjcgNjQuNCA5NC4zIDQ3LjUgODkuNCIvPgogICAgICAgIDxwb2x5Z29uIGNsYXNzPSJjbHMtMyIgcG9pbnRzPSI4OS41IDEzNS41IDg5LjcgMTI5LjkgODguMSAxMjguNiA2NS40IDEyOC42IDY0IDEyOS45IDY0LjEgMTM1LjUgNDUuMSAxMjYuNSA1MS43IDEzMS45IDY1LjIgMTQxLjIgODguMyAxNDEuMiAxMDEuOCAxMzEuOSAxMDguNCAxMjYuNSA4OS41IDEzNS41Ii8+CiAgICAgICAgPHBvbHlnb24gY2xhc3M9ImNscy05IiBwb2ludHM9Ijg4IDExNi43IDg1LjEgMTE0LjcgNjguNCAxMTQuNyA2NS42IDExNi43IDY0IDEyOS45IDY1LjQgMTI4LjYgODguMSAxMjguNiA4OS43IDEyOS45IDg4IDExNi43Ii8+CiAgICAgICAgPHBvbHlnb24gY2xhc3M9ImNscy0yIiBwb2ludHM9IjE0OC41IDQ3IDE1My41IDIyLjYgMTQ1LjkgMCA4OCA0Mi42IDExMC4zIDYxLjMgMTQxLjggNzAuNSAxNDguNyA2Mi40IDE0NS43IDYwLjIgMTUwLjUgNTUuOSAxNDYuOCA1MyAxNTEuNiA0OS40IDE0OC41IDQ3Ii8+CiAgICAgICAgPHBvbHlnb24gY2xhc3M9ImNscy0yIiBwb2ludHM9IjAgMjIuNiA1LjEgNDcgMS45IDQ5LjQgNi43IDUzLjEgMyA1NS45IDcuOCA2MC4yIDQuOCA2Mi40IDExLjggNzAuNSA0My4zIDYxLjMgNjUuNiA0Mi42IDcuNiAwIDAgMjIuNiIvPgogICAgICAgIDxwb2x5Z29uIGNsYXNzPSJjbHMtNiIgcG9pbnRzPSIxNDEuOCA3MC41IDExMC4zIDYxLjMgMTE5LjggNzUuNiAxMDUuNiAxMDMuMSAxMjQuNCAxMDIuOCAxNTIuNCAxMDIuOCAxNDEuOCA3MC41Ii8+CiAgICAgICAgPHBvbHlnb24gY2xhc3M9ImNscy02IiBwb2ludHM9IjQzLjMgNjEuMyAxMS44IDcwLjUgMS4zIDEwMi44IDI5LjIgMTAyLjggNDcuOSAxMDMuMSAzMy44IDc1LjYgNDMuMyA2MS4zIi8+CiAgICAgICAgPHBvbHlnb24gY2xhc3M9ImNscy02IiBwb2ludHM9Ijg2IDc3LjEgODggNDIuNiA5Ny4xIDE4LjEgNTYuNCAxOC4xIDY1LjYgNDIuNiA2Ny42IDc3LjEgNjguNCA4Ny45IDY4LjQgMTE0LjcgODUuMSAxMTQuNyA4NS4yIDg3LjkgODYgNzcuMSIvPgogICAgICA8L2c+CiAgICA8L2c+CiAgICA8ZyBpZD0iY2FyZGFub19hZGEiIGRhdGEtbmFtZT0iY2FyZGFubyBhZGEiPgogICAgICA8ZyBpZD0iY2FyZGFub19hZGEtMiIgZGF0YS1uYW1lPSJjYXJkYW5vIGFkYS0yIj4KICAgICAgICA8Y2lyY2xlIGlkPSJf0K3Qu9C70LjQv9GBXzYiIGRhdGEtbmFtZT0i0K3Qu9C70LjQv9GBIDYiIGNsYXNzPSJjbHMtNCIgY3g9IjEyOC4wNSIgY3k9IjEyMi41NiIgcj0iNDEuMTUiLz4KICAgICAgICA8cGF0aCBpZD0iX9Ct0LvQu9C40L/RgV82X9C60L7Qv9C40Y9fMjkiIGRhdGEtbmFtZT0i0K3Qu9C70LjQv9GBIDYg0LrQvtC/0LjRjyAyOSIgY2xhc3M9ImNscy04IiBkPSJNMTIzLjQ2LDEwOS45M2MyLjI1LDAsNC4wNywxLjgyLDQuMDcsNC4wNywwLDIuMjUtMS44Miw0LjA3LTQuMDcsNC4wNy0yLjI1LDAtNC4wNy0xLjgyLTQuMDctNC4wNywwLTIuMjUsMS44Mi00LjA3LDQuMDctNC4wN1pNMTMzLjI4LDEwOS45M2MyLjI1LDAsNC4wNywxLjgyLDQuMDcsNC4wNywwLDIuMjUtMS44Miw0LjA3LTQuMDcsNC4wNy0yLjI1LDAtNC4wNy0xLjgyLTQuMDctNC4wNywwLTIuMjUsMS44Mi00LjA3LDQuMDctNC4wN2gwWk0xMzMuMjgsMTI3LjA1YzIuMjUsMCw0LjA3LDEuODIsNC4wNyw0LjA3LDAsMi4yNS0xLjgyLDQuMDctNC4wNyw0LjA3LTIuMjUsMC00LjA3LTEuODItNC4wNy00LjA3LDAtMi4yNSwxLjgyLTQuMDcsNC4wNy00LjA3aDAsMFpNMTIzLjQ2LDEyNy4wNWMyLjI1LDAsNC4wNywxLjgyLDQuMDcsNC4wNywwLDIuMjUtMS44Miw0LjA3LTQuMDcsNC4wNy0yLjI1LDAtNC4wNy0xLjgyLTQuMDctNC4wNywwLTIuMjUsMS44Mi00LjA3LDQuMDctNC4wN1pNMTE4LjQxLDExOC42M2MyLjI1LDAsNC4wNywxLjgyLDQuMDcsNC4wNywwLDIuMjUtMS44Miw0LjA3LTQuMDcsNC4wNy0yLjI1LDAtNC4wNy0xLjgyLTQuMDctNC4wNywwLTIuMjUsMS44Mi00LjA3LDQuMDctNC4wN2gwWk0xMzguMzMsMTE4LjYzYzIuMjUsMCw0LjA3LDEuODIsNC4wNyw0LjA3LDAsMi4yNS0xLjgyLDQuMDctNC4wNyw0LjA3LTIuMjUsMC00LjA3LTEuODItNC4wNy00LjA3LDAtMi4yNSwxLjgyLTQuMDcsNC4wNy00LjA3aDBaTTE0Mi45NiwxMTEuNjJjMS4zOSwwLDIuNTIsMS4xMywyLjUyLDIuNTMsMCwxLjM5LTEuMTMsMi41Mi0yLjUzLDIuNTItMS4zOSwwLTIuNTItMS4xMy0yLjUyLTIuNTJzMS4xMy0yLjUyLDIuNTItMi41MmgwWk0xNDIuOTYsMTI4LjQ1YzEuMzksMCwyLjUyLDEuMTMsMi41MiwyLjUzLDAsMS4zOS0xLjEzLDIuNTItMi41MywyLjUyLTEuMzksMC0yLjUyLTEuMTMtMi41Mi0yLjUyczEuMTMtMi41MiwyLjUyLTIuNTJoMFpNMTEzLjc4LDEyOC40NWMxLjM5LDAsMi41MiwxLjEzLDIuNTIsMi41MywwLDEuMzktMS4xMywyLjUyLTIuNTMsMi41Mi0xLjM5LDAtMi41Mi0xLjEzLTIuNTItMi41MiwwLTEuMzksMS4xMy0yLjUyLDIuNTMtMi41MmgwWk0xMTMuNzgsMTExLjYyYzEuMzksMCwyLjUyLDEuMTMsMi41MiwyLjUzLDAsMS4zOS0xLjEzLDIuNTItMi41MywyLjUyLTEuMzksMC0yLjUyLTEuMTMtMi41Mi0yLjUyLDAtMS4zOSwxLjEzLTIuNTIsMi41My0yLjUyaDBaTTEyOC4zNywxMDMuMmMxLjM5LDAsMi41MiwxLjEzLDIuNTIsMi41MywwLDEuMzktMS4xMywyLjUyLTIuNTMsMi41Mi0xLjM5LDAtMi41Mi0xLjEzLTIuNTItMi41MnMxLjEzLTIuNTIsMi41Mi0yLjUyaDBaTTEyOC4zNywxMzYuODZjMS4zOSwwLDIuNTIsMS4xMywyLjUyLDIuNTMsMCwxLjM5LTEuMTMsMi41Mi0yLjUzLDIuNTItMS4zOSwwLTIuNTItMS4xMy0yLjUyLTIuNTJzMS4xMy0yLjUyLDIuNTItMi41MmgwWk0xMzkuMTcsMTM5LjM5YzEuMTYsMCwyLjEuOTQsMi4xLDIuMSwwLDEuMTYtLjk0LDIuMS0yLjEsMi4xLTEuMTYsMC0yLjEtLjk0LTIuMS0yLjFzLjk0LTIuMSwyLjEtMi4xaDBaTTExNy41NywxMzkuMzljMS4xNiwwLDIuMS45NCwyLjEsMi4xLDAsMS4xNi0uOTQsMi4xLTIuMSwyLjEtMS4xNiwwLTIuMS0uOTQtMi4xLTIuMXMuOTQtMi4xLDIuMS0yLjFoMFpNMTE3LjU3LDEwMS41MmMxLjE2LDAsMi4xLjk0LDIuMSwyLjEsMCwxLjE2LS45NCwyLjEtMi4xLDIuMS0xLjE2LDAtMi4xLS45NC0yLjEtMi4xcy45NC0yLjEsMi4xLTIuMWgwWk0xMzkuMTcsMTAxLjUyYzEuMTYsMCwyLjEuOTQsMi4xLDIuMSwwLDEuMTYtLjk0LDIuMS0yLjEsMi4xLTEuMTYsMC0yLjEtLjk0LTIuMS0yLjFzLjk0LTIuMSwyLjEtMi4xaDBaTTE1MC4xMSwxMjAuMzFjMS4xNiwwLDIuMS45NCwyLjEsMi4xLDAsMS4xNi0uOTQsMi4xLTIuMSwyLjEtMS4xNiwwLTIuMS0uOTQtMi4xLTIuMSwwLTEuMTYuOTQtMi4xLDIuMS0yLjFoMFpNMTA2LjYyLDEyMC4zMWMxLjE2LDAsMi4xLjk0LDIuMSwyLjEsMCwxLjE2LS45NCwyLjEtMi4xLDIuMS0xLjE2LDAtMi4xLS45NC0yLjEtMi4xcy45NC0yLjEsMi4xLTIuMWgwWk0xMDUuMDgsMTA3LjQxYy45MywwLDEuNjguNzUsMS42OCwxLjY4cy0uNzUsMS42OC0xLjY4LDEuNjgtMS42OC0uNzUtMS42OC0xLjY4aDBjMC0uOTMuNzUtMS42OCwxLjY4LTEuNjhoMFpNMTA1LjA4LDEzNC4zNGMuOTMsMCwxLjY4Ljc1LDEuNjgsMS42OHMtLjc1LDEuNjgtMS42OCwxLjY4LTEuNjgtLjc1LTEuNjgtMS42OGgwYzAtLjkzLjc1LTEuNjgsMS42OC0xLjY4aDBaTTE1MS42NiwxMzQuMzRjLjkzLDAsMS42OC43NSwxLjY4LDEuNjgsMCwuOTMtLjc1LDEuNjgtMS42OCwxLjY4cy0xLjY4LS43NS0xLjY4LTEuNjhoMGMwLS45My43NS0xLjY4LDEuNjgtMS42OGgwWk0xNTEuNjYsMTA3LjQxYy45MywwLDEuNjguNzUsMS42OCwxLjY4LDAsLjkzLS43NSwxLjY4LTEuNjgsMS42OHMtMS42OC0uNzUtMS42OC0xLjY4aDBjMC0uOTMuNzUtMS42OCwxLjY4LTEuNjhoMFpNMTI4LjM3LDkzLjk0Yy45MywwLDEuNjguNzUsMS42OCwxLjY4LDAsLjkzLS43NSwxLjY4LTEuNjgsMS42OC0uOTMsMC0xLjY4LS43NS0xLjY4LTEuNjhoMGMwLS45My43NS0xLjY4LDEuNjgtMS42OGgwWk0xMjguMzcsMTQ3LjhjLjkzLDAsMS42OC43NSwxLjY4LDEuNjgsMCwuOTMtLjc1LDEuNjgtMS42OCwxLjY4LS45MywwLTEuNjgtLjc1LTEuNjgtMS42OHMuNzUtMS42OCwxLjY4LTEuNjhoMFpNMTQzLjI0LDE0Ni42OGMuNzcsMCwxLjQuNjMsMS40LDEuNCwwLC43Ny0uNjMsMS40LTEuNCwxLjRzLTEuNC0uNjMtMS40LTEuNGgwYzAtLjc3LjYzLTEuNCwxLjQtMS40Wk0xMTMuNSwxNDYuNjhjLjc3LDAsMS40LjYzLDEuNCwxLjRzLS42MywxLjQtMS40LDEuNC0xLjQtLjYzLTEuNC0xLjRoMGMwLS43Ny42My0xLjQsMS40LTEuNFpNMTEzLjUsOTUuNjNjLjc3LDAsMS40LjYzLDEuNCwxLjRzLS42MywxLjQtMS40LDEuNC0xLjQtLjYzLTEuNC0xLjRoMGMwLS43Ny42My0xLjQsMS40LTEuNGgwWk0xNDMuMjQsOTUuNjNjLjc3LDAsMS40LjYzLDEuNCwxLjQsMCwuNzctLjYzLDEuNC0xLjQsMS40cy0xLjQtLjYzLTEuNC0xLjRoMGMwLS43Ny42My0xLjQsMS40LTEuNGgwWk0xNTcuODMsMTIxLjE2Yy43NywwLDEuNC42MywxLjQsMS40LDAsLjc3LS42MywxLjQtMS40LDEuNHMtMS40LS42My0xLjQtMS40aDBjMC0uNzguNjMtMS40LDEuNC0xLjRoMFpNOTguOTEsMTIxLjE2Yy43NywwLDEuNC42MywxLjQsMS40cy0uNjMsMS40LTEuNCwxLjQtMS40LS42My0xLjQtMS40aDBjMC0uNzguNjMtMS40LDEuNC0xLjRoMFoiLz4KICAgICAgPC9nPgogICAgPC9nPgogIDwvZz4KPC9zdmc+", + version: "version", + }); + } else { + resolve(undefined); + } + }); + }); + } catch (err) { + return Promise.resolve(undefined); + } +} diff --git a/packages/mesh-wallet/src/mesh/index.ts b/packages/mesh-wallet/src/mesh/index.ts index d36b8769..7531fd18 100644 --- a/packages/mesh-wallet/src/mesh/index.ts +++ b/packages/mesh-wallet/src/mesh/index.ts @@ -15,19 +15,27 @@ import { } from "@meshsdk/common"; import { Address, + buildBaseAddress, + buildEnterpriseAddress, + buildRewardAddress, + CardanoSDKSerializer, + deserializeAddress, + deserializeTx, + Ed25519KeyHashHex, fromTxUnspentOutput, + Hash28ByteBase16, resolvePrivateKey, + toAddress, toTxUnspentOutput, TransactionUnspentOutput, } from "@meshsdk/core-cst"; import { Transaction } from "@meshsdk/transaction"; -import { AppWallet } from "../app"; import { EmbeddedWallet } from "../embedded"; import { GetAddressType } from "../types"; export type CreateMeshWalletOptions = { - networkId: number; + networkId: 0 | 1; fetcher?: IFetcher; submitter?: ISubmitter; key: @@ -44,6 +52,12 @@ export type CreateMeshWalletOptions = { type: "mnemonic"; words: string[]; }; + // | { + // type: "address"; + // address: string; + // } + accountIndex?: number; + keyIndex?: number; }; /** @@ -68,45 +82,69 @@ export type CreateMeshWalletOptions = { * ``` */ export class MeshWallet implements IInitiator, ISigner, ISubmitter { - private readonly _wallet: AppWallet; + private readonly _wallet: EmbeddedWallet | null; + // private readonly _account: Account; + private readonly _accountIndex: number = 0; + private readonly _keyIndex: number = 0; + private readonly _fetcher?: IFetcher; + private readonly _submitter?: ISubmitter; + private readonly _networkId: 0 | 1; + private _addresses: { + baseAddress?: Address; + enterpriseAddress?: Address; + rewardAddress?: Address; + baseAddressBech32?: string; + enterpriseAddressBech32?: string; + rewardAddressBech32?: string; + } = {}; constructor(options: CreateMeshWalletOptions) { switch (options.key.type) { case "root": - this._wallet = new AppWallet({ + this._wallet = new EmbeddedWallet({ networkId: options.networkId, - fetcher: options.fetcher, - submitter: options.submitter, key: { type: "root", bech32: options.key.bech32, }, }); + this.getAddressesFromWallet(this._wallet); break; case "cli": - this._wallet = new AppWallet({ + this._wallet = new EmbeddedWallet({ networkId: options.networkId, - fetcher: options.fetcher, - submitter: options.submitter, key: { type: "cli", payment: options.key.payment, stake: options.key.stake, }, }); + this.getAddressesFromWallet(this._wallet); break; case "mnemonic": - this._wallet = new AppWallet({ + this._wallet = new EmbeddedWallet({ networkId: options.networkId, - fetcher: options.fetcher, - submitter: options.submitter, key: { type: "mnemonic", words: options.key.words, }, }); + this.getAddressesFromWallet(this._wallet); break; + // case "address": + // console.log(4); + // this._wallet = null; + // this.buildAddressFromBech32Address(options.key.address); + // console.log(5); + // break; } + + this._networkId = options.networkId; + + if (options.fetcher) this._fetcher = options.fetcher; + if (options.submitter) this._submitter = options.submitter; + if (options.accountIndex) this._accountIndex = options.accountIndex; + if (options.keyIndex) this._keyIndex = options.keyIndex; } /** @@ -148,7 +186,7 @@ export class MeshWallet implements IInitiator, ISigner, ISubmitter { * @returns an address */ getChangeAddress(): string { - return this._wallet.getPaymentAddress(); + return this._addresses.baseAddressBech32!; } /** @@ -162,19 +200,53 @@ export class MeshWallet implements IInitiator, ISigner, ISubmitter { async getCollateral( addressType: GetAddressType = "payment", ): Promise { - const utxos = await this._wallet.getCollateralUnspentOutput(0, addressType); + const utxos = await this.getCollateralUnspentOutput(addressType); return utxos.map((utxo, i) => { return fromTxUnspentOutput(utxo); }); } + /** + * Get a list of UTXOs to be used as collateral inputs for transactions with plutus script inputs. + * + * This is used in transaction building. + * + * @returns a list of UTXOs + */ + async getCollateralUnspentOutput( + addressType: GetAddressType = "payment", + ): Promise { + const utxos = await this.getUnspentOutputs(addressType); + + // find utxos that are pure ADA-only + const pureAdaUtxos = utxos.filter((utxo) => { + return utxo.output().amount().multiasset() === undefined; + }); + + // sort utxos by their lovelace amount + pureAdaUtxos.sort((a, b) => { + return ( + Number(a.output().amount().coin()) - Number(b.output().amount().coin()) + ); + }); + + // return the smallest utxo but not less than 5000000 lovelace + for (const utxo of pureAdaUtxos) { + if (Number(utxo.output().amount().coin()) >= 5000000) { + return [utxo]; + } + } + + return []; + } + /** * Returns the network ID of the currently connected account. 0 is testnet and 1 is mainnet but other networks can possibly be returned by wallets. Those other network ID values are not governed by CIP-30. This result will stay the same unless the connected account has changed. * * @returns network ID */ getNetworkId(): number { - return this._wallet.getNetworkId(); + return this._networkId; } /** @@ -183,7 +255,7 @@ export class MeshWallet implements IInitiator, ISigner, ISubmitter { * @returns a list of reward addresses */ getRewardAddresses(): string[] { - return [this._wallet.getRewardAddress()]; + return [this._addresses.rewardAddressBech32!]; } /** @@ -254,6 +326,11 @@ export class MeshWallet implements IInitiator, ISigner, ISubmitter { * @returns a signature */ signData(payload: string): DataSignature { + if (!this._wallet) { + throw new Error( + "[MeshWallet] Read only wallet does not support signing data.", + ); + } return this._wallet.signData(this.getChangeAddress(), payload); } @@ -265,7 +342,30 @@ export class MeshWallet implements IInitiator, ISigner, ISubmitter { * @returns a signed transaction in CBOR */ signTx(unsignedTx: string, partialSign = false): string { - return this._wallet.signTx(unsignedTx, partialSign); + if (!this._wallet) { + throw new Error( + "[MeshWallet] Read only wallet does not support signing data.", + ); + } + + const tx = deserializeTx(unsignedTx); + if ( + !partialSign && + tx.witnessSet().vkeys() !== undefined && + tx.witnessSet().vkeys()!.size() !== 0 + ) + throw new Error( + "Signatures already exist in the transaction in a non partial sign call", + ); + + const newSignatures = this._wallet.signTx( + unsignedTx, + this._accountIndex, + this._keyIndex, + ); + + let signedTx = EmbeddedWallet.addWitnessSets(unsignedTx, [newSignatures]); + return signedTx; } /** @@ -295,7 +395,12 @@ export class MeshWallet implements IInitiator, ISigner, ISubmitter { * @returns a transaction hash */ async submitTx(tx: string): Promise { - return await this._wallet.submitTx(tx); + if (!this._submitter) { + throw new Error( + "[AppWallet] Submitter is required to submit transactions. Please provide a submitter.", + ); + } + return this._submitter.submitTx(tx); } /** @@ -306,7 +411,11 @@ export class MeshWallet implements IInitiator, ISigner, ISubmitter { * @returns an Address object */ getUsedAddress(addressType?: GetAddressType): Address { - return this._wallet.getUsedAddress(0, 0, addressType); + if (addressType === "enterprise") { + return toAddress(this._addresses.enterpriseAddressBech32!); + } else { + return toAddress(this._addresses.baseAddressBech32!); + } } /** @@ -319,7 +428,19 @@ export class MeshWallet implements IInitiator, ISigner, ISubmitter { async getUnspentOutputs( addressType?: GetAddressType, ): Promise { - return await this._wallet.getUnspentOutputs(0, addressType); + if (!this._fetcher) { + throw new Error( + "[AppWallet] Fetcher is required to fetch UTxOs. Please provide a fetcher.", + ); + } + + const utxos = await this._fetcher.fetchAddressUTxOs( + addressType == "enterprise" + ? this._addresses.enterpriseAddressBech32! + : this._addresses.baseAddressBech32!, + ); + + return utxos.map((utxo) => toTxUnspentOutput(utxo)); } /** @@ -410,4 +531,66 @@ export class MeshWallet implements IInitiator, ISigner, ISubmitter { return mnemonic; } + + getAddressesFromWallet(wallet: EmbeddedWallet) { + const account = wallet.getAccount(this._accountIndex, this._keyIndex); + + this._addresses = { + baseAddress: account.baseAddress, + enterpriseAddress: account.enterpriseAddress, + rewardAddress: account.rewardAddress, + baseAddressBech32: account.baseAddressBech32, + enterpriseAddressBech32: account.enterpriseAddressBech32, + rewardAddressBech32: account.rewardAddressBech32, + }; + } + + buildAddressFromBech32Address(address: string) { + const serializer = new CardanoSDKSerializer(); + + const deserializedAddress = + serializer.deserializer.key.deserializeAddress(address); + + if ( + deserializedAddress.pubKeyHash && + deserializedAddress.stakeCredentialHash + ) { + this._addresses.baseAddress = buildBaseAddress( + this._networkId, + Hash28ByteBase16.fromEd25519KeyHashHex( + Ed25519KeyHashHex(deserializedAddress.pubKeyHash), + ), + Hash28ByteBase16.fromEd25519KeyHashHex( + Ed25519KeyHashHex( + Ed25519KeyHashHex(deserializedAddress.stakeCredentialHash), + ), + ), + ).toAddress(); + this._addresses.baseAddressBech32 = + this._addresses.baseAddress.toBech32(); + } + + if (deserializedAddress.pubKeyHash) { + this._addresses.enterpriseAddress = buildEnterpriseAddress( + this._networkId, + Hash28ByteBase16.fromEd25519KeyHashHex( + Ed25519KeyHashHex(deserializedAddress.pubKeyHash), + ), + ).toAddress(); + this._addresses.enterpriseAddressBech32 = + this._addresses.enterpriseAddress.toBech32(); + } + + if (deserializedAddress.stakeCredentialHash) { + this._addresses.rewardAddress = buildRewardAddress( + this._networkId, + Hash28ByteBase16.fromEd25519KeyHashHex( + Ed25519KeyHashHex(deserializedAddress.stakeCredentialHash), + ), + ).toAddress(); + + this._addresses.rewardAddressBech32 = + this._addresses.rewardAddress.toBech32(); + } + } } diff --git a/packages/mesh-wallet/src/mesh_old/index.ts b/packages/mesh-wallet/src/mesh_old/index.ts new file mode 100644 index 00000000..d36b8769 --- /dev/null +++ b/packages/mesh-wallet/src/mesh_old/index.ts @@ -0,0 +1,413 @@ +import type { + Asset, + AssetExtended, + DataSignature, + UTxO, +} from "@meshsdk/common"; +import { + IFetcher, + IInitiator, + ISigner, + ISubmitter, + POLICY_ID_LENGTH, + resolveFingerprint, + toUTF8, +} from "@meshsdk/common"; +import { + Address, + fromTxUnspentOutput, + resolvePrivateKey, + toTxUnspentOutput, + TransactionUnspentOutput, +} from "@meshsdk/core-cst"; +import { Transaction } from "@meshsdk/transaction"; + +import { AppWallet } from "../app"; +import { EmbeddedWallet } from "../embedded"; +import { GetAddressType } from "../types"; + +export type CreateMeshWalletOptions = { + networkId: number; + fetcher?: IFetcher; + submitter?: ISubmitter; + key: + | { + type: "root"; + bech32: string; + } + | { + type: "cli"; + payment: string; + stake?: string; + } + | { + type: "mnemonic"; + words: string[]; + }; +}; + +/** + * Mesh Wallet provides a set of APIs to interact with the blockchain. This wallet is compatible with Mesh transaction builders. + * + * It is a single address wallet, a wrapper around the AppWallet class. + * + * ```javascript + * import { MeshWallet, BlockfrostProvider } from '@meshsdksdk/core'; + * + * const blockchainProvider = new BlockfrostProvider(''); + * + * const wallet = new MeshWallet({ + * networkId: 0, + * fetcher: blockchainProvider, + * submitter: blockchainProvider, + * key: { + * type: 'mnemonic', + * words: ["solution","solution","solution","solution","solution",","solution","solution","solution","solution","solution","solution","solution","solution","solution","solution","solution","solution","solution","solution","solution","solution","solution","solution"], + * }, + * }); + * ``` + */ +export class MeshWallet implements IInitiator, ISigner, ISubmitter { + private readonly _wallet: AppWallet; + + constructor(options: CreateMeshWalletOptions) { + switch (options.key.type) { + case "root": + this._wallet = new AppWallet({ + networkId: options.networkId, + fetcher: options.fetcher, + submitter: options.submitter, + key: { + type: "root", + bech32: options.key.bech32, + }, + }); + break; + case "cli": + this._wallet = new AppWallet({ + networkId: options.networkId, + fetcher: options.fetcher, + submitter: options.submitter, + key: { + type: "cli", + payment: options.key.payment, + stake: options.key.stake, + }, + }); + break; + case "mnemonic": + this._wallet = new AppWallet({ + networkId: options.networkId, + fetcher: options.fetcher, + submitter: options.submitter, + key: { + type: "mnemonic", + words: options.key.words, + }, + }); + break; + } + } + + /** + * Returns a list of assets in the wallet. This API will return every assets in the wallet. Each asset is an object with the following properties: + * - A unit is provided to display asset's name on the user interface. + * - A quantity is provided to display asset's quantity on the user interface. + * + * @returns a list of assets and their quantities + */ + async getBalance(): Promise { + const utxos = await this.getUnspentOutputs(); + + const assets = new Map(); + utxos.map((utxo) => { + const _utxo = fromTxUnspentOutput(utxo); + _utxo.output.amount.map((asset) => { + const assetId = asset.unit; + const amount = Number(asset.quantity); + if (assets.has(assetId)) { + const quantity = assets.get(assetId)!; + assets.set(assetId, quantity + amount); + } else { + assets.set(assetId, amount); + } + }); + }); + + const arrayAssets: Asset[] = Array.from(assets, ([unit, quantity]) => ({ + unit, + quantity: quantity.toString(), + })); + + return arrayAssets; + } + + /** + * Returns an address owned by the wallet that should be used as a change address to return leftover assets during transaction creation back to the connected wallet. + * + * @returns an address + */ + getChangeAddress(): string { + return this._wallet.getPaymentAddress(); + } + + /** + * This function shall return a list of one or more UTXOs (unspent transaction outputs) controlled by the wallet that are required to reach AT LEAST the combined ADA value target specified in amount AND the best suitable to be used as collateral inputs for transactions with plutus script inputs (pure ADA-only UTXOs). + * + * If this cannot be attained, an error message with an explanation of the blocking problem shall be returned. NOTE: wallets are free to return UTXOs that add up to a greater total ADA value than requested in the amount parameter, but wallets must never return any result where UTXOs would sum up to a smaller total ADA value, instead in a case like that an error message must be returned. + * + * @returns a list of UTXOs + */ + + async getCollateral( + addressType: GetAddressType = "payment", + ): Promise { + const utxos = await this._wallet.getCollateralUnspentOutput(0, addressType); + return utxos.map((utxo, i) => { + return fromTxUnspentOutput(utxo); + }); + } + + /** + * Returns the network ID of the currently connected account. 0 is testnet and 1 is mainnet but other networks can possibly be returned by wallets. Those other network ID values are not governed by CIP-30. This result will stay the same unless the connected account has changed. + * + * @returns network ID + */ + getNetworkId(): number { + return this._wallet.getNetworkId(); + } + + /** + * Returns a list of reward addresses owned by the wallet. A reward address is a stake address that is used to receive rewards from staking, generally starts from `stake` prefix. + * + * @returns a list of reward addresses + */ + getRewardAddresses(): string[] { + return [this._wallet.getRewardAddress()]; + } + + /** + * Returns a list of unused addresses controlled by the wallet. + * + * @returns a list of unused addresses + */ + getUnusedAddresses(): string[] { + return [this.getChangeAddress()]; + } + + /** + * Returns a list of used addresses controlled by the wallet. + * + * @returns a list of used addresses + */ + getUsedAddresses(): string[] { + return [this.getChangeAddress()]; + } + + /** + * Get a list of UTXOs to be used as collateral inputs for transactions with plutus script inputs. + * + * This is used in transaction building. + * + * @returns a list of UTXOs + */ + async getUsedCollateral(): Promise { + const collateralUtxo = await this.getCollateral(); + + const unspentOutput = collateralUtxo.map((utxo) => { + return toTxUnspentOutput(utxo); + }); + + return unspentOutput; + } + + /** + * Get a list of UTXOs to be used for transaction building. + * + * This is used in transaction building. + * + * @returns a list of UTXOs + */ + async getUsedUTxOs( + addressType?: GetAddressType, + ): Promise { + return await this.getUnspentOutputs(addressType); + } + + /** + * Return a list of all UTXOs (unspent transaction outputs) controlled by the wallet. + * + * @returns a list of UTXOs + */ + async getUtxos(addressType?: GetAddressType): Promise { + const utxos = await this.getUsedUTxOs(addressType); + return utxos.map((c) => fromTxUnspentOutput(c)); + } + + /** + * This endpoint utilizes the [CIP-8 - Message Signing](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030) to sign arbitrary data, to verify the data was signed by the owner of the private key. + * + * Here, we get the first wallet's address with wallet.getUsedAddresses(), alternativelly you can use reward addresses (getRewardAddresses()) too. It's really up to you as the developer which address you want to use in your application. + * + * @param address + * @param payload + * @returns a signature + */ + signData(payload: string): DataSignature { + return this._wallet.signData(this.getChangeAddress(), payload); + } + + /** + * Requests user to sign the provided transaction (tx). The wallet should ask the user for permission, and if given, try to sign the supplied body and return a signed transaction. partialSign should be true if the transaction provided requires multiple signatures. + * + * @param unsignedTx + * @param partialSign + * @returns a signed transaction in CBOR + */ + signTx(unsignedTx: string, partialSign = false): string { + return this._wallet.signTx(unsignedTx, partialSign); + } + + /** + * Experimental feature - sign multiple transactions at once. + * + * @param unsignedTxs - array of unsigned transactions in CborHex string + * @param partialSign - if the transactions are signed partially + * @returns array of signed transactions CborHex string + */ + signTxs(unsignedTxs: string[], partialSign = false): string[] { + const signedTxs: string[] = []; + + for (const unsignedTx of unsignedTxs) { + const signedTx = this.signTx(unsignedTx, partialSign); + signedTxs.push(signedTx); + } + + return signedTxs; + } + + /** + * Submits the signed transaction to the blockchain network. + * + * As wallets should already have this ability to submit transaction, we allow dApps to request that a transaction be sent through it. If the wallet accepts the transaction and tries to send it, it shall return the transaction ID for the dApp to track. The wallet can return error messages or failure if there was an error in sending it. + * + * @param tx + * @returns a transaction hash + */ + async submitTx(tx: string): Promise { + return await this._wallet.submitTx(tx); + } + + /** + * Get a used address of type Address from the wallet. + * + * This is used in transaction building. + * + * @returns an Address object + */ + getUsedAddress(addressType?: GetAddressType): Address { + return this._wallet.getUsedAddress(0, 0, addressType); + } + + /** + * Get a list of UTXOs to be used for transaction building. + * + * This is used in transaction building. + * + * @returns a list of UTXOs + */ + async getUnspentOutputs( + addressType?: GetAddressType, + ): Promise { + return await this._wallet.getUnspentOutputs(0, addressType); + } + + /** + * A helper function to get the assets in the wallet. + * + * @returns a list of assets + */ + async getAssets(): Promise { + const balance = await this.getBalance(); + return balance + .filter((v) => v.unit !== "lovelace") + .map((v) => { + const policyId = v.unit.slice(0, POLICY_ID_LENGTH); + const assetName = v.unit.slice(POLICY_ID_LENGTH); + const fingerprint = resolveFingerprint(policyId, assetName); + + return { + unit: v.unit, + policyId, + assetName: toUTF8(assetName), + fingerprint, + quantity: v.quantity, + }; + }); + } + + /** + * A helper function to get the lovelace balance in the wallet. + * + * @returns lovelace balance + */ + async getLovelace(): Promise { + const balance = await this.getBalance(); + const nativeAsset = balance.find((v) => v.unit === "lovelace"); + + return nativeAsset !== undefined ? nativeAsset.quantity : "0"; + } + + /** + * A helper function to get the assets of a specific policy ID in the wallet. + * + * @param policyId + * @returns a list of assets + */ + async getPolicyIdAssets(policyId: string): Promise { + const assets = await this.getAssets(); + return assets.filter((v) => v.policyId === policyId); + } + + /** + * A helper function to get the policy IDs of all the assets in the wallet. + * + * @returns a list of policy IDs + */ + async getPolicyIds(): Promise { + const balance = await this.getBalance(); + return Array.from( + new Set(balance.map((v) => v.unit.slice(0, POLICY_ID_LENGTH))), + ).filter((p) => p !== "lovelace"); + } + + /** + * A helper function to create a collateral input for a transaction. + * + * @returns a transaction hash + */ + async createCollateral(): Promise { + const tx = new Transaction({ initiator: this }); + tx.sendLovelace(this.getChangeAddress(), "5000000"); + const unsignedTx = await tx.build(); + const signedTx = await this.signTx(unsignedTx); + const txHash = await this.submitTx(signedTx); + return txHash; + } + + /** + * Generate mnemonic or private key + * + * @param privateKey return private key if true + * @returns a transaction hash + */ + static brew(privateKey = false, strength = 256): string[] | string { + const mnemonic = EmbeddedWallet.generateMnemonic(strength); + + if (privateKey) { + return resolvePrivateKey(mnemonic); + } + + return mnemonic; + } +} diff --git a/packages/mesh-wallet/test/app.test.ts b/packages/mesh-wallet/test/app.test.ts index fed9c007..02c6730f 100644 --- a/packages/mesh-wallet/test/app.test.ts +++ b/packages/mesh-wallet/test/app.test.ts @@ -1,4 +1,4 @@ -import { AppWallet } from "../src"; +import { AppWallet } from "@meshsdk/wallet"; describe("AppWallet", () => { const wallet = new AppWallet({ diff --git a/packages/mesh-wallet/test/browser.test.ts b/packages/mesh-wallet/test/browser.test.ts index ac7d6f9c..e2db9b52 100644 --- a/packages/mesh-wallet/test/browser.test.ts +++ b/packages/mesh-wallet/test/browser.test.ts @@ -1,6 +1,5 @@ import { CardanoSDKUtil, Serialization } from "@meshsdk/core-cst"; - -import { WalletStaticMethods } from "../src"; +import { WalletStaticMethods } from "@meshsdk/wallet"; describe("BroswerWallet", () => { it("signTx: addWitnessSet", () => { diff --git a/packages/mesh-wallet/test/embedded.test.ts b/packages/mesh-wallet/test/embedded.test.ts index 7c95132e..9b0e84c2 100644 --- a/packages/mesh-wallet/test/embedded.test.ts +++ b/packages/mesh-wallet/test/embedded.test.ts @@ -1,6 +1,5 @@ import { checkSignature } from "@meshsdk/core-cst"; - -import { EmbeddedWallet } from "../src"; +import { EmbeddedWallet } from "@meshsdk/wallet"; describe("EmbeddedWallet mnemonic", () => { const wallet = new EmbeddedWallet({ diff --git a/packages/mesh-wallet/test/mesh.test.ts b/packages/mesh-wallet/test/mesh.test.ts index 7b78638c..0b3bbf20 100644 --- a/packages/mesh-wallet/test/mesh.test.ts +++ b/packages/mesh-wallet/test/mesh.test.ts @@ -1,4 +1,4 @@ -import { MeshWallet } from "../src"; +import { MeshWallet } from "@meshsdk/wallet"; describe("MeshWallet", () => { const wallet = new MeshWallet({