Tutorial 3: Mint BSV20 Token
Overview
In this tutorial, we will use contract HashLock as an example, to introduce how to mint a BSV20 Token (version 1) with sCrypt and transfer it with a Smart Contract.
To enable all these features, you should install scrypt-ord
as an dependency in your project.
npm install scrypt-ord
Contract
The new contract HashLockFT
is almost the same as the previous implementation, except two differences.
- It must be derived from
BSV20V1
instead ofSmartContract
.
class HashLockFT extends BSV20 {
...
}
- The constructor has extra parameters -
tick
,max
,lim
, anddec
- representing BSV20 fields.
constructor(tick: ByteString, max: bigint, lim: bigint, dec: bigint, hash: Sha256) {
super(tick, max, lim, dec)
this.init(...arguments)
this.hash = hash
}
The contract also stores a hash value in the contract, and it will be unlocked successfully when calling the public method unlock
with the correct message.
class HashLockFT extends BSV20 {
@prop()
hash: Sha256
...
@method()
public unlock(message: ByteString) {
assert(this.hash == sha256(message), 'hashes are not equal')
}
}
The base class BSV20
encapsulated helper functions to handle BSV20 (version 1) tokens. If you want to create your own contract that can interact with BSV20 protocol, derive from it.
Deploy and Mint
For BSV20 version 1, tokens must be deployed before mint. We first create an instance of contract HashLockFT
, then call function deployToken
to deploy the new token, and call mint
at last to mint tokens into the contract instance.
// BSV20 fields
const tick = toByteString('HELLO', true)
const max = 100n
const lim = 10n
const dec = 0n
// create contract instance
const message = toByteString('Hello sCrypt', true)
const hash = sha256(message)
const hashLock = new HashLockFT(tick, max, lim, dec, hash)
...
// deploy the new BSV20 token $HELLO
await hashLock.deployToken()
// mint 10 $HELLO into contract instance
const mintTx = await hashLock.mint(10n)
Normally, we use a P2PKH address to receive the token, then the token is controlled by a private key the same as the general P2PKH.
In this example, the token is mint to a contract instance, it is controlled by the smart contract, which means it can only be transferred when the hash lock is unlocked.
Transfer Token
For now, the contract instance holds the token and we try to transfer it to a P2PKH address.
Step 1. Create Receiver Instance
Class BSV20P2PKH
represents a P2PKH address that can hold BSV20 version 1 tokens. Its constructor takes BSV20 fields and an receiving address as parameters.
const alice = new BSV20V1P2PKH(tick, max, lim, dec, addressAlice)
const bob = new BSV20V1P2PKH(tick, max, lim, dec, addressBob)
Step 2. Call the Contract
Just as other contract calling methods we introduced before, we call the public method unlock
of HashLockFT
as follows.
// Call the contract
const { tx: transferTx } = await hashLock.methods.unlock(message, {
transfer: [
{
instance: alice,
amt: 2n,
},
{
instance: bob,
amt: 5n,
},
],
} as OrdiMethodCallOptions<HashLockFT>)
This code will create a transaction that transfers 2 tokens to alice
and 5 to bob
.
The default transaction builder will automatically add a token change output on the transaction. In this example, it will automatically add a token change output with 3 tokens, paying to the default address of the instance connected signer. You can also specify the token change address by passing the value to the key tokenChangeAddress
of struct OrdiMethodCallOptions
.
Execute command npx ts-node tests/examples/mintBSV20.ts
to run this example.
Then you can check your token transfer details on the explorer.
The UTXO model is a powerful feature of BSV20, we can send tokens to multiple receivers in a single transaction, allowing us to create complex and efficient transactions.
Conclusion
Great! You have finished the tutorial on how to mint and transfer the BSV20 Token with a Smart Contract.
The full complete contract and example can be found in sCrypt's repository.