update hello world codes

This commit is contained in:
Hong Jing (Jingles) 2024-11-27 13:12:50 +08:00
parent c3b07dfe83
commit 0b007b4405
8 changed files with 198 additions and 171 deletions

View File

@ -2,3 +2,5 @@ artifacts/
build/
*.sk
*.addr
node_modules
.DS_Store

View File

@ -1,33 +1,54 @@
# Hello, World!
An example of an Hello, World! contract using Aiken and [Lucid](https://github.com/spacebudz/lucid).
An example of an Hello, World! contract using Aiken and [Mesh](https://meshjs.dev/).
See the [full tutorial on aiken-lang.org](https://aiken-lang.org/getting-started/hello-world).
See the [full tutorial on aiken-lang.org](https://aiken-lang.org/example--hello-world/end-to-end/mesh).
## Building
## Setup
### Building
```
aiken build
```
## Generating Credentials
### Initializing workspace
```
deno run --allow-net --allow-write generate-credentials.ts
npm init -y
npm install @meshsdk/core tsx
```
## Locking Funds
### Setup environment variables
```
export BLOCKFROST_PROJECT_ID=preprod...
```
## Usage
### Generating Credentials
```
npx tsx generate-credentials.ts
```
### Locking Funds
> **Warning** Require `BLOCKFROST_API_KEY` environment variable to be set.
```
deno run --allow-net --allow-read --allow-env hello_world-lock.ts
npx tsx lock.ts
```
## Unlocking Funds
Successful transaction hash: `bfa4818940831dff961a2f097e1aef9bf626de744fd96abfd2be7d6b61afb270` (preprod)
### Unlocking Funds
> **Warning** Require `BLOCKFROST_API_KEY` environment variable to be set.
```
deno run --allow-net --allow-read --allow-env hello_world-unlock.ts TRANSACTION_ID_FROM_LOCK
npx tsx unlock.ts TRANSACTION_ID_FROM_LOCK
```
Successful transaction hash: `1f8f3abac70c3a71c6aa943b4b9a6ac002e63a69225eb59305c3cd663cda3dd7` (preprod)

View File

@ -0,0 +1,54 @@
import fs from "node:fs";
import {
BlockfrostProvider,
MeshTxBuilder,
MeshWallet,
serializePlutusScript,
UTxO,
} from "@meshsdk/core";
import { applyParamsToScript } from "@meshsdk/core-csl";
import blueprint from "./plutus.json";
const blockchainProvider = new BlockfrostProvider(process.env.BLOCKFROST_PROJECT_ID!);
// wallet for signing transactions
export const wallet = new MeshWallet({
networkId: 0,
fetcher: blockchainProvider,
submitter: blockchainProvider,
key: {
type: "root",
bech32: fs.readFileSync("me.sk").toString(),
},
});
export function getScript() {
const scriptCbor = applyParamsToScript(
blueprint.validators[0].compiledCode,
[]
);
const scriptAddr = serializePlutusScript(
{ code: scriptCbor, version: "V3" },
).address;
return { scriptCbor, scriptAddr };
}
// reusable function to get a transaction builder
export function getTxBuilder() {
return new MeshTxBuilder({
fetcher: blockchainProvider,
submitter: blockchainProvider,
});
}
// reusable function to get a UTxO by transaction hash
export async function getUtxoByTxHash(txHash: string): Promise<UTxO> {
const utxos = await blockchainProvider.fetchUTxOs(txHash);
if (utxos.length === 0) {
throw new Error("UTxO not found");
}
return utxos[0];
}

View File

@ -1,14 +1,16 @@
import { Lucid } from "https://deno.land/x/lucid@0.8.3/mod.ts";
const lucid = await Lucid.new(undefined, "Preview");
const privateKey = lucid
.utils
.generatePrivateKey();
await Deno.writeTextFile("key.sk", privateKey);
const address = await lucid
.selectWalletFromPrivateKey(privateKey)
.wallet
.address();
await Deno.writeTextFile("key.addr", address);
import { MeshWallet } from '@meshsdk/core';
import fs from 'node:fs';
const secret_key = MeshWallet.brew(true) as string;
fs.writeFileSync('me.sk', secret_key);
const wallet = new MeshWallet({
networkId: 0,
key: {
type: 'root',
bech32: secret_key,
},
});
fs.writeFileSync('me.addr', wallet.getUnusedAddresses()[0]);

View File

@ -1,72 +0,0 @@
import {
Blockfrost,
Constr,
Data,
fromHex,
Lucid,
SpendingValidator,
toHex,
TxHash,
} from "https://deno.land/x/lucid@0.8.3/mod.ts";
import * as cbor from "https://deno.land/x/cbor@v1.4.1/index.js";
const lucid = await Lucid.new(
new Blockfrost(
"https://cardano-preview.blockfrost.io/api/v0",
Deno.env.get("BLOCKFROST_API_KEY"),
),
"Preview",
);
lucid.selectWalletFromPrivateKey(await Deno.readTextFile("./key.sk"));
const validator = await readValidator();
// --- Supporting functions
async function readValidator(): Promise<SpendingValidator> {
const validator = JSON
.parse(await Deno.readTextFile("plutus.json"))
.validators[0];
return {
type: "PlutusV2",
script: toHex(cbor.encode(fromHex(validator.compiledCode))),
};
}
const publicKeyHash = lucid.utils
.getAddressDetails(await lucid.wallet.address())
.paymentCredential
?.hash;
const datum = Data.to(new Constr(0, [publicKeyHash]));
const txHash = await lock(1000000n, { into: validator, owner: datum });
await lucid.awaitTx(txHash);
console.log(`1 tADA locked into the contract at:
Tx ID: ${txHash}
Datum: ${datum}
`);
// --- Supporting functions
async function lock(
lovelace: bigint,
{ into, owner }: { into: SpendingValidator; owner: string },
): Promise<TxHash> {
const contractAddress = lucid.utils.validatorToAddress(into);
const tx = await lucid
.newTx()
.payToContract(contractAddress, { inline: owner }, { lovelace })
.complete();
const signedTx = await tx
.sign()
.complete();
return signedTx.submit();
}

View File

@ -1,76 +0,0 @@
import {
Blockfrost,
Constr,
Data,
fromHex,
Lucid,
OutRef,
Redeemer,
SpendingValidator,
toHex,
TxHash,
utf8ToHex,
} from "https://deno.land/x/lucid@0.8.3/mod.ts";
import * as cbor from "https://deno.land/x/cbor@v1.4.1/index.js";
const lucid = await Lucid.new(
new Blockfrost(
"https://cardano-preview.blockfrost.io/api/v0",
Deno.env.get("BLOCKFROST_API_KEY"),
),
"Preview",
);
lucid.selectWalletFromPrivateKey(await Deno.readTextFile("./key.sk"));
const validator = await readValidator();
const utxo: OutRef = { txHash: Deno.args[0], outputIndex: 0 };
const redeemer = Data.to(new Constr(0, [utf8ToHex("Hello, World!")]));
const unlockTxHash = await unlock(utxo, {
from: validator,
using: redeemer,
});
await lucid.awaitTx(unlockTxHash);
console.log(`1 tADA unlocked from the contract
Tx ID: ${unlockTxHash}
Redeemer: ${redeemer}
`);
// --- Supporting functions
async function unlock(
ref: OutRef,
{ from, using }: { from: SpendingValidator; using: Redeemer },
): Promise<TxHash> {
const [utxo] = await lucid.utxosByOutRef([ref]);
const tx = await lucid
.newTx()
.collectFrom([utxo], using)
.addSigner(await lucid.wallet.address())
.attachSpendingValidator(from)
.complete();
const signedTx = await tx
.sign()
.complete();
return signedTx.submit();
}
async function readValidator(): Promise<SpendingValidator> {
const validator = JSON
.parse(await Deno.readTextFile("plutus.json"))
.validators[0];
return {
type: "PlutusV2",
script: toHex(cbor.encode(fromHex(validator.compiledCode))),
};
}

View File

@ -0,0 +1,39 @@
import { Asset, deserializeAddress, mConStr0 } from "@meshsdk/core";
import { getScript, getTxBuilder, wallet } from "./common";
async function main() {
// these are the assets we want to lock into the contract
const assets: Asset[] = [
{
unit: "lovelace",
quantity: "1000000",
},
];
// get utxo and wallet address
const utxos = await wallet.getUtxos();
const walletAddress = (await wallet.getUsedAddresses())[0];
const { scriptAddr } = getScript();
// hash of the public key of the wallet, to be used in the datum
const signerHash = deserializeAddress(walletAddress).pubKeyHash;
// build transaction with MeshTxBuilder
const txBuilder = getTxBuilder();
await txBuilder
.txOut(scriptAddr, assets) // send assets to the script address
.txOutDatumHashValue(mConStr0([signerHash])) // provide the datum where `"constructor": 0`
.changeAddress(walletAddress) // send change back to the wallet address
.selectUtxosFrom(utxos)
.setNetwork('preprod')
.complete();
const unsignedTx = txBuilder.txHex;
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);
console.log(`1 tADA locked into the contract at Tx ID: ${txHash}`);
}
main();

View File

@ -0,0 +1,57 @@
import {
deserializeAddress,
mConStr0,
stringToHex,
} from "@meshsdk/core";
import { getScript, getTxBuilder, getUtxoByTxHash, wallet } from "./common";
async function main() {
// get utxo, collateral and address from wallet
const utxos = await wallet.getUtxos();
const walletAddress = (await wallet.getUsedAddresses())[0];
const collateral = (await wallet.getCollateral())[0];
const { scriptCbor } = getScript();
// hash of the public key of the wallet, to be used in the datum
const signerHash = deserializeAddress(walletAddress).pubKeyHash;
// redeemer value to unlock the funds
const message = "Hello, World!";
// get the utxo from the script address of the locked funds
const txHashFromDesposit = process.argv[2];
const scriptUtxo = await getUtxoByTxHash(txHashFromDesposit);
// build transaction with MeshTxBuilder
const txBuilder = getTxBuilder();
await txBuilder
.spendingPlutusScript("V3") // we used plutus v3
.txIn( // spend the utxo from the script address
scriptUtxo.input.txHash,
scriptUtxo.input.outputIndex,
scriptUtxo.output.amount,
scriptUtxo.output.address
)
.txInScript(scriptCbor)
.txInRedeemerValue(mConStr0([stringToHex(message)])) // provide the required redeemer value `Hello, World!`
.txInDatumValue(mConStr0([signerHash])) // only the owner of the wallet can unlock the funds
.requiredSignerHash(signerHash)
.changeAddress(walletAddress)
.txInCollateral(
collateral.input.txHash,
collateral.input.outputIndex,
collateral.output.amount,
collateral.output.address
)
.selectUtxosFrom(utxos)
.setNetwork('preprod')
.complete();
const unsignedTx = txBuilder.txHex;
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);
console.log(`1 tADA unlocked from the contract at Tx ID: ${txHash}`);
}
main();