Hello World Smart Contract
2025-02-21: Missing steps for lock and unlock
Requirements
A Cup of Coffee
The Aiken Hello World Example (You need to update the smart contract name to avoid getting the
already exists
message from Anvil API.)The Smart Contract name should be in this format:
your_org/hello-world
See the official documentation: Aiken Hello World
An Anvil API Key (you can use the one provided in this document to access
preprod
)customer.json
with 100ADA, you can use the CLI tool to generate the wallet, then send funds from the faucet to it. (TODO: Added wallet cli link)
Objectives
Interact with any Smart Contracts using Anvil API
Objectives
Upload Blueprint
Deploy Smart Contract On-Chain
Update/Delete Blueprint
Hello World Lock & Unlock ADA
Get a
jsonSchema
from your blueprint to get types for the language you use.See below for the code in one file (
full.ts
)
Aiken Smart Contract
Helper Functions
Function to extract validator hashes
from a blueprint
function getValidators(validators: typeof blueprint.validators) {
return [...validators.reduce((a, b) => a.set(b.hash, b) && a, new Map<string, typeof blueprint.validators[number]>()).values()];
}
Prerequisites
You need to load your Blueprint like this:
import blueprint from "./hello-world/plutus.json" with {type: "json"};
The wallet used in this guide is loaded like this:
You also need the CSL imports and Buffer for that to work, it is only the case when you are using the wallet in the backend.
import { Buffer } from "node:buffer";
import { FixedTransaction, PrivateKey } from "npm:@emurgo/[email protected]"; // only required due to signing in the backend.
import customer from "./customer.json" with {type: "json"}; // Optional, this guide is using this approach.
You can use any wallet, like the one in your browser or with weld, but to limit the external steps and streamline the flow. This guide uses the wallet directly in the backend. You can take a look at the signing transaction document to see how to use the browser wallet.
The api key used is this one:
const X_API_KEY = "testnet_EyrkvCWDZqjkfLSe1pxaF0hXxUcByHEhHuXIBjt9";
Payload
To upload your validator on Anvil Backend
Benefit of doing so, will reduce the complexity and steps to interact with your smart contract. as it will be store directly in the backend. Your API Key is link with your Blueprint and will let you update and delete it if needed.
Deploy the Smart Contract On-Chain
const payload = {
changeAddress: "addr_test...",
message: "Smart contract deployed using anvil API",
outputs: getValidators(blueprint.validators).map(validator => ({
address: scriptAddresses[validator.hash],
datum: {
type: "script",
hash: validator.hash
}
}))
}
scriptAddresses
:Key = Validator Hash
Value = Address of the Smart Contract (Enterprise Address)
Steps
Step 1 - Upload Blueprint
Upload your blueprint (plutus.json
) to Anvil Backend
Create Blueprint
const blueprintRegistration = await fetch("https://preprod.api.ada-anvil.app/v2/services/blueprints",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": X_API_KEY
},
body: JSON.stringify({
blueprint
})
});
const uploadedBlueprint = await blueprintRegistration.json();
console.debug(JSON.stringify(uploadedBlueprint, null, 2))
const { scriptAddresses } = uploadedBlueprint;
scriptAddresses
: Needed for Step #2
This API Call is an
upsert
, so if you forget thescriptAddresses
or need to update your blueprint, you can reuse the same call.
Tip: Once registered, if you need to update the name without changing the smart contract code or logic, you can safely delete the blueprint using the former name and then re-upload it.
Step 2 - Deploy Smart Contract
You need a valid Cardano wallet with some ADA on it (100ADA should be more than enough)Wallet CLI
Deploy the smart contract on-chain in order to get the reference UTXO
Payload to build the transaction:
const contract = {
changeAddress: customer.base_address_preprod,
message: "Smart contract deployed using anvil API",
outputs: getValidators(blueprint.validators).map(validator => ({
address: scriptAddresses[validator.hash],
datum: {
type: "script",
hash: validator.hash,
}
})),
};
Create the transaction
const contractDeployed = await fetch(
`https://preprod.api.ada-anvil.app/v2/services/transactions/build`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": X_API_KEY
},
body: JSON.stringify(contract),
}
);
const contractToDeployTransaction = await contractDeployed.json();
console.log(JSON.stringify(contractToDeployTransaction));
Sign and Submit the transaction
The signature process uses CSL for simplicity. You can use your wallet to retrieve the signature
a100...
(take a look to the signature documentation for more information TODO, link Internal URL)
// Sign the transaction using CSL.
const txToSubmitOnChain = FixedTransaction.from_bytes(
Buffer.from(contractToDeployTransaction.complete, "hex")
);
txToSubmitOnChain.sign_and_add_vkey_signature(
PrivateKey.from_bech32(customer.skey)
);
const urlSubmit = "https://preprod.api.ada-anvil.app/v2/services/transactions/submit";
const submitted = await fetch(urlSubmit, {
method: "POST",
body: JSON.stringify({
signatures: [], // no signature required as it is part of the `txToSubmitOnChain`.
transaction: txToSubmitOnChain.to_hex(),
}),
headers: {
"Content-Type": "application/json",
"X-Api-Key": X_API_KEY,
},
});
const response = await submitted.json();
console.debug(response);
const { txHash } = response;
Step 3 - Link Blueprint and UTXO
Update blueprint to link references to deployed validators.
const response = await fetch(`https://preprod.api.ada-anvil.app/v2/services/blueprints`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": X_API_KEY
},
body: JSON.stringify({
blueprint,
refs: getValidators(blueprint.validators).reduce((a, b, index) => {
a[b.hash] = { txHash, index };
return a;
}, {} as Record<string, { txHash: string, index: number }>),
})
});
const updatedBlueprint = await response.json()
console.log(updatedBlueprint);
Conclusion
From here you have uploaded your blueprint and linked the reference UTXO on-chain and in Anvil Backend.
The next step is to interact with the hello-world
Smart Contract (Lock & Unlock ADA)
Full Example
Usage (Hello World Lock/Unlock)
Lock Funds
Payload
TODO: Explain the JSON below
const input = {
changeAddress: customer.base_address_preprod,
message: "Locking my fortune using anvil API",
outputs: [
{
address: await getScriptAddr(hash), // script address of the first validator
lovelace: 2_000_000, // 1 ADA = 1_000_000 Lovelace
datum: {
type: "inline",
value: {
owner: customer.key_hash // Only the Customer will be able to unlock the funds
},
shape: {
validatorHash: hash,
purpose: "spend"
}
}
}
],
};
Unlock Funds
Payload
TODO: Explain the JSON below
const input = {
changeAddress: customer.base_address_preprod,
message: "Unlock my fortune using anvil API",
scriptInteractions: [
{
hash,
purpose: "spend",
// This Output ref and index is the UTXO locked at the previous step.
outputRef: {
txHash: "7ac8f6922d51ffe2980e73c57c985b3906795440b5a565cc8806899dc88b110e", // ACTION: Replace with your txHash
index: 0, // ACTION: Replace with you index
},
redeemer: { // Aka. Smart contract Parameters
type: "json",
value: {
msg: Buffer.from("Bonjour Monde!!", "utf8").toString("hex") // ACTION: Replace with your String
}
}
}
],
requiredSigners: [customer.key_hash], // Aka. extra_signatories
};
Full Example - Lock Fund
Full Example - Unlock Fund
Last updated
Was this helpful?