Skip to main content

Built-in Functions

SolidCash has several built-in functions for things like cryptographic and arithmetic applications, and it includes many common arithmetic and other operators that you would expect in a programming language.

Arithmetic functions​

The arithmetic built-ins take bigint parameters, which accept any integer type. abs, min and max keep a bounded argument type: abs of an int8 is an int8, and min or max of two bounded integers has the wider of the two types. With a bigint argument they return bigint.

abs()​

bigint abs(bigint a)

Returns the absolute value of argument a.

min()​

bigint min(bigint a, bigint b)

Returns the minimum value of arguments a and b.

max()​

bigint max(bigint a, bigint b)

Returns the maximum value of arguments a and b.

within()​

bool within(bigint x, bigint lower, bigint upper)

Returns true if and only if x >= lower && x < upper.

addmod()​

bigint addmod(bigint x, bigint y, bigint k)

Returns (x + y) % k. Because the BCH VM has arbitrary-precision integers, the intermediate sum cannot overflow, so this is exactly (x + y) % k with no wraparound.

mulmod()​

bigint mulmod(bigint x, bigint y, bigint k)

Returns (x * y) % k, with the same no-overflow guarantee as addmod.

Hashing functions​

ripemd160()​

bytes20 ripemd160(any x)

Returns the RIPEMD-160 hash of argument x.

sha1()​

bytes20 sha1(any x)

Returns the SHA-1 hash of argument x.

sha256()​

bytes32 sha256(any x)

Returns the SHA-256 hash of argument x.

hash160()​

bytes20 hash160(any x)

Returns the RIPEMD-160 hash of the SHA-256 hash of argument x.

hash256()​

bytes32 hash256(any x)

Returns the double SHA-256 hash of argument x.

keccak256()​

bytes32 keccak256(bytes x)

Returns the real Keccak-256 hash of x, byte-identical to Ethereum's. Bitcoin Cash has no Keccak opcode, so this compiles to a co-spent compute side-car rather than inline script. A constant keccak256("literal") is folded at compile time. See Cryptography.

note

An address is not implicitly a bytes, so hash an address with an explicit cast: hash160(bytes(msg.sender)).

Signature checking functions​

caution

All signature checking functions must comply with the NULLFAIL rule, which only allows 0x as an invalid signature. Any other invalid signature will immediately fail the entire script.

Nullfail example​

The NULLFAIL rule means passing an invalid signature to checkSig() does not return false: it fails the script. To safely return false on a signature check, use an empty 0x signature instead, as shown below:

contract Escrow(pubkey seller, pubkey referee) {
// This would immediately fail: userSig is invalid for whichever key it
// does not match, and a non-empty invalid signature aborts the script.
//
// require(checkSig(userSig, seller) || checkSig(userSig, referee));

// Instead take two signatures, and pass 0x for the unused one so that
// checkSig returns false rather than aborting.
function release(sig sellerSig, sig refereeSig) {
require(checkSig(sellerSig, seller) || checkSig(refereeSig, referee));
}
}

checkSig()​

bool checkSig(sig s, pubkey pk)

Checks that transaction signature s is valid for the current transaction and matches with public key pk.

checkMultiSig()​

bool checkMultiSig(sig[] sigs, pubkey[] pks)

Performs a multi-signature check using a list of transaction signatures and public keys.

note

The TypeScript SDK supports multisig arguments. checkMultiSig requires ECDSA transaction signatures, so create each argument with SignatureAlgorithm.ECDSA; SignatureTemplate defaults to Schnorr for ordinary checkSig.

checkDataSig()​

bool checkDataSig(datasig s, bytes msg, pubkey pk)

Checks that sig s is a valid signature for message msg and matches with public key pk. OP_CHECKDATASIG verifies the signature over sha256(msg), so the signer signs sha256(msg), not msg itself.

Other functions​

toPaddedBytes()​

bytes toPaddedBytes(bigint value, bigint length)

Pads the integer value with zeros to the specified length (OP_NUM2BIN). With a literal length the result type is bytesN, for example bytes20 for toPaddedBytes(x, 20). This is most useful when storing integer values in local state (see local state guide).

tip

Using bytes20 placeholderPkh = toPaddedBytes(0, 20) will generate a 20 byte zero-array at runtime, whereas bytes20 placeholderPkh = 0x0000000000000000000000000000000000000000 will actually take 20 bytes of space in your contract.

intToString()​

string intToString(bigint value)

Converts an integer to its decimal string representation.

stringToInt()​

bigint stringToInt(string value)

Parses a decimal string into an integer.

erc7201()​

uint256 erc7201(string namespace)

Returns the specification-conformant ERC-7201 namespaced storage slot. A literal or constant-string namespace is folded with real Keccak at compile time; a runtime string lowers to the complete formula. See EVM Storage & ERC-7201 Compatibility.

Signature recovery​

Bitcoin Cash has no public-key recovery opcode, so these compile to a co-spent recovery side-car pair. All three take Solidity's (hash, v, r, s) argument shape and are bit-for-bit EVM-conformant.

ecrecoverPubKey()​

pubkey ecrecoverPubKey(bytes32 hash, int v, bytes32 r, bytes32 s)

Recovers the signer's secp256k1 public key.

ecrecoverP2pkh()​

address ecrecoverP2pkh(bytes32 hash, int v, bytes32 r, bytes32 s)

Recovers the signer's P2PKH locking bytecode.

ecrecoverEvm()​

bytes20 ecrecoverEvm(bytes32 hash, int v, bytes32 r, bytes32 s)

Recovers the signer's Ethereum address.

Bare Solidity ecrecover(hash, v, r, s) is available only when the compiler option ecrecover is set to 'p2pkh' or 'evm', which selects one of these projections.

caution

Recovery spans two co-spent side-car inputs per call. If the public key is already available to the spender, use checkDataSig instead: it is a single opcode. See Cryptography.

Block functions​

blockhash()​

bytes32 blockhash(int blockNumber)

Returns the hash of the given block, read from a per-height oracle NFT of the contract's own category. It makes the contract stateful; a missing oracle NFT is an error, not a zero hash. See Global Variables.

blobhash()​

bytes32 blobhash(int index)

Always returns zero. Bitcoin Cash has no EIP-4844 blobs; this exists as a porting shim.

gasleft()​

gasleft()

A fixed shim that always returns the integer 1000000. Bitcoin Cash has no gas metering; this exists so ported gas-budget checks keep running. Compiler-warned; do not rely on the value.

See also​