Skip to content

IdanMann/py-scryptlib

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

71 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

scryptlib-python

A Python SDK for sCrypt.

Build Status

You can learn all about writing sCrypt smart contracts in the official docs.

Installation

Compiler

To use the SDK, you need to get a copy of the sCrypt compiler. You can get it either by downloading the sCrypt IDE or executing the following command, if you have an UNIX-like OS:

curl -Ls https://scrypt.io/setup | sh -s --

This will download the latest version of the compiler.

You can also download a specific version of the compiler using the -v flag:

curl -Ls https://scrypt.io/setup | sh -s -- -v 1.15.1

SDK

You can install the SDK as a Python package using pip, either directly from the project folder:

pip install .

, or from the PyPI:

pip install scryptlib

Usage

The SDK is used to convert script templates, produced by the sCrypt compiler, to an object-based representation in Python. It allows for easy compilation, inspection and verification of smart contracts.

Compiling an sCrypt contract

We can compile an sCrypt conract source file like so:

import scryptlib

contract = './test/res/arraydemo.scrypt'
compiler_result = scryptlib.compile_contract(contract)

This will leave us with a CompilerResult object, that contains all of the data, returned by the compiler. The compile_contract method will try to automatically search for the compiler binary. You can also explicitly pass the path to the binary, using the compiler_bin parameter.

It is also possible to pass the sCrypt source code as a string object:

contract_source = '''
    contract Equals {
        int x;

        constructor(int x) {
            this.x = x;
        }

        public function equals(int y) {
            require(this.x == y);
        }

    }
'''

compiler_result = scryptlib.compile_contract(contract_source, from_string=True)

The resulting contract description file will be written to ./out by default. That may also be changed with the out_dir parameter. You can access the contract description directly from the CompilerResult with its to_desc() method.

Evaluating a contract locally

We can evaluate any public function of the contract locally on our machine, before broadcasting it.

First we need to create a class representation of the contract and instantiate it:

import scryptlib
from scryptlib.types import Int

EQUAL_VAL = 2021

contract = './test/res/equals.scrypt'

compiler_result = scryptlib.compile_contract(contract)
desc = compiler_result.to_desc()

Equals = scryptlib.build_contract_class(desc)
contract_obj = Equals(Int(EQUAL_VAL))

As we can see, the created class takes the contract parameters in the constructor. In the case of the Equals contract, that is an sCrypt int type, which we can represent in Python using an instance of scryptlib.types.Int.

Once we have an instance of the contract class, we can evaluate its public functions:

verify_result = contract_obj.equals(Int(EQUAL_VAL)).verify()
assert verify_result == True

From the example see, that we called the contracts public function, named equals. The actual call to equals() in Python reutrns an instance of scryptlib.abi.FunctionCall. That object in turn has a method, named verify, with which we can run the function calls unlocking script against the contracts locking script. verify can internaly create an input evaluation context for simple contracts, but once we start using more advanced constructs, like signatures, we can pass an instance of bitconx.TxInputContext, using the tx_input_context parameter.

py-scryptlib leverages the bitcoinx library to deal with Bitcoin primitives.

The following is an example of a local evaluation of a P2PKH contract:

import pytest
import scryptlib
from scryptlib.types import Sig, PubKey, Ripemd160

import bitcoinx
from bitcoinx import SigHash, PrivateKey, pack_byte


key_priv = PrivateKey.from_arbitrary_bytes(b'test123')
key_pub = key_priv.public_key
pubkey_hash = key_pub.hash160()

contract = './test/res/p2pkh.scrypt'

compiler_result = scryptlib.compile_contract(contract)
desc = compiler_result.to_desc()

P2PKH = scryptlib.build_contract_class(desc)
p2pkh_obj = P2PKH(Ripemd160(pubkey_hash))

context = scryptlib.create_dummy_input_context()

sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID)
input_idx = 0
utxo_satoshis = context.utxo.value
sighash = context.tx.signature_hash(input_idx, utxo_satoshis, p2pkh_obj.locking_script, sighash_flag)

sig = key_priv.sign(sighash, hasher=None)
sig = sig + pack_byte(sighash_flag)

verify_result = p2pkh_obj.unlock(Sig(sig), PubKey(key_pub)).verify(context)
assert verify_result == True

You can find many other examples under test/test_contract_*.

Testing

The SDK has a suite of unit tests, which we can run by executing the pytest command in the root of the project.

About

sCrypt SDK for Python

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 100.0%