Skip to main content

Migration Notes

v0.12 to v0.14​

Version 0.14.0-beta.1 is a major protocol and workflow upgrade, not only a syntax update. Existing stateless contracts can often be recompiled directly, but existing stateful deployments are not layout-compatible with the new self-pinned data/vmap/chunk protocol. Recompile, audit the artifact, and deploy a new category.

Runtime and project requirements​

  • Use Node.js 22 or newer and the same 0.14.0-beta.1 version of all six packages: solidc, solidcash, @solidcash/utils, @solidcash/testing, @solidcash/solidhat and @solidcash/create-solidhat. They ship as ESM only.
  • SolidHat projects use solidcash.config.ts (with defineConfig from @solidcash/solidhat/config), the solidhat CLI, and artifacts under artifacts/solidcash; a project on plain @solidcash/testing uses its solidcash CLI. New projects set compiler: { evmCompat: true }. solidhat init --from-hardhat (solidcash init --from-hardhat without SolidHat) writes solidcash.config.ts from the nearest Hardhat config; it does not edit the Hardhat file.

Stateful storage and deployment​

  • Stateful contracts now use a category-salted, self-pinned P2SH32 address and a minting master NFT. Treat both the category and the locking bytecode as deployment identity.
  • Ordinary fields use one or more indexed data NFTs. Dynamic strings/bytes and eligible T[] values use a length header plus 120-byte chunks. Every mapping is a sorted verified mapping with a HEAD node; large mapping values use a separate 126-byte continuation format.
  • Eligible unbounded arrays select the dense chunk backend by default. Code which relied on a bare T[] behaving as a sparse integer mapping should declare mapping(uint256 => T) or compile deliberately with chunkedArrays: false. Native bounded non-packed arrays remain collection-backed; compatibility-mode bounded arrays may become packed.
  • external state variables are isolated into dedicated data NFTs. State layout, array backend, compiler options, and declaration order are deployment compatibility concerns.
  • Prefer ContractFactory.deploy(...) with a connected signer. The explicit low-level form is StatefulContract.deploy(artifact, constructorArgs, options), not a single object containing the artifact. Supply funding, change, and initial commitment state deliberately.

Calls, events, and lifecycle​

  • Cross-contract calls are composed co-spends, not synchronous account calls. A call target is an address, the callee master's locking bytecode, not a category id. Register deployed targets through the SDK's external registry and let auto-derivation construct the callee blocks and return-event outputs.
  • msg.sender is the calling contract's address, or tx.origin (the first non-token P2PKH input) for a direct spend. The compiler warns on every read of msg.sender or tx.origin; authorize with checkSig instead.
  • Event records are immutable NFT commitments and are queried through receipts, filters, or listeners. Do not assume an EVM log bloom or runtime revert-data transport.
  • Native upgrade moves the master to new bytecode while preserving the category. Data NFTs are re-minted on the new bytecode, the satoshi and token containers move with the master, and mapping entries move one per transaction through a migrateRecords function. Values kept in chunk NFTs do not migrate yet, and the SDK refuses an upgrade that would strand one. The compiler still refuses an upgrade that runs as a message-bus route in a contract with state variables. A native upgrade is different from a proxy deployment, which keeps its address.
  • selfdestruct, child deployment, and split/merge operations require their dedicated SDK builders and explicit funding/recipient/thread plans.
  • Experimental in 0.14.0-beta.1, outside the stable compatibility promise: calls that mutate another contract's state, custom delegate forwarding beyond the built-in upgrades.deployProxy profile and upgrades.upgradeProxy, message-bus kernel composition (messageBus.compose, sc.batch([...])), the framed convention (composition: 'framed'), and Solidity shapes outside the compatibility manifest.

