Skip to content
Draft

v0.13 #370

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ea5496e
Update default VM target to BCH_2026
rkalis Oct 9, 2025
48d00d4
Update script limits & docs
rkalis Oct 9, 2025
381adb0
Use MockNetworkProvider in examples
rkalis Oct 9, 2025
7459a99
Add do-while loop to grammar and AST builder
rkalis Oct 14, 2025
ff82d56
Add checks for final require statement to loop
rkalis Oct 14, 2025
f62fe31
Add typechecking for do-while loop condition
rkalis Oct 14, 2025
9d29566
Add TODO for OP_NOT OP_NOT <> '' optimisation
rkalis Oct 14, 2025
6fc2d30
Add compilation / code generation logic for do-while loops
rkalis Oct 14, 2025
9e80444
Add number comparison negation optimisations + update release notes
rkalis Oct 16, 2025
223197a
Do not perform final-verify check inside loops
rkalis Oct 16, 2025
6847700
Add loops to docs
rkalis Oct 16, 2025
a868ebc
Bump version to 0.13.0-next.0
rkalis Oct 16, 2025
fede6c3
Fix loop scope not being closed bug
rkalis Nov 13, 2025
cd82956
Fix require statement detection inside loops and add tests for it
rkalis Nov 13, 2025
6fa4c07
Rework console.log handling for loops + add tests
rkalis Nov 13, 2025
74e9bfc
Update release notes
rkalis Nov 13, 2025
f9e7db3
Bump version to 0.13.0-next.1
rkalis Nov 13, 2025
822d566
Fix tests
rkalis Nov 13, 2025
a2f7fa8
Fix spellcheck
rkalis Nov 13, 2025
be22a80
update next docs (#385)
mr-zwets Jan 6, 2026
0a526d3
Refactor last remaining TODO in LibauthTemplate
rkalis Jan 6, 2026
ae6b48d
Replace pako with fflate
rkalis Jan 8, 2026
84307f4
Add bitshift, arithmetic shift, and invert operators
rkalis Jan 8, 2026
34c3e91
fix spellcheck
mr-zwets Jan 9, 2026
dd72761
small script-limits docs improvement
mr-zwets Jan 9, 2026
6c1f2a5
Update release notes for 0.13.0-next.2
rkalis Jan 13, 2026
817391f
Bump version to 0.13.0-next.2
rkalis Jan 13, 2026
4bda757
Improve testing-suite
rkalis Jan 13, 2026
0539a9b
Remove url-join devDependency from cashc
rkalis Jan 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@
"locktimes",
"lokad",
"lshift",
"LSHIFTNUM",
"LSHIFTBIN",
"mecenas",
"meep",
"minimaldata",
Expand Down Expand Up @@ -154,6 +156,8 @@
"ripemd",
"rosco",
"rshift",
"RSHIFTBIN",
"RSHIFTNUM",
"sablier",
"satoshis",
"sats",
Expand Down Expand Up @@ -221,6 +225,7 @@
"cherian",
"CSCriptNum",
"docu",
"fflate",
"fundme",
"getblockcount",
"getrawtransaction",
Expand Down
2 changes: 1 addition & 1 deletion examples/announcement.cash
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma cashscript ^0.12.0;
pragma cashscript ^0.13.0;

/* This is a contract showcasing covenants outside of regular transactional use.
* It enforces the contract to make an "announcement" on Memo.cash, and send the
Expand Down
11 changes: 9 additions & 2 deletions examples/announcement.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import { Contract, ElectrumNetworkProvider, Output, TransactionBuilder } from 'cashscript';
import { Contract, Output, randomUtxo, TransactionBuilder } from 'cashscript';
import { compileFile } from 'cashc';
import { stringify } from '@bitauth/libauth';
import { URL } from 'url';
import { MockNetworkProvider } from 'cashscript/dist';

// Compile the Announcement contract to an artifact object
const artifact = compileFile(new URL('announcement.cash', import.meta.url));

// Initialise a network provider for network operations on MAINNET
const addressType = 'p2sh20';
const provider = new ElectrumNetworkProvider();

// Once you're ready to send transactions on a real network (like chipnet or mainnet), use the ElectrumNetworkProvider
// const provider = new ElectrumNetworkProvider();
const provider = new MockNetworkProvider();

// Instantiate a new contract using the compiled artifact and network provider
// AND providing the constructor parameters (none)
const contract = new Contract(artifact, [], { provider, addressType });

// Add a mock UTXO to the mock network provider
provider.addUtxo(contract.address, randomUtxo());

// Get contract balance & output address + balance
console.log('contract address:', contract.address);
const contractUtxos = await contract.getUtxos();
Expand Down
4 changes: 2 additions & 2 deletions examples/hodl_vault.cash
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma cashscript ^0.12.0;
pragma cashscript ^0.13.0;

// This contract forces HODLing until a certain price target has been reached
// A minimum block is provided to ensure that oracle price entries from before this block are disregarded
Expand All @@ -11,7 +11,7 @@ contract HodlVault(
int minBlock,
int priceTarget
) {
function spend(sig ownerSig, datasig oracleSig, bytes oracleMessage) {
function spend(sig ownerSig, datasig oracleSig, bytes8 oracleMessage) {
// message: { blockHeight, price }
bytes4 blockHeightBin, bytes4 priceBin = oracleMessage.split(4);
int blockHeight = int(blockHeightBin);
Expand Down
10 changes: 7 additions & 3 deletions examples/hodl_vault.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { stringify } from '@bitauth/libauth';
import { Contract, SignatureTemplate, ElectrumNetworkProvider, TransactionBuilder, Output } from 'cashscript';
import { Contract, SignatureTemplate, TransactionBuilder, Output, MockNetworkProvider, randomUtxo } from 'cashscript';
import { compileFile } from 'cashc';
import { URL } from 'url';

Expand All @@ -14,14 +14,18 @@ import {
// Compile the HodlVault contract to an artifact object
const artifact = compileFile(new URL('hodl_vault.cash', import.meta.url));

// Initialise a network provider for network operations on CHIPNET
const provider = new ElectrumNetworkProvider('chipnet');
// Once you're ready to send transactions on a real network (like chipnet or mainnet), use the ElectrumNetworkProvider
// const provider = new ElectrumNetworkProvider();
const provider = new MockNetworkProvider();

// Instantiate a new contract using the compiled artifact and network provider
// AND providing the constructor parameters
const parameters = [alicePub, oraclePub, 100000n, 30000n];
const contract = new Contract(artifact, parameters, { provider });

// Add a mock UTXO to the mock network provider
provider.addUtxo(contract.address, randomUtxo());

// Get contract balance & output address + balance
console.log('contract address:', contract.address);
const contractUtxos = await contract.getUtxos();
Expand Down
2 changes: 1 addition & 1 deletion examples/mecenas.cash
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma cashscript ^0.12.0;
pragma cashscript ^0.13.0;

/* This is an unofficial CashScript port of Licho's Mecenas contract. It is
* not compatible with Licho's EC plugin, but rather meant as a demonstration
Expand Down
10 changes: 7 additions & 3 deletions examples/mecenas.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { stringify } from '@bitauth/libauth';
import { Contract, ElectrumNetworkProvider, Output, TransactionBuilder } from 'cashscript';
import { Contract, MockNetworkProvider, Output, randomUtxo, TransactionBuilder } from 'cashscript';
import { compileFile } from 'cashc';
import { URL } from 'url';

Expand All @@ -9,15 +9,19 @@ import { aliceAddress, alicePkh, bobPkh } from './common.js';
// Compile the Mecenas contract to an artifact object
const artifact = compileFile(new URL('mecenas.cash', import.meta.url));

// Initialise a network provider for network operations on CHIPNET
const provider = new ElectrumNetworkProvider('chipnet');
// Once you're ready to send transactions on a real network (like chipnet or mainnet), use the ElectrumNetworkProvider
// const provider = new ElectrumNetworkProvider();
const provider = new MockNetworkProvider();

// Instantiate a new contract using the compiled artifact and network provider
// AND providing the constructor parameters:
// (recipient: alicePkh, funder: bobPkh, pledge: 10000)
const pledgeAmount = 10_000n;
const contract = new Contract(artifact, [alicePkh, bobPkh, pledgeAmount], { provider });

// Add a mock UTXO to the mock network provider
provider.addUtxo(contract.address, randomUtxo());

// Get contract balance & output address + balance
console.log('contract address:', contract.address);
const contractUtxos = await contract.getUtxos();
Expand Down
2 changes: 1 addition & 1 deletion examples/mecenas_locktime.cash
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma cashscript ^0.12.0;
pragma cashscript ^0.13.0;

// This is an experimental contract for a more "streaming" Mecenas experience
// Completely untested, just a concept
Expand Down
2 changes: 1 addition & 1 deletion examples/p2pkh.cash
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pragma cashscript ^0.12.0;
pragma cashscript ^0.13.0;

contract P2PKH(bytes20 pkh) {
// Require pk to match stored pkh and signature to match
Expand Down
12 changes: 8 additions & 4 deletions examples/p2pkh.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { URL } from 'url';
import { compileFile } from 'cashc';
import { ElectrumNetworkProvider, Contract, SignatureTemplate, TransactionBuilder } from 'cashscript';
import { Contract, SignatureTemplate, TransactionBuilder, MockNetworkProvider, randomUtxo } from 'cashscript';
import { stringify } from '@bitauth/libauth';

// Import Alice's keys from common.ts
Expand All @@ -9,13 +9,17 @@ import { alicePkh, alicePriv, aliceAddress, alicePub } from './common.js';
// Compile the P2PKH contract to an artifact object
const artifact = compileFile(new URL('p2pkh.cash', import.meta.url));

// Initialise a network provider for network operations on CHIPNET
const provider = new ElectrumNetworkProvider('chipnet');
// Once you're ready to send transactions on a real network (like chipnet or mainnet), use the ElectrumNetworkProvider
// const provider = new ElectrumNetworkProvider();
const provider = new MockNetworkProvider();

// Instantiate a new contract using the compiled artifact and network provider
// AND providing the constructor parameters (pkh: alicePkh)
const contract = new Contract(artifact, [alicePkh], { provider });

// Add a mock UTXO to the mock network provider
provider.addUtxo(contract.address, randomUtxo());

// Get contract balance & output address + balance
console.log('contract address:', contract.address);
const contractUtxos = await contract.getUtxos();
Expand Down Expand Up @@ -52,4 +56,4 @@ if (changeAmount > 1000n) transactionBuilder.addOutput(changeOutput);

const tx = await transactionBuilder.send();

console.log('transaction details:', stringify(tx));
console.log('transaction details:', stringify(tx));
10 changes: 7 additions & 3 deletions examples/p2pkh.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { stringify } from '@bitauth/libauth';
import { compileFile } from 'cashc';
import { ElectrumNetworkProvider, SignatureTemplate, Contract, TransactionBuilder, Output } from 'cashscript';
import { SignatureTemplate, Contract, TransactionBuilder, Output, MockNetworkProvider, randomUtxo } from 'cashscript';
import { URL } from 'url';

// Import Alice's keys from common.ts
Expand All @@ -9,13 +9,17 @@ import { alicePkh, alicePriv, aliceAddress, alicePub } from './common.js';
// Compile the P2PKH contract to an artifact object
const artifact = compileFile(new URL('p2pkh.cash', import.meta.url));

// Initialise a network provider for network operations on CHIPNET
const provider = new ElectrumNetworkProvider('chipnet');
// Once you're ready to send transactions on a real network (like chipnet or mainnet), use the ElectrumNetworkProvider
// const provider = new ElectrumNetworkProvider();
const provider = new MockNetworkProvider();

// Instantiate a new contract using the compiled artifact and network provider
// AND providing the constructor parameters (pkh: alicePkh)
const contract = new Contract(artifact, [alicePkh], { provider });

// Add a mock UTXO to the mock network provider
provider.addUtxo(contract.address, randomUtxo());

// Get contract balance & output address + balance
console.log('contract address:', contract.address);
const contractUtxos = await contract.getUtxos();
Expand Down
6 changes: 3 additions & 3 deletions examples/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "cashscript-examples",
"private": true,
"version": "0.12.1",
"version": "0.13.0-next.2",
"description": "Usage examples of the CashScript SDK",
"main": "p2pkh.js",
"type": "module",
Expand All @@ -13,8 +13,8 @@
"dependencies": {
"@bitauth/libauth": "^3.1.0-next.8",
"@types/node": "^22.17.0",
"cashc": "^0.12.1",
"cashscript": "^0.12.1",
"cashc": "^0.13.0-next.2",
"cashscript": "^0.13.0-next.2",
"eslint": "^8.56.0",
"typescript": "^5.9.2"
}
Expand Down
2 changes: 2 additions & 0 deletions examples/testing-suite/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
**/dist/
**/node_modules/
25 changes: 25 additions & 0 deletions examples/testing-suite/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# CashScript Testing Suite

This is an example project to demonstrate how to write and compile CashScript contracts and test them using the CashScript SDK and Vitest.

## Writing a CashScript contract

We have included two simple example contracts in the `contracts/` directory that can be used as a starting point to write your own contracts. The contracts demonstrate logs, require statements and transaction signatures.

## Compiling the contracts

We have included a task to compile the contracts in the `tasks/` directory called `compile.ts`. This task will compile all the contracts in the `contracts/` directory and save the artifacts in the `artifacts/` directory. This includes both the JSON and TypeScript artifacts. It is recommended to use the TypeScript artifacts for proper type-safety.

You can run the task with `yarn compile`.

## Running the tests

We have included test files in the `test/` directory, which test the expected functionality of the contracts. For key management, we have included a utility file in the `utils/` directory which exports testing keys for Alice and Bob.

You can run the tests with `yarn test`.

## Next steps

Once you're getting comfortable writing, compiling and testing CashScript contracts, you can copy the `testing-suite` directory into your own project to use as a starting point. From there you can start writing more complex contracts and integrate them into full applications.

We recommend checking out the [CashScript SDK documentation](https://cashscript.org/docs/sdk/) for more information on how to use the CashScript SDK, and the specific section on the [testing setup](https://cashscript.org/docs/sdk/testing-setup) for more information on how to test your contracts.
12 changes: 6 additions & 6 deletions examples/testing-suite/artifacts/example.artifact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ export default {
},
],
bytecode: 'OP_1 OP_NUMEQUAL',
source: 'contract Example() {\n function test(int value) {\n console.log(value, \'test\');\n require(value == 1, \'Wrong value passed\');\n }\n}\n',
source: 'contract Example() {\n function test(int value) {\n console.log(value, "test");\n require(value == 1, "Wrong value passed");\n }\n}\n',
debug: {
bytecode: '007a519c',
sourceMap: '4:12:4:17;;:21::22;:12:::1',
bytecode: '519c',
sourceMap: '4:21:4:22;:4::46:1',
logs: [
{
ip: 0,
Expand All @@ -33,15 +33,15 @@ export default {
],
requires: [
{
ip: 4,
ip: 2,
line: 4,
message: 'Wrong value passed',
},
],
},
compiler: {
name: 'cashc',
version: '0.11.0',
version: '0.13.0-next.2',
},
updatedAt: '2025-04-11T09:08:09.750Z',
updatedAt: '2026-01-13T10:40:29.996Z',
} as const;
4 changes: 2 additions & 2 deletions examples/testing-suite/artifacts/example.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
},
"compiler": {
"name": "cashc",
"version": "0.12.0"
"version": "0.13.0-next.2"
},
"updatedAt": "2025-12-09T10:19:09.338Z"
"updatedAt": "2026-01-13T10:40:29.996Z"
}
63 changes: 63 additions & 0 deletions examples/testing-suite/artifacts/transfer_with_timeout.artifact.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
export default {
contractName: 'TransferWithTimeout',
constructorInputs: [
{
name: 'sender',
type: 'pubkey',
},
{
name: 'recipient',
type: 'pubkey',
},
{
name: 'timeout',
type: 'int',
},
],
abi: [
{
name: 'transfer',
inputs: [
{
name: 'recipientSig',
type: 'sig',
},
],
},
{
name: 'timeout',
inputs: [
{
name: 'senderSig',
type: 'sig',
},
],
},
],
bytecode: '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',
source: 'pragma cashscript ^0.13.0;\n\ncontract TransferWithTimeout(\n pubkey sender,\n pubkey recipient,\n int timeout\n) {\n // Require recipient\'s signature to match\n function transfer(sig recipientSig) {\n require(checkSig(recipientSig, recipient));\n }\n\n // Require timeout time to be reached and sender\'s signature to match\n function timeout(sig senderSig) {\n require(checkSig(senderSig, sender));\n require(tx.time >= timeout);\n }\n}\n',
debug: {
bytecode: '5379009c63547a7bac77777767537a519d537a7cad7cb16d5168',
sourceMap: '9:4:11:5;;;;;10:25:10:37;;:39::48;:8::51:1;9:4:11:5;;;;14::17::0;;;;15:25:15:34;;:36::42;:8::45:1;16:27:16:34:0;:8::36:1;14:4:17:5;;3:0:18:1',
logs: [],
requires: [
{
ip: 12,
line: 10,
},
{
ip: 23,
line: 15,
},
{
ip: 25,
line: 16,
},
],
},
compiler: {
name: 'cashc',
version: '0.13.0-next.2',
},
updatedAt: '2026-01-13T10:40:30.007Z',
} as const;
Loading