diff --git a/apps/playground/src/pages/apis/utilities/serializers/index.tsx b/apps/playground/src/pages/apis/utilities/serializers/index.tsx index 2dac4694..f7b98874 100644 --- a/apps/playground/src/pages/apis/utilities/serializers/index.tsx +++ b/apps/playground/src/pages/apis/utilities/serializers/index.tsx @@ -4,6 +4,7 @@ import SidebarFullwidth from "~/components/layouts/sidebar-fullwidth"; import TitleIconDescriptionBody from "~/components/sections/title-icon-description-body"; import Metatags from "~/components/site/metatags"; import { metaSerializers } from "~/data/links-utilities"; +import SerializeNativeScript from "./serialize-native-script"; const ReactPage: NextPage = () => { const sidebarItems = [{ label: "Coming soon", to: "resolveDataHash" }]; @@ -22,6 +23,8 @@ const ReactPage: NextPage = () => { > <> + + ); diff --git a/apps/playground/src/pages/apis/utilities/serializers/resolve-data-hash.tsx b/apps/playground/src/pages/apis/utilities/serializers/resolve-data-hash.tsx deleted file mode 100644 index ae59bbb5..00000000 --- a/apps/playground/src/pages/apis/utilities/serializers/resolve-data-hash.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { useState } from "react"; -import Link from "~/components/link"; - -import { Data } from "@meshsdk/core"; -import { resolveDataHash } from "@meshsdk/core"; - -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"; - -export default function ResolveDataHash() { - return ( - - ); -} - -function Left() { - return ( - <> -

- Converts datum into hash. Getting the hash is useful when you need to - query for the UTXO that contain the assets you need for your - transaction's input. -

-

- Explore Transaction to learn more - about designing Datum, and learn how to query for UTXOs containing the - datum hash. -

- - ); -} - -function Right() { - const [userInput, setUserInput] = useState("supersecretdatum"); - - async function runDemo() { - const datum: Data = userInput; - const dataHash = resolveDataHash(datum); - return dataHash; - } - - let codeSnippet = `resolveDataHash('${userInput}');`; - - return ( - - setUserInput(e.target.value)} - label="Datum" - key={0} - />, - ]} - /> - - ); -} diff --git a/apps/playground/src/pages/apis/utilities/serializers/serialize-native-script.tsx b/apps/playground/src/pages/apis/utilities/serializers/serialize-native-script.tsx new file mode 100644 index 00000000..d39e0ca1 --- /dev/null +++ b/apps/playground/src/pages/apis/utilities/serializers/serialize-native-script.tsx @@ -0,0 +1,65 @@ +import { + deserializeAddress, + NativeScript, + serializeNativeScript, +} from "@meshsdk/core"; + +import LiveCodeDemo from "~/components/sections/live-code-demo"; +import TwoColumnsScroll from "~/components/sections/two-columns-scroll"; +import { demoAddresses } from "~/data/cardano"; + +export default function SerializeNativeScript() { + return ( + + ); +} + +function Left() { + return ( + <> +

Serialize Native script into bech32 address.

+ + ); +} + +function Right() { + async function runDemo() { + const { pubKeyHash: keyHash } = deserializeAddress( + demoAddresses.testnetPayment, + ); + + const nativeScript: NativeScript = { + type: "all", + scripts: [ + { + type: "before", + slot: "99999999", + }, + { + type: "sig", + keyHash: keyHash, + }, + ], + }; + + const address = serializeNativeScript(nativeScript); + + return address; + } + + let codeSnippet = ``; + + return ( + + ); +} diff --git a/apps/playground/src/pages/smart-contracts/vesting/full-tutorial.tsx b/apps/playground/src/pages/smart-contracts/vesting/full-tutorial.tsx new file mode 100644 index 00000000..a368acea --- /dev/null +++ b/apps/playground/src/pages/smart-contracts/vesting/full-tutorial.tsx @@ -0,0 +1,454 @@ +import Link from "~/components/link"; +import TwoColumnsScroll from "~/components/sections/two-columns-scroll"; +import Codeblock from "~/components/text/codeblock"; + +export default function VestingFullTutorial() { + return ( + + ); +} + +function Left() { + return ( + <> +

+ Vesting contract is a smart contract that locks up funds for a period of + time and allows the owner to withdraw the funds after the lockup period. + Usually, vesting contract defines a beneficiary who can be different + from the original owner. +

+ +

+ When a new employee joins an organization, they typically receive a + promise of compensation to be disbursed after a specified duration of + employment. This arrangement often involves the organization depositing + the funds into a vesting contract, with the employee gaining access to + the funds upon the completion of a predetermined lockup period. Through + the utilization of vesting contracts, organizations establish a + mechanism to encourage employee retention by linking financial rewards + to tenure. +

+ +

On-Chain code

+ +

+ First, we define the datum's shape, as this datum serves as + configuration and contains the different parameters of our vesting + operation. +

+ + + +

+ In this example, we define a `VestingDatum` that contains the following + fields: +

+ +
    +
  • + `lock_until`: The POSIX timestamp in milliseconds until which the + funds are locked. +
  • +
  • + `owner`: The credentials (public key hash) of the owner of the funds. +
  • +
  • + `beneficiary`: The credentials (public key hash) of the beneficiary of + the funds. +
  • +
+ +

+ This datum can be found in + `aiken-vesting/aiken-workspace/lib/vesting/types.ak`. +

+ +

Next, we define the spend validator.

+ + or { + key_signed(ctx.transaction.extra_signatories, datum.owner), + and { + key_signed(ctx.transaction.extra_signatories, datum.beneficiary), + valid_after(ctx.transaction.validity_range, datum.lock_until), + }, + } + _ -> False + } + } +} +`} + /> + +

+ In this example, we define a `vesting` validator that ensures the + following conditions are met: +

+ +
    +
  • The transaction must be signed by owner
  • +
+

Or:

+
    +
  • The transaction must be signed by beneficiary
  • +
  • The transaction must be valid after the lockup period
  • +
+ +

+ This validator can be found in + `aiken-vesting/aiken-workspace/validators/vesting.ak`. +

+ +

How it works

+ +

+ The owner of the funds deposits the funds into the vesting contract. The + funds are locked up until the lockup period expires. +

+ +

+ Transactions can include validity intervals that specify when the + transaction is valid, both from and until a certain time. The ledger + verifies these validity bounds before executing a script and will only + proceed if they are legitimate. +

+ +

+ This approach allows scripts to incorporate a sense of time while + maintaining determinism within the script's context. For instance, if a + transaction has a lower bound `A`, we can infer that the current time is + at least `A`. +

+ +

+ It's important to note that since we don't control the upper bound, a + transaction might be executed even 30 years after the vesting delay. + However, from the script's perspective, this is entirely acceptable. +

+ +

+ The beneficiary can withdraw the funds after the lockup period expires. + The beneficiary can also be different from the owner of the funds. +

+ +

Testing

+ +

+ To test the vesting contract, we have provided the a comphrehensive test + script,you can run tests with `aiken check`. +

+ +

The test script includes the following test cases:

+ +
    +
  • success unlocking
  • +
  • success unlocking with only owner signature
  • +
  • success unlocking with beneficiary signature and time passed
  • +
  • fail unlocking with only beneficiary signature
  • +
  • fail unlocking with only time passed
  • +
+ +

+ We recommend you to check out + `aiken-vesting/aiken-workspace/validators/tests/vesting.ak` to learn + more. +

+ +

Compile and build script

+ +

To compile the script, run the following command:

+ + + +

+ This command will generate a CIP-0057 Plutus blueprint, which you can + find in `aiken-vesting/aiken-workspace/plutus.json`. +

+ +

Off-Chain code

+ +

Deposit funds

+ +

+ First, the owner can deposit funds into the vesting contract. The owner + can specify the lockup period and the beneficiary of the funds. +

+ + + +

+ In this example, we deposit 10 ADA into the vesting contract. The funds + are locked up for 1 minute, and the beneficiary is specified. +

+ +

+ Then, we prepare a few variables to be used in the transaction. We get + the wallet address and the UTXOs of the wallet. We also get the script + address of the vesting contract, to send the funds to the script + address. We also get the owner and beneficiary public key hashes. +

+ + + +

+ Next, we construct the transaction to deposit the funds into the vesting + contract. +

+ + + +

+ In this example, we construct the transaction to deposit the funds into + the vesting contract. We specify the script address of the vesting + contract, the amount to deposit, and the lockup period, owner, and + beneficiary of the funds. +

+ +

Finally, we sign and submit the transaction.

+ + + +

+ To execute this code, ensure you have defined blockfrost key in the + `.env` file. You can also define your wallet mnemonic in + `aiken-vesting/src/configs.ts` file. +

+ +

You can run the following command execute the deposit funds code:

+ + + +

+ Upon successful execution, you will receive a transaction hash. Save + this transaction hash for withdrawing the funds. +

+ +

+ Example of a{" "} + + successful deposit transaction + + . +

+ +

Withdraw funds

+ +

+ After the lockup period expires, the beneficiary can withdraw the funds + from the vesting contract. The owner can also withdraw the funds from + the vesting contract. +

+ +

+ First, let's look for the UTxOs containing the funds locked in the + vesting contract. +

+ + + +

+ In this example, we fetch the UTxOs containing the funds locked in the + vesting contract. We specify the transaction hash of the deposit + transaction. +

+ +

+ Like before, we prepare a few variables to be used in the transaction. + We get the wallet address and the UTXOs of the wallet. We also get the + script address of the vesting contract, to send the funds to the script + address. We also get the owner and beneficiary public key hashes. +

+ + + +

+ Next, we prepare the datum and the slot number to set the transaction + valid interval to be valid only after the slot. +

+ + (vestingUtxo.output.plutusData!); + +const invalidBefore = + unixTimeToEnclosingSlot( + Math.min(datum.fields[0].int as number, Date.now() - 15000), + SLOT_CONFIG_NETWORK.preprod + ) + 1; +`} + /> + +

