Skip to main content

Global Functions & Operators

NexScript 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​

abs()​

int abs(int a)

Returns the absolute value of argument a.

min()​

int min(int a, int b)

Returns the minimum value of arguments a and b.

max()​

int max(int a, int b)

Returns the maximum value of arguments a and b.

within()​

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

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

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.

Signature checking functions​

caution

All signature checking functions must comply with the NULLFAIL rule. This means that if you want to use the output of a signature check inside the condition of an if-statement, the input signature needs to either be correct, or an empty byte array. When you use an incorrect signature as an input, the script will fail.

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(int signers, sig[] sigs, pubkey[] pks)
bool checkMultiSig(sig[] sigs, pubkey[] pks)

Performs a multi-signature check using a list of transaction signatures and public keys, with Nexa's Schnorr multisig. signers is a bitfield of which keys signed: bit 0 for the first key in pks, bit 1 for the second, and so on, with one bit per signature. The signatures must be in the same order as their keys. At most 16 keys.

When every key signs, signers can be left out. When only some keys sign, which ones can differ between spends, so the spender passes it as an argument:

contract Treasury(pubkey alice, pubkey bob, pubkey carol) {
// any 2 of the 3: signers is e.g. 0b101 when alice and carol sign
function spend(int signers, sig s1, sig s2) {
require(checkMultiSig(signers, [s1, s2], [alice, bob, carol]));
}
}

In the SDK, multisigSigners(pubkeys, signingPubkeys) computes signers:

const signers = multisigSigners([alicePub, bobPub, carolPub], [alicePub, carolPub]); // 0b101n
await treasury.functions
.spend(signers, new SignatureTemplate(alicePriv), new SignatureTemplate(carolPriv))
.to(recipient, 10000n)
.send();

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.

encodeNumber()​

bytes encodeNumber(int number)

Minimally encodes the number to VM data. Useful in covenants and digest building. Currently limited to positive number only.

encodeData()​

bytes encodeData(bytes data)

Minimally encodes the data to VM data. Useful in covenants and digest building. Currently limited to data sizes less than 76 to be compatible with OP_PUSHDATA1.

Token functions​

hasAuthority()​

bool hasAuthority(int flags, int required)

Checks that flags is a token authority (a negative authority field, as returned by tokenAuthority) that has every flag in required. required is a sum of the constants below; 0 only checks that flags is an authority.

ConstantFlag
AUTHORITY_MINTCan mint tokens
AUTHORITY_MELTCan melt tokens
AUTHORITY_BATONCan create authority outputs, including passing itself on
AUTHORITY_RESCRIPTCan change the redeem script
AUTHORITY_SUBGROUPCan create subgroups
// output 0 must carry an authority that can mint and pass itself on
require(hasAuthority(tx.outputs[0].tokenAuthority, AUTHORITY_MINT + AUTHORITY_BATON));
note

The authority field is a 64 bit number with the AUTHORITY flag in bit 63, so it is negative as a script number, and script numbers are sign-magnitude. Testing its bits with & directly does not work; hasAuthority() converts it to its 8 byte two's complement form first.

Merkle functions​

merkleRoot()​

bytes32 merkleRoot(bytes proof, bytes[] elements)
bytes32 merkleRoot(bytes proof, bytes[] elements, int options)

Computes the root of a merkle tree from some of its leaves and a proof that they are in it, using OP_MERKLEROOT. Comparing the result with a known root checks that the elements are in that tree. elements is an array literal of 1 to 256 elements, in the order of their positions in the tree, and the proof must use all of them. See the merkle guide for building trees and proofs with the SDK.

options is a constant sum of:

ConstantMeaning
MERKLE_SHA256SHA256 for leaves and inner nodes (the default)
MERKLE_HASH256Double SHA256
MERKLE_RIPEMD160RIPEMD160, so the root is 20 bytes
MERKLE_HASH160SHA256 then RIPEMD160, so the root is 20 bytes
MERKLE_HASH_ELEMENTSThe elements are raw data that the opcode hashes into leaves. Without it they must already be leaf hashes.

Name at most one hash, and each constant once: the hash constants add up to each other (MERKLE_RIPEMD160 + MERKLE_HASH160 is MERKLE_HASH256), so the compiler rejects a sum that would silently select a different hash.

// pk must be one of the public keys in the tree with this root
require(merkleRoot(proof, [pk], MERKLE_HASH_ELEMENTS) == root);

The result is 32 bytes, or 20 for MERKLE_RIPEMD160 and MERKLE_HASH160, except when every node the proof reaches is empty: then it is the 1-byte empty element 0x00. That cannot equal a real root, so comparing the result with one is safe; check its length before using it any other way.

caution

With MERKLE_HASH_ELEMENTS, two kinds of element prove more than they should. An empty element hashes to the empty leaf, so it proves any empty slot whose sibling is also empty. An element twice the hash size (64 bytes, or 40 for 20-byte hashes) that is two child hashes put together hashes to their parent, so with the proof from that level up it passes as a leaf. Unless the contract already rules them out (a public key that checkSig accepts is never empty or 64 bytes), require the element to be non-empty and not twice the hash size. See the merkle guide.

Operators​

An overview of all supported operators and their precedence is included below. Notable is a lack of exponentiation, since these operations are not supported by the underlying Script.

PrecedenceDescriptionOperator
1Parentheses(<expression>)
2Type cast<type>(<expression>)
3Object instantiationnew <class>(<args...>)
4Function call<function>(<args...>)
5Tuple index<tuple>[<index>]
6Member access<object>.<member>
7Unary minus-
7Logical NOT!
8Multiplication, division and modulo*, /, %
9Addition and subtraction+, -
9String / bytes concatenation+
10Numeric comparison<, >, <=, >=
11Equality and inequality==, !=
12Bitwise AND&
13Bitwise XOR^
14Bitwise OR|
15Logical AND&&
16Logical OR||
17Assignment=