Getting Started
Try CashScript Online
To get started with writing CashScript smart contracts quickly, it is recommended to try out the CashScript Playground, a web application which lets you easily write and create contracts!
The Playground supports 'Mocknet', allowing you to create virtual UTXOs for development without having to get Testnet coins and set up a Testnet wallet.
The CashScript Playground is a great way to get started without doing any JavaScript/TypeScript coding to set up wallets, fetch balances and invoke contract functions. This way you can focus on learning just CashScript!
Here are the 5 simple steps for creating your first smart contract transaction with the Playground:
- Compile a contract, for example the default
TransferWithTimeout
contract. - Create a new contract in the 'New Contract' tab by providing the contract arguments.
- Add UTXOs to the smart contract address and the wallets used for testing.
- Next, go to the TransactionBuilder select the contract and the function to invoke
- Finally, specify the in- and outputs for the transaction and click 'Send'!
Creating a CashScript Contract
To get started coding locally we will use a code editor and learn how to work with the cashc
compiler to create CashScript contract artifacts.
Prerequisites
To write CashScript smart contracts locally you use a code editor. For the best developer experience, we recommend to use VS Code with the CashScript extension. This way it will automatically recognize .cash
files and offer highlighting and autocompletion.
- Basic familiarity with the command line
- Node.js installed
- A code editor (VS Code recommended)
To set up your CashScript developer environment, see the Syntax Highlighting guide.
Installing the CashScript compiler
The command line CashScript compiler cashc
can be installed from NPM.
npm install -g cashc
Writing your first contract
Open your code editor to start writing your first CashScript smart contract.
We can start from a basic TransferWithTimeout
smart contract. Create a new file TransferWithTimeout.cash
.
The TransferWithTimeout
contract takes in 3 contract arguments and has 2 contract functions: transfer
and timeout
.
pragma cashscript ^0.10.0;
contract TransferWithTimeout(pubkey sender, pubkey recipient, int timeout) {
// Allow the recipient to claim their received money
function transfer(sig recipientSig) {
require(checkSig(recipientSig, recipient));
}
// Allow the sender to reclaim their sent money after the timeout is reached
function timeout(sig senderSig) {
require(checkSig(senderSig, sender));
require(tx.time >= timeout);
}
}
There are some other examples available on the Examples page that can be used to take inspiration from. Further examples of the TypeScript and JavaScript integration can be found on GitHub.
Compiling your contract
The next step after writing your smart contract is using the command line compiler to create a contract artifact, so that it can be imported into the CashScript SDK.
cashc ./TransferWithTimeout.cash --output ./TransferWithTimeout.json
This will create an artifact file TransferWithTimeout.json
from your CashScript file. If you look at the bytecode
property on the artifact you will see the raw BCH script generated by the cashc
compiler:
OP_3 OP_PICK OP_0 OP_NUMEQUAL OP_IF OP_4 OP_ROLL OP_ROT OP_CHECKSIG OP_NIP OP_NIP OP_NIP OP_ELSE OP_3 OP_ROLL OP_1 OP_NUMEQUALVERIFY OP_3 OP_ROLL OP_SWAP OP_CHECKSIGVERIFY OP_SWAP OP_CHECKLOCKTIMEVERIFY OP_2DROP OP_1 OP_ENDIF
Creating a CashScript Transaction
After creating a contract artifact, we can now use the TypeScript SDK to initialise the smart contract and to invoke spending functions on the smart contract UTXOs. We'll continue with the TransferWithTimeout
artifact generated earlier.
The CashScript SDK is written in TypeScript meaning that you can either use TypeScript or vanilla JavaScript to use the SDK. It's recommended to use TypeScript for full type-safety of all you contract logic.
Installing the TypeScript SDK
The TypeScript SDK can be installed into your project with NPM. Note that CashScript is a pure ESM package.
npm install cashscript
Initialising a Contract
Now to initialise a contract we will import the ElectrumNetworkProvider
and Contract
classes from the CashScript SDK. We also need to import the contract artifact. Lastly, we need public keys from a generated key-pair to use as arguments for contract initialisation.
import { ElectrumNetworkProvider, Contract } from 'cashscript';
import artifact from './TransferWithTimeout.json' with { type: 'json' };
import { alicePub, bobPub } from './keys.js';
// Initialise a network provider for network operations
const provider = new ElectrumNetworkProvider('chipnet');
// Instantiate a new TransferWithTimeout contract
const contractArguments = [alicePub, bobPub, 100000n];
const options = { provider };
const contract = new Contract(artifact, contractArguments, options);
// Get the contract address and info about its balance
console.log("Contract address: " + contract.address);
console.log("Contract balance: " + await contract.getBalance());
console.log("Contract UTXOs: " + await contract.getUtxos());
For a code example of how to generate key-pairs with Libauth, see the CashScript Examples' common.ts
file where Alice and Bob's key-pairs are created.
Creating a Transaction
Lastly, to spend from the smart contract we've initialised, you need to make sure there is an actual contract balance on the smart contract address. In other words, we need to make sure there's at least one UTXO with the smart contract locking bytecode, so that we can spend from it!
import { ElectrumNetworkProvider, Contract, SignatureTemplate } from 'cashscript';
import { alicePub, bobPriv, bobPub } from './keys.js';
import artifact from './TransferWithTimeout.json';
// Initialise a network provider for network operations
const provider = new ElectrumNetworkProvider('chipnet');
// Instantiate a new TransferWithTimeout contract
const contractArguments = [alicePub, bobPub, 100000n];
const options = { provider };
const contract = new Contract(artifact, contractArguments, options);
// Call the transfer function with Bob's signature
// i.e. Bob claims the money that Alice has sent him
const transferDetails = await contract.functions
.transfer(new SignatureTemplate(bobPriv))
.to('bitcoincash:qrhea03074073ff3zv9whh0nggxc7k03ssh8jv9mkx', 10000n)
.send();
console.log(transferDetails);
Congrats 🎉! You've successfully created a transaction spending from a Bitcoin Cash smart contract!