+ In this example, we prepare the datum and the slot number to set the + transaction valid interval to be valid only after the slot. We get the + lockup period from the datum and set the transaction valid interval to + be valid only after the lockup period. +

+ +

+ Next, we construct the transaction to withdraw the funds from the + vesting contract. +

+ + + +

+ In this example, we construct the transaction to withdraw the funds from + the vesting contract. We specify the UTxO containing the funds locked in + the vesting contract, the script address of the vesting contract, the + wallet address to send the funds to, and the transaction valid interval. +

+ +

+ Finally, we sign and submit the transaction. Notice that since we are + unlocking fund from validator, partial sign has to be specified by + passing a `true` parameter into `wallet.signTx`. +

+ + + +

+ To execute this code, update `aiken-vesting/src/withdraw-fund.ts` with + the transaction hash from the deposit transaction. Ensure you have + defined blockfrost key in the `.env` file. You can also define your + wallet mnemonic in `aiken-vesting/src/configs.ts` file. +

+ +

Run the following command:

+ + + +

+ Example of a{" "} + + successful withdraw transaction + + . +

+ + ); +} diff --git a/apps/playground/src/pages/smart-contracts/vesting/index.tsx b/apps/playground/src/pages/smart-contracts/vesting/index.tsx index f0fee7c0..555d3e1a 100644 --- a/apps/playground/src/pages/smart-contracts/vesting/index.tsx +++ b/apps/playground/src/pages/smart-contracts/vesting/index.tsx @@ -8,12 +8,14 @@ import Codeblock from "~/components/text/codeblock"; import { metaVesting } from "~/data/links-smart-contracts"; import { InstallSmartContract } from "../common"; import VestingDepositFund from "./deposit-fund"; +import VestingFullTutorial from "./full-tutorial"; import VestingWithdrawFund from "./withdraw-fund"; const ReactPage: NextPage = () => { const sidebarItems = [ { label: "Deposit Fund", to: "depositFund" }, { label: "Withdraw Fund", to: "withdrawFund" }, + { label: "Full Tutorial", to: "tutorial" }, ]; let example = ``; @@ -85,6 +87,7 @@ const ReactPage: NextPage = () => { + ); diff --git a/apps/playground/src/pages/yaci/getting-started/setup.tsx b/apps/playground/src/pages/yaci/getting-started/setup.tsx index 0f35c330..1ed15397 100644 --- a/apps/playground/src/pages/yaci/getting-started/setup.tsx +++ b/apps/playground/src/pages/yaci/getting-started/setup.tsx @@ -37,7 +37,7 @@ function Left() { Yaci releases on Github {" "} and download the latest release. Under Assets, you will - find the Source code (zip) file. + find the yaci-devkit-version.zip file.

Extract the zip file to a folder on your system. This folder will be diff --git a/apps/playground/src/pages/yaci/getting-started/start.tsx b/apps/playground/src/pages/yaci/getting-started/start.tsx index 0feebd38..d808319b 100644 --- a/apps/playground/src/pages/yaci/getting-started/start.tsx +++ b/apps/playground/src/pages/yaci/getting-started/start.tsx @@ -26,10 +26,10 @@ function Left() {

To create a new devnet, run the following command from yaci-cli:

create-node -o --start`} />

- To create a new devnet with Conway era, run the following command from + To create a new devnet with Babbage era, run the following command from yaci-cli:

- create-node -o --era conway --start`} /> + create-node -o --era babbage --start`} />

To start a devnet with zero fees, run the following command from yaci-cli: