Use sCrypt to implement a simple Token smart contract

A long time ago, some people began to study the tokenization of external assets on the Bitcoin network, and many related protocols were also produced. Overall, most of these agreements by the representative of the original information assets through such OP_RETURNconduct on the chain after the operation code into the script and the like, in order to achieve the "Asset chain" process. But because the logic used to execute and verify these metadata is not done by Bitcoin miners, these solutions are called Layer 2 solutions.

Different from the previous work, what we are about to introduce here is a mechanism for implementing the first-level Token smart contract. The core of this scheme is to rely on the miners of the Bitcoin network to complete the relevant logic and verification of the contract at the consensus layer, thereby further improving the security and reliability of the Token contract. We use the sCrypt language to implement a simple example (only 2 token holders).

Token smart contract

Token status table

Using the stateful Bitcoin smart contract technology we introduced before , we can store the entire Token holder information table in the state of the contract. In fact, this information table is a map structure that holds the public key address of each holder and its corresponding holding share. As shown below:

tokenTable

The specific Token contract implementation can be found here :

import "util.scrypt";

/**
 * A toy token example between two holders
 */
contract Token {
    
    
    public function transfer(PubKey sender, Sig senderSig, PubKey receiver, 
	 int value /* amount to be transferred */, bytes txPreimage, int amount) {
    
    
        
        // this ensures the preimage is for the current tx
	 require(Tx.checkPreimage(txPreimage));

        // authorize
        require(checkSig(senderSig, sender));

        // read previous locking script
        bytes lockingScript = Util.scriptCode(txPreimage);
        int scriptLen = length(lockingScript);

        PubKey pk0 = PubKey(lockingScript[scriptLen - 68 : scriptLen - 35]);
        int balance0 = unpack(lockingScript[scriptLen - 35 : scriptLen - 34]);
        PubKey pk1 = PubKey(lockingScript[scriptLen - 34 : scriptLen - 1]);
        int balance1 = unpack(lockingScript[scriptLen - 1 : ]);

        // only between two holders
        require(sender == pk0 && receiver == pk1 || sender == pk1  && receiver == pk0);

        // transfer
        if (sender == pk0) {
    
    
            require(balance0 >= value);
            balance0 = balance0 - value;
            balance1 = balance1 + value;
        } else {
    
    
            require(balance1 >= value);
            balance1 = balance1 - value;
            balance0 = balance0 + value;
        }

        // write new locking script
        bytes lockingScript_ = lockingScript[: scriptLen - 68] + pk0 + num2bin(balance0, 1) + pk1 + num2bin(balance1, 1);
        bytes hashOutputs = Util.hashOutputs(txPreimage);
        Sha256 hashOutputs_ = hash256(num2bin(amount, 8) + Util.writeVarint(lockingScript_));
		require(hashOutputs == hashOutputs_);
    }
}

As introduced in the previous article , first we need to verify that the preimage parameter is indeed the current transaction:

require(Tx.checkPreimage(txPreimage));

The following line of code ensures that only the owner can transfer the token:

require(checkSig(senderSig, sender));

The rest of the code is to verify and maintain the internal state of the contract. The process here is similar to the one in the previous article.

Token issuance

Here is the Javascript sample code for deploying and transferring tokens. The deployment transaction of the contract is Tx1 . We can see that pk0the value 024c79d694ef7dfd53217de55f7fbf63d2381b18e31afc408b226bc88a6a3cb4f0, the initial balance of its token 100; pk1value 038ad6e71978a3bcc2974b7106f91a61cf03b184189c67ceb1e34e4e7cc898c2aa, it is 0 token initial balance. The parts marked in red in the following figure are their respective balances:
Tx1

Token transfer

Next, pk0 transfers 40 tokens to pk1 , and the corresponding transaction is Tx2 . Then the balance of pk0 will become 60 ( 0x3c in hexadecimal), and the balance of pk1 will become 40 (0x28 in hexadecimal).
Tx2

Finally, pk1 transfers 10 tokens back to pk0 , and the corresponding transaction is Tx3 . In the end, their balances are pk0 70 (0x46) and pk1 30 (0x1e).
Tx3

in conclusion

Here we only show how to transfer tokens between two owners. In fact, the actual contract that can be used is much more complicated than this, for example, the logic of checking the balance before the transfer is added. Of course, similar extensions should be feasible. Thanks to the scalability of the Bitcoin SV network, any first-tier Token contract that can extend this contract can run at a very low cost. Coupled with many previous second-layer tokenization protocols, it opens up unlimited possibilities in the future for us explorers of the blockchain world.

Guess you like

Origin blog.csdn.net/freedomhero/article/details/107308691