ABI and Solidity imports​

  • Native selectors remain SHA-256-derived and native abi.* data uses compact Script framing. evmCompat (the Solidity-source compatibility mode) also switches the abi.* family to EVM-compatible head/tail bytes and Keccak selectors; use uint160 for an Ethereum-shaped address, since a SolidCash address is full BCH locking bytecode.
  • Under evmCompat, selector signatures follow Solidity's canonical spelling, so a selector, interfaceId or event topic hash equals what solc derives for the same declaration; abi.encodeWithSignature also accepts a signature built at runtime and hashes it through the keccak256 side-car.
  • Under evmCompat, an event argument of statically known scalar width is written in standard EVM notation and the artifact marks the parameter notation: 'evm'. A consumer decoding an event commitment by hand must dispatch on that field; the SDK's decoders and builders already do, and a receipt read through the SDK is unaffected.
  • Compile imported Solidity with evmCompat: true. Canonical EVM storage assembly, StorageSlot, and ERC-7201 patterns use the documented storage bridge; shapes outside that bridge, or outside the supported memory/call/delegate/Yul subset, fail with diagnostics and may require a BCH-specific rewrite.
  • int and uint are 256-bit checked types in the Solidity-compatible model; use bigint for the BCH-native arbitrary-precision integer. Audit arithmetic and packed encodings when migrating older native code.

SDK and tests​

  • The solidcash root is now the lean stateless surface only: Contract, TransactionBuilder, SignatureTemplate, Signer, randomUtxo, the error classes, and the regtest, Bitcoin RPC and FullStack providers. Stateful contracts, the factory, the message bus, framed composition, block oracles, the Electrum and mock network providers, HD signers, loop-call helpers, WalletConnect helpers and BCMR metadata live on subpaths: solidcash/stateful, solidcash/contract-factory, solidcash/message-bus, solidcash/framed, solidcash/oracle, solidcash/network/electrum, solidcash/network/mock, solidcash/hdsigner, solidcash/loop-call, solidcash/walletconnect and solidcash/bcmr. The root does not re-export them, so importing it stays fast; update the affected import statements rather than the SDK.
  • Signer/ContractFactory and connected methods are the maintained high-level workflow. Raw Contract and TransactionBuilder remain available for explicit transaction composition.
  • MockNetworkProvider starts empty, updates its UTXO set by default, and supports funded signers, snapshots, block/time control, and a configurable VM target. Tests must create or request their funding explicitly. By default it relaxes sizes (1,000,000-byte inputs, stack items and NFT commitments) and has no dust rule; only the operation-cost density (800 per byte) is real, so a green mock test does not prove a transaction is valid on mainnet.
  • Use Vitest with @solidcash/testing or SolidHat. The maintained Chai-style matchers cover named failures, events, BCH/token balance changes, and common transaction assertions; they are not universal Hardhat plugin compatibility.
  • Multi-contract source files return an ArtifactMap from compileFileMulti/compileStringMulti. Select a primary contract explicitly when using a single-artifact API, and use split-bundle APIs only when deploying the corresponding root/facet topology.

solidc compiler​

bounded bytes casting​

The purely semantic cast of bytes to a bounded bytes type (which does not offer any type safety) is now unsafe_bytes4(bytes). bytes4(bytes) is still accepted, but it now follows Solidity 0.8.5 and later: it right-pads with zero bytes or truncates to exactly 4 bytes, so it changes a value of a different length. Review every bytesN(bytes) cast in older code.

bytes x = 0x12345678;

// before
bytes4(x); // => 0x12345678 (correct semantic cast)
bytes5(x); // => 0x12345678 (incorrect semantic cast)

// after
// marked as unsafe to indicate that this is a purely semantic cast
unsafe_bytes4(x); // => 0x12345678 (correct semantic cast)
unsafe_bytes5(x); // => 0x12345678 (incorrect semantic cast)
bytes5(x); // => 0x1234567800 (right-padded to 5 bytes)

int to padded bytes casting​

In the past, bytes4(int) or bytes(int, 4) would perform a NUM2BIN operation, padding the value to 4 bytes, while bytes4(bytes) was a purely semantic type cast. This caused confusion, so instead you can now use the toPaddedBytes(int, length) function to perform the same padding (NUM2BIN) operation.

bytes4(int) is still accepted. In a native compile it pads the number like toPaddedBytes(int, 4); under evmCompat it writes the value as big-endian two's complement, as Solidity does.

// before
bytes4(5); // => 0x05000000
bytes(5, 4); // => 0x05000000

// after
toPaddedBytes(5, 4); // => 0x05000000

bool casting​

The bool() casting function now correctly changes the value of the argument to true for non-zero values and false for zero values, instead of only semantically treating the value as a boolean. This worked correctly when using the boolean directly inside require or if statements, but not when using it in a comparison.

// before
require(bool(5)); // => true
require(bool(5) == true); // => false || compiles to 0x05 0x01 OP_NUMEQUALVERIFY

// after
require(bool(5)); // => still true
require(bool(5) == true); // => true || compiles to 0x05 OP_0NOTEQUAL 0x01 OP_NUMEQUALVERIFY

If you want to keep the old behaviour (without added opcodes), you can use the unsafe_bool() casting function instead.

v0.11 to v0.12​

There are several breaking changes to the SDK in this release.

SolidCash SDK​

Old Transaction Builder Removal​

The most impactful breaking change is the removal of the deprecated 'Simple Transaction Builder'. See below for steps to migrate to the new transaction builder.

Contract constructor​

Before, the provider option was optional in the Contract constructor. This is no longer the case.

// Before: defaults to mainnet ElectrumNetworkProvider
const contract = new Contract(artifact, constructorArgs);

// After: explicitly specify the provider
const provider = new ElectrumNetworkProvider('mainnet');
const contract = new Contract(artifact, constructorArgs, { provider });

Transaction Builder​

Before, the setMaxFee() method was used to set the maximum fee for the transaction. This was replaced with the maximumFeeSatoshis option in the constructor. Additionally, the maximumFeeSatsPerByte option was added.

// Before: setMaxFee() was used to set the maximum fee
const builder = new TransactionBuilder({ provider }).setMaxFee(1000n);

// After: maximumFeeSatoshis option was added to the constructor
const builder = new TransactionBuilder({ provider, maximumFeeSatoshis: 1000n });

Additionally, transactionBuilder.bitauthUri() was renamed to transactionBuilder.getBitauthUri() for consistency.

MockNetworkProvider​

Before, the updateUtxoSet option was false by default for the MockNetworkProvider. This is now true by default to better match real-world network behaviour.

// Before: updateUtxoSet is false by default
const provider = new MockNetworkProvider();

// After: updateUtxoSet is true by default, if you want to keep the old behaviour, set it to false
const provider = new MockNetworkProvider({ updateUtxoSet: false });

Earlier, the MockNetworkProvider also automatically added some test UTXOs to the provider, which is no longer the case. Make sure to add any UTXOs you need manually.

v0.10 to v0.11​

There are several breaking changes to the compiler and SDK in this release. They are listed below in their own sections.

solidc compiler​

tx.age was renamed to this.age to better reflect that it enforces a UTXO-level locktime check (not transaction-level). To migrate, replace all occurrences of tx.age with this.age.

SDK: Transaction Builder​

The 'Simple Transaction builder' has been marked as deprecated and the 'Advanced Transaction Builder' is now simply referred to as the SolidCash Transaction Builder, as there is only one supported for the future.

Example​

Since the new transaction builder is quite different from the old one, it may be useful to see an example refactored from the old way to the new way.

With the deprecated 'simple transaction builder' the API looked like this:

import { SignatureTemplate } from 'solidcash';
import { ElectrumNetworkProvider } from 'solidcash/network/electrum';

const provider = new ElectrumNetworkProvider(Network.MAINNET);

// Optionally specify the contract UTXO
const contractUtxos = await contract.getUtxos();
const selectedContractUtxo = contractUtxos[0]

// Specify Bob Utxo to add to the transaction
const bobUtxos = await provider.getUtxos(bobAddress);
const selectedUtxoBob = bobUtxos[0]

const bobSignatureTemplate = new SignatureTemplate(bobPriv)

// Start building the transaction
const txDetails = await contract.functions
.transfer(bobSignatureTemplate)
.from(selectedContractUtxo)
.fromP2PKH(selectedUtxoBob, bobSignatureTemplate)
.to('bitcoincash:qrhea03074073ff3zv9whh0nggxc7k03ssh8jv9mkx', 10000n)
.withoutChange()
.send();

With the new transaction builder the API looks like this:

import { TransactionBuilder, SignatureTemplate } from 'solidcash';
import { ElectrumNetworkProvider } from 'solidcash/network/electrum';

const provider = new ElectrumNetworkProvider(Network.MAINNET);

// Specify the contract UTXO
const contractUtxos = await contract.getUtxos();
const selectedContractUtxo = contractUtxos[0]

// Specify Bob Utxo to add to the transaction
const bobUtxos = await provider.getUtxos(bobAddress);
const selectedUtxoBob = bobUtxos[0]

const bobSignatureTemplate = new SignatureTemplate(bobPriv)

// Start building the transaction
const txDetails = await new TransactionBuilder({ provider })
.addInput(selectedContractUtxo, contract.unlock.transfer(bobSignatureTemplate))
.addInput(selectedUtxoBob, bobSignatureTemplate.unlockP2PKH())
.addOutput({
to: 'bitcoincash:qrhea03074073ff3zv9whh0nggxc7k03ssh8jv9mkx',
amount: 10000n
})
.send();

With the new transaction builder, all inputs and outputs are explicitly specified. This means that there are no automatic change outputs added (for BCH or tokens). This means that there are also no .withMinChange(), .withoutChange(), .withoutTokenChange(), withHardcodedFee(), or .withFeePerByte() methods. The developer is responsible for manually adding change outputs. There is still an option to use .setMaxFee() as a security measure to prevent the transaction from being too expensive.

SDK: ElectrumNetworkProvider​

The underlying electrum-cash library has been migrated to the new @electrum-cash/network package. This drops support for electrum cluster functionality. We reworked the second parameter of the ElectrumNetworkProvider constructor to be an options object, which can contain a custom electrum client or a custom hostname.

If you were not using custom clusters, there is no need to change anything. If you were using custom clusters, you will need to update your code to use the new @electrum-cash/network package and use a single client instead of a cluster.

Example​

Before:

import { ElectrumCluster, ClusterOrder } from 'electrum-cash';
import { ElectrumNetworkProvider } from 'solidcash/network/electrum';

const customCluster = new ElectrumCluster('SolidCash Application', '1.4.1', 2, 3, ClusterOrder.PRIORITY);
customCluster.addServer('bch.imaginary.cash', 50004, ElectrumTransport.WSS.Scheme, false);
customCluster.addServer('blackie.c3-soft.com', 50004, ElectrumTransport.WSS.Scheme, false);
customCluster.addServer('electroncash.dk', 50004, ElectrumTransport.WSS.Scheme, false);

const provider = new ElectrumNetworkProvider('mainnet', customCluster);

After:

import { ElectrumClient } from '@electrum-cash/network';
import { ElectrumNetworkProvider } from 'solidcash/network/electrum';

const customClient = new ElectrumClient('SolidCash Application', '1.4.1', 'bch.imaginary.cash');
const provider = new ElectrumNetworkProvider('mainnet', { electrum: customClient });

// or

const provider = new ElectrumNetworkProvider('mainnet', { hostname: 'bch.imaginary.cash' });

v0.9 to v0.10​

SolidCash SDK​

The Reason enum + FailedTimeCheckError and FailedSigCheckError errors have been removed. If you were using these to check your transaction errors, you should now use the new error classes FailedRequireError, FailedTransactionEvaluationError and FailedTransactionError.

If you were using transaction.meep() or using the meep string in errors, you should now use transaction.bitauthUri() to get a BitAuth URI for debugging or use the bitauthUri string in errors.

The Argument type has been split into FunctionArgument and ConstructorArgument and the encodeArgument function has been renamed to encodeFunctionArgument. If you were using these types in your code, you should update your code to use the new types, depending on whether you were using them as function arguments or constructor arguments.

v0.7 to v0.8​

solidc compiler​

solidc is now a Pure ESM package. This means that you can no longer use require to import solidcash. For more information, see the ESM documentation.

LockingBytecodeP2SH should be replaced with LockingBytecodeP2SH20 to keep the same behaviour, or updated to LockingBytecodeP2SH32 to use the recommended new P2SH32 Address type.

SolidCash SDK​

solidcash is now a Pure ESM package. This means that you can no longer use require to import solidcash. For more information, see the ESM documentation.

Contract instantiation​

When instantiating a Contract object, you now have to pass an options object as a third parameter instead of a network provider. This options object contains the network provider, as well as the address type. The address type defaults to p2sh32 but can be changed to p2sh20 if you want to keep the same address type as in earlier versions of the SDK.

// old
const contract = new Contract(artifact, constructorArgs, provider);

// new
const options = { provider, addressType: 'p2sh20' };
const contract = new Contract(artifact, constructorArgs, options);

SIGHASH_UTXO​

All signature templates use SIGHASH_ALL | SIGHASH_UTXOS now, to keep using only the previous SIGHASH_ALL, overwrite it in the following way:

const sig = new SignatureTemplate(wif, HashType.SIGHASH_ALL);

Note that you need to use only SIGHASH_ALL if you're still using "old-style" covenants (from SolidCash v0.6.0 and lower). It is recommended to upgrade to the new "native" covenants (from SolidCash v0.7.0 and higher) instead.

bigint​

You can no longer use number inputs for constructor arguments, function arguments, or input/output amounts. Use bigint instead. contract.getBalance() and contract.getUtxos() now also return bigint for satoshi amounts instead of number.

Name changes & removal of deprecated features​

  • Network options "testnet" and "staging" should be replaced with "testnet3" and "testnet4" respectively.
  • contract.getRedeemScriptHex() should be replaced with contract.bytecode.
  • BitboxNetworkProvider has been removed since Bitbox is long deprecated. Switch to modern solutions like ElectrumNetworkProvider instead.

v0.6 to v0.7​

solidc compiler​

The older preimage-based introspection/covenants have been replaced with the newly supported native introspection/covenants. This has significant consequences for any existing covenant contracts, but in general this native introspection makes covenants more accessible, flexible and efficient. See below for a list of changes. In some cases there is no one to one mapping between the old introspection and the new introspection methods, so the logic of the smart contracts will need to be refactored as well.

Most importantly, it is now possible to access specific data for all individual inputs and outputs, rather than e.g. working with hashes of the outputs (tx.hashOutputs). This offers more flexibility around the data you want to enforce. For more information about this new native introspection functionality, refer to the Global covenant variables section of the documentation, the Covenants guide and the Native Introspection CHIP.

Covenant variables​

  • tx.version and tx.locktime used to be bytes4, but are now int.
  • tx.hashtype has been removed and can no longer be accessed.
  • tx.hashPrevouts and tx.outpoint have been removed. Instead, the outpoints of individual inputs can be accessed with tx.inputs[i].outpointTransactionHash and tx.inputs[i].outpointIndex. The index of the active input can be accessed with this.activeInputIndex.
  • tx.hashSequence and tx.sequence have been removed. Instead, the sequence numbers of individual inputs can be accessed with tx.inputs[i].sequenceNumber. The index of the active input can be accessed with this.activeInputIndex.
  • tx.bytecode has been renamed to this.activeBytecode
  • tx.value has been removed. Instead, the value of individual inputs can be accessed with tx.inputs[i].value. The index of the active input can be accessed with this.activeInputIndex.
  • tx.hashOutputs has been removed. Instead, the value and locking bytecode of individual outputs can be accessed separately with tx.outputs[i].value and tx.outputs[i].lockingBytecode.

