sCrypt is a subset of TypeScript used for writing smart contract on BSV blockchain. It is said to be an embedded Domain Specific Language (eDSL), simply put, it is a language within another language which is TypeScript. The choice of TypeScript as the host language for sCrypt fulfills two of the aims of writing bitcoin smart contracts. It is a familiar JavaScript programming language with type safety features. Thus to use it for bitcoin smart contract, a programmer do not need to learn new programming language. This article focuses on introduction to sCrypt, sCrypt syntax and data types. It aims at introducing newcomers into the sCrypt syntax and data types which are essentials for writing smart contracts and building decentralized applications (dApps) on BSV blockchain.
INTRODUCTION TO SCRYPT.
sCrypt is a high-level programming language that is specified for writing smart contracts on BSV blockchain. It is designed with high emphasis on reliability and security for developers use within the BSV ecosystem. It utilizes the inherent Bitcoin protocol i.e script verification. This feature alone give smart contracts written on sCrypt high level of integrity. sCrypt language is compiled into Bitcoin Script which result in assembly-like scripts that can be used as a locking scripts while building transactions on BSV blockchain.
Bitcoin uses a scripting system for transaction. Script is a simple series of instructions. These instructions are in sequential order and stack-based. Data is pushed onto the stack and opcodes are used to perform operations on items found on the stack. To learn more about bitcoin scripts you can check here.
Key Features Of SCRYPT.
sCrypt has some key features which gives it more benefits over other languages that are used for writing smart contracts. Some of the features and benefits offered by sCrypt are stated below.
Security and Reliability: sCrypt leverage on inherent security protocol of the Bitcoin by building on top of the Bitcoin scripts. As such it minimizes the risk of vulnerabilities and exploits.
Script Compatibility: sCrypt is completely compatible with Bitcoin Scripts, thus it enables easy integration of smart contracts written with sCrypt into the existing Bitcoin infrastructure. Bitcoin Script codes can also be translated into sCrypt code.
Syntax Resemblance: sCrypt syntax resembles that of the familiar programming languages like Python and JavaScript. It also has programming constructs like variables, functions, loops and conditionals. The syntax and structure resemblance in sCrypt reduces learning curves for developers that are familiar with programming languages like JavaScript and Python.
Deterministic Execution: sCrypt enforces predetermined execution of smart contracts which is essential for consensus and BSV blockchain integrity maintenance. This enhances the reliability and trustworthiness of smart contracts on BSV.
Scalability and Performance: sCrypt has lightweight and efficient architecture that minimizes resources consumption. It enables the creation of complex smart contracts with high level of performance and scalability.
Tools and Development Environment: sCrypt offers a comprehensive suite of developers tools and resources to support developers throughout the smart contract development life cycle. The tools include integrated development environments (IDEs), testing frameworks and documentation. The tools help to simplify development, code review and debugging process.
BASIC SYNTAX OF sCrypt.
sCrypt has basic syntax elements like variables, functions, conditionals and loops just like other programming languages.
Variables: Data is store in variables and the variable can be declared using the key word var
const
or let
Examples of variable declarations is shown below
let a: bigint = 1n // n-suffix means the constant will be compiled as a bigint
a = BigInt(1) // Can also be defined with the BigInt() wrapper instead
var b: boolean = false
const N: number = 3
As shown above, variables are declared using the keyword, followed by the variable name and the variable can be initialized with a value. Using the keyword let
we initialize the variable
named ‘a’ with value of 1 which is a big integer. The variable
named ‘b’ is initialized to be false, it is a boolean type. Lastly the variable
named ’N’ is initialized to be 3, it a number.
- Functions: Functions are blocks of code that performs a specific task and can be reused in a smart contract. Functions are declared using the
function
keyword, followed by the function’s name, parameters and the function’s body inside a curly bracket as shown below;
function add(int a, int b) {
return a + b;
}
The function
above is an addition function
to add two integers ‘a’ and ‘b’ and return the sum of the two. The name of the function
is ‘add’ , with parameters (int a) and (int b). The body of the function contain the return statement of the function.
Note that while writing smart contract for BSV blockchain using sCrypt, some functions are built-in-functions that may be a bit varied from the format above as shown in the example below.
// None of the below functions need an explicit import, as they're built into scrypt-ts itself.
let h = sha256(utf8ToByteString("hello"))
assert(
h == toByteString("2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824")
)
As shown above assert
is a built-in function in sCrypt, it throws error only if the conditions passed to it is false. If all the conditions passed to assert
is true, a contract call will be successful. The condition passed to assert
in the code snippet above is h == toByteString(“2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824”).
- Conditionals: Conditionals are used to execute different blocks of code according to defined conditions. Conditional include if else and else if statements as shown below;
if (x > 0) {
// Code block to execute if x is greater than 0
} else if (x == 0) {
// Code block to execute if x is equal to 0
} else {
// Code block to execute if x is less than 0
}
- Loops: Loops are used to execute a block of code continuously as long as a specified condition is true. Bitcoin Script does not provide looping constructs natively for security reasons, to prevent DoS attacks. All loops must be bounded at compile time. If there is a need to loop inside @method, the following format must be strictly used:
for(let i = 0; i < maxLoopCount; i++) {
...
}
As shown above, the initial value must be zero, the operator used must be < then initial value increments i++ . maxLoopCount must be a compile-time constant. Loop like break and continue are currently not allowed currently.
- Comments: Comments are used to add explanatory notes within a code but the comments are ignored by the compiler. Single-line comments start with //, and multi-line comments are enclosed between /* and */. Examples are shown below;
// This is a single-line comment
/*
This is a multi-line comment
that spans multiple lines
*/
DATA TYPES IN sCrypt.
In the traditional programming language, we are conversant with the data types integer, boolean, string and array. Integers used the keyword int and are used to represent positive or negative whole numbers. Booleans used the keyword bool and are used to represent true or false values. String used the keyword string and are used to represent text data. These data type are present in sCrypt with some additional ones and some modifications. sCrypt data types can be classified as basic types, number type, array types, user defined type and domain type.
Basic Data Types: Examples of basic data types are boolean, bigint (big integer) and string. While writing smart contracts with sCrypt, boolean and bigint are allowed to be used in @props and @methods along with their wrapper types Boolean and BigInt . A string literal is not allowed to be used directly without being converted into a ByteString. Examples of these data types in use is given below;
@method()
public example(x: bigint, y: ByteString, z: boolean) {
assert(x == 5n)
assert(z)
// Strings must by converted to ByteString before being used
// in a smart contract:
assert(y == utf8ToByteString("hello world!"))
// We can also parse hex strings:
assert(x == unpack(toByteString('05')))
// Vice versa, we can turn integers into ByteStrings:
assert(pack(x) == toByteString('05'))
// Little-endian signed-magnitude representation is being used:
assert(pack(-x) == toByteString('85'))
assert(pack(-x * 1000n) == toByteString('8893'))
}
As shown above, strings must be converted to ByteString before being used in a smart contract like the case for the string “hello world”. Integers can be turned into ByteString and from ByteString back to integer.
- Number Type: The number type is not allowed in @props and @method.
In some special cases, parameters of type number must be passed. In this case, we can use Number() function to convert bigint to number. Example of this is shown below;
// Array indexes:
let arr: FixedArray<bigint, 3> = [1n, 3n, 3n]
let index: bigint = 2n
let item = arr[Number(idx)]
// ByteString operations:
let size: bigint = 3n
let b: ByteString = reverseBytes(toByteString("001122"), Number(size))
let end: bigint = 1n
b.slice(0, Number(end))
In the examples above Number() is used to convert bigint in array indexes to number arr[Number(idx)]. It is also used to convert bigint in ByteString operations to number, Number(size) and Number(end).
Note that, number type can also be converted to bigint as shown below;
let x: bigint = BigInt(10)
- Array Types: The common array types in TypeScript like T[] or Array are not allowed to be used in @props and @methods. An array must be declared as type of FixedArray, whose LENGTH must be a compile-time-constant value as shown below:
let aaa: FixedArray<bigint, 3> = [1n, 3n, 3n]
const N = 2
let aab: FixedArray<bigint, N> = [1n, 2n]
// 2-dimensional array
let abb: FixedArray<FixedArray<bigint, 2>, 3> = [
[1n, 3n],
[1n, 3n],
[1n, 3n],
]
// Fill:
let zeroArr = fill(0n, 3) // = [0n, 0n, 0n]
const M = 3 // Length must be a compile time constant
let falseArr = fill(false, M)
- User Defined Type: Users can be define customized data types using type or interface, made of basic types.
type ST = {
a: bigint
b: boolean
}
interface ST1 {
x: ST
y: ByteString
}
- Domain Types: There are several domain data types specific to the Bitcoin context, used to further improve type safety.
let pubKey = PubKey(
toByteString("02a2ef6eb12d3076dbdc98241920f75ac88b664656400aa390a0b236ea1eb6ec0b")
)
let pkh = Addr(pubKey2Addr(pubKey))
let h = Sha256(sha256(utf8ToByteString("hello")))
// Will fail as passed data is not a SHA256 hash:
//let h2 = Sha256(utf8ToByteString('ffaabb'))
These data types provide the foundation for storing and manipulating data within sCrypt smart contracts. The basic syntax elements provide the foundation for writing smart contracts in sCrypt. Good knowledge and usage of both data types and sCrypt syntax will help developers to create clear, concise, and maintainable smart contracts on the BSV blockchain. For further reading visit the sCrypt documentation and look toward our next article.
Top comments (0)