Additionally, it is now possible to access the number of inputs and outputs with tx.inputs.length and tx.outputs.length. It is also possible to access individual inputs' locking bytecode and unlocking bytecode with tx.inputs[i].lockingBytecode and tx.inputs[i].unlockingBytecode. It is also no longer a requirement to have a signature check somewhere in the contract in order to use this introspection/covenant functionality.

Utility classes​

OutputP2PKH, OutputP2SH and OutputNullData have been replaced by LockingBytecodeP2PKH, LockingBytecodeP2SH and LockingBytecodeNullData respectively. These new classes only produce the locking bytecode, rather than the full output (including value). This means that the locking bytecode and value of outputs need to be checked separately.

Other changes​

Casting from sig to datasig has been removed since that was only useful for old-style covenants. If, for any reason, you do want to cast a sig to a datasig you will need to manually cut the hashtype off the end and update datasig(s) to s.split(s.length - 1)[0].

Example​

Since the new covenant functionality is very different from the existing, it may be useful to see a complex covenant contract refactored from the old way to the new way.

Mecenas.scash v0.6.0
pragma solidcash ^0.6.0;

contract Mecenas(bytes20 recipient, bytes20 funder, int pledge, int period) {
function receive(pubkey pk, sig s) {
require(checkSig(s, pk));
require(tx.age >= period);

int minerFee = 1000;
int intValue = int(bytes(tx.value));

if (intValue <= pledge + minerFee) {
// The contract has less value than the pledge, or equal.
// The recipient must claim all of it.

bytes8 amount1 = bytes8(intValue - minerFee);
bytes34 out1 = new OutputP2PKH(amount1, recipient);
require(hash256(out1) == tx.hashOutputs);
} else {
// The contract has more value than the pledge. The recipient must
// also add one change output sending the remaining coins back
// to the contract.

bytes8 amount1 = bytes8(pledge);
bytes8 amount2 = bytes8(intValue - pledge - minerFee);
bytes34 out1 = new OutputP2PKH(amount1, recipient);
bytes32 out2 = new OutputP2SH(amount2, hash160(tx.bytecode));
require(hash256(out1 + out2) == tx.hashOutputs);
}
}

function reclaim(pubkey pk, sig s) {
require(hash160(pk) == funder);
require(checkSig(s, pk));
}
}
Mecenas.scash 0.7.0
contract Mecenas(bytes20 recipient, bytes20 funder, int pledge, int period) {
function receive() {
require(tx.age >= period);

// Check that the first output sends to the recipient
bytes25 recipientLockingBytecode = new LockingBytecodeP2PKH(recipient);
require(tx.outputs[0].lockingBytecode == recipientLockingBytecode);

// Calculate the value that's left
int minerFee = 1000;
int currentValue = tx.inputs[this.activeInputIndex].value;
int changeValue = currentValue - pledge - minerFee;

// If there is not enough left for *another* pledge after this one,
// we send the remainder to the recipient. Otherwise we send the
// remainder to the recipient and the change back to the contract
if (changeValue <= pledge + minerFee) {
require(tx.outputs[0].value == currentValue - minerFee);
} else {
require(tx.outputs[0].value == pledge);
bytes changeBytecode = tx.inputs[this.activeInputIndex].lockingBytecode;
require(tx.outputs[1].lockingBytecode == changeBytecode);
require(tx.outputs[1].value == changeValue);
}
}

function reclaim(pubkey pk, sig s) {
require(hash160(pk) == funder);
require(checkSig(s, pk));
}
}

v0.5 to v0.6​

solidc compiler​

The exports for library usage of solidc have been updated. All utility-type exports have been moved to the @solidcash/utils package, but they are still accessible from the utils export from solidc. Note that the recommended use of solidc is still the CLI, not the NPM package.

In v0.5 you could encode a string like this:

const { Data } = require('solidc');

const encodedString = Data.encodeString('Hello World');

While for v0.6 you'd need to use the utils export or @solidcash/utils:

const { utils } = require('solidc');
const { encodeString } = require('@solidcash/utils');

const encodedString = utils.encodeString('Hello World');
const encodedString = encodeString('Hello World');

Compilation functions used to be exported as part of the SolidCompiler object, but are now exported as standalone functions.

In v0.5 compilation looked like this:

const { SolidCompiler } = require('solidc');

const Mecenas = SolidCompiler.compileFile(path.join(__dirname, 'mecenas.scash'));

In v0.6, this needs to be changed to this:

const { compileFile } = require('solidc');

const Mecenas = compileFile(path.join(__dirname, 'mecenas.scash'));

SolidCash SDK​

The SolidCash SDK no longer depends on solidc and no longer exports the SolidCompiler object. This reflects the recommended usage where the CLI is used for compilation and the artifact JSON is saved. Then this artifact JSON can be imported into the SolidCash SDK. If you prefer to compile your contracts from code, you need to add solidc as a dependency and use its compilation functionality.

v0.4 to v0.5​

SolidCash SDK​

The contract instantiation flow has been refactored to enable compatibility with more BCH libraries and simplify the different classes involved.


In v0.4 a contract could be compiled or imported using Contract.compile() or Contract.import(), which returned a Contract object. On that Contract object contract.new(...args) could be called, which returned an Instance object. In the v0.5 release, the Contract and Instance objects have been merged and simplified, while the compilation has been extracted into its own class.

In v0.4, contract instantiation looked like this:

const { Contract } = require('solidcash');

const Mecenas = Contract.compile(path.join(__dirname, 'mecenas.scash'), 'testnet');
const contract = Mecenas.new(alicePkh, bobPkh, 10000);

In v0.5, this needs to be changed to look like this:

const { SolidCompiler, ElectrumNetworkProvider, Contract } = require('solidcash');

const Mecenas = SolidCompiler.compileFile(path.join(__dirname, 'mecenas.scash'));
const provider = new ElectrumNetworkProvider('testnet');
const contract = new Contract(Mecenas, [alicePkh, bobPkh, 10000], provider);

  • Transaction object's .send() function now returns either a libauth Transaction or raw hex string rather than a BITBOX Transaction. If it is necessary, the raw hex string can be imported into libraries such as BITBOX to achieve similar functionality as before.

  • In v0.4.1, Sig was deprecated in favour of SignatureTemplate. In v0.5.0, the deprecated class has been removed. All occurrences of Sig should be replaced with SignatureTemplate.

See the release notes for an overview of other new changes.

v0.3 to v0.4​

solidc compiler​

In v0.3, casting an int type to a bytes would perform an NUM2BIN operation, padding the value to 8 bytes. This made bytes(10) equivalent to bytes8(10). From v0.4.0 onwards, casting to an unbounded bytes type is only a semantic cast, indicating that the int value should be treated as a bytes value.

  • If you need the old behaviour, you should change all occurrences of bytes(x) to bytes8(x).

SolidCash SDK​

The entire Transaction flow has been refactored to a more fluent chained TransactionBuilder API.

  • All occurrences of .send(to, amount) should be replaced with .to(to, amount).send().
  • All occurrences of .send(outputs) should be replaced with .to(outputs).send().
    • Alternatively, the list of outputs can be split up between several .to() calls.
    • If any of the outputs contain opReturn outputs, these should be added separately using .withOpReturn(chunks)
  • The same transformations are applicable to all .meep() calls.
  • The meep() function previously logged the meep command automatically, but now it returns the command as a string, so you should console.log() the command separately.
  • All transaction options previously included in the TxOptions object should now be provided using chained functions.
    • The time option should be provided using the .withTime(time) function.
    • The age option should be provided using the .withAge(age) function.
    • The fee option should be provided using the .withHardcodedFee(fee) function.
    • The minChange option should be provided using the .withMinChange(minChange) function.

In v0.2.2, Contract.fromCashFile() and Contract.fromArtifact() were deprecated in favour of Contract.compile() and Contract.import(). In v0.4.0, the deprecated functions have been removed.

  • All occurrences of Contract.fromCashFile() should be replaced with Contract.compile().
  • All occurrences of Contract.fromArtifact() should be replaced with Contract.import().

See the release notes for an overview of other new changes.