NexScript is a high-level programming language for Nexa smart contracts. It offers a strong abstraction layer over the Nexa Scripting language. The Nexscript playground allows developers to deploy and interact with Nexa smart contracts. This tutorial explains how to develop, deploy, fund, and interact with the default TransferWithTimeout NexScript smart contract.
Open Nexscript playground in your browser and decide if you will use Nexa mainnet or Nexa testnet. Using the NexScript playground in mainnet requires some Nexa coins, or you can get some tNexa testnet coins from the tNexa faucet and use the playground in testnet mode.
Select Nexa mainnet or Nexa testnet
After the contract has been deployed, we will fund it by sending Nexa to the contract’s address. The contract functions dictate the rules for unlocking and spending the Nexa from the contract’s address.
The following is the default NexScript Nexa smart contract code from the Nexscript playground:
pragma nexscript >= 0.8.0;
contract TransferWithTimeout(pubkey sender, pubkey recipient, int timeout) {
// Require recipient's signature to match
function transfer(sig recipientSig) {
require(checkSig(recipientSig, recipient));
}
// Require timeout time to be reached and sender's signature to match
function timeout(sig senderSig) {
require(checkSig(senderSig, sender));
require(tx.time >= timeout);
}
}
The transfer(..)
function only transfers Nexa from the contract address to the recipient if the recipient’s signature matches the recipient’s public key.
The timeout(..)
function only transfers funds from the contract to the sender if the sender’s signature matches the sender’s public key and the timeout check passes.
The timeout check compares the timeout argument with the global Nexscript variable tx.time:
The value of
tx.time
can either represent the block number of the spending transaction or its timestamp. When comparing it with values below500,000,000
, it is treated as a blocknumber, while higher values are treated as a timestamp.
For the sake of this tutorial, we will set the timeout argument to represent block number 42000, which will cause the timeout check to always pass since block number 42000 has been mined.
Generate the contract artifact
To generate the contract artifact, click the pink Compile button at the bottom of the page. This will generate aNexa contract artifact that contains all the information needed to deploy and interact with the TransferWithTimeout contract. The contract artifact for the TransferWithTimeout contract is now displayed in the Nexscript playground:
Overview of the contract artifact for TransferWithTimeout
The contract artifact is a JSON file that can be easily downloaded from the playground by clicking “download JSON file” and has the following contents:
{
"contracts": [
{
"contractName": "TransferWithTimeout",
"constructorInputs": [
{
"name": "sender",
"type": "pubkey",
"visible": false,
"unused": false
},
{
"name": "recipient",
"type": "pubkey",
"visible": false,
"unused": false
},
{
"name": "timeout",
"type": "int",
"visible": false,
"unused": false
}
],
"abi": [
{
"name": "transfer",
"inputs": [
{
"name": "recipientSig",
"type": "sig"
}
]
},
{
"name": "timeout",
"inputs": [
{
"name": "senderSig",
"type": "sig"
}
]
}
],
"dependencies": [],
"bytecode": "OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_3 OP_PICK OP_0 OP_NUMEQUAL OP_IF OP_4 OP_ROLL OP_ROT OP_CHECKSIGVERIFY OP_2DROP OP_DROP OP_ELSE OP_3 OP_ROLL OP_1 OP_NUMEQUALVERIFY OP_3 OP_ROLL OP_SWAP OP_CHECKSIGVERIFY OP_SWAP OP_CHECKLOCKTIMEVERIFY OP_2DROP OP_ENDIF",
"contracts": []
}
],
"source": "pragma nexscript >= 0.8.0;\n \ncontract TransferWithTimeout(pubkey sender, pubkey recipient, int timeout) {\n // Require recipient's signature to match\n function transfer(sig recipientSig) {\n require(checkSig(recipientSig, recipient));\n }\n \n // Require timeout time to be reached and sender's signature to match\n function timeout(sig senderSig) {\n require(checkSig(senderSig, sender));\n require(tx.time >= timeout);\n }\n}\n",
"compiler": {
"name": "nexc",
"version": "1.0.2"
},
"updatedAt": "2024-09-08T10:52:43.351Z"
}
Notably, contractName:
and the constructorInputs:
are required to construct and deploy the contract.
Deploy
To deploy the TransferWithTimeout contract, navigate to the New Contract page and select the TransferWithTimeout artifact from the dropdown. Set the contract name to MyFirstContract. Each contract must have an unique name.
Contract name: MyFirstContract
The constructor input arguments required to construct the contract are the sender public key, recipient public key, and timeout.
To create a public key for the sender and the recipient, navigate to the Wallets page and add two wallets. Label one wallet “sender” and one “recipient”
Clicking “Add” creates a new wallet.
Click the sender’s public key hex to copy the sender’s public key, then navigate to the New Contract page, paste it into the pubkey sender field, navigate back to the Wallets page, copy the recipient public key hex, navigate to New Contract and paste it into the pubkey recipient field:
New contract with name and arguments
Click the pink create button to create the address. You should get the following alert to indicate that the contract is created and deployed to the Nexa blockchain successfully:
Contract deployed
Fund contract
Navigate to the Contracts page to see the newly deployed contract.
Deployed contract with contract address and QR-code to fund the contract
Copy the contract address or scan the QR code to send (say, 2000 NEX) worth of Nexa or testnet Nexa to the contract. Then click the pink refresh button to see the Nexa balance of the contract address.
The contract address has 2000 NEX worth of Nexa
Interacting with the contract
Navigate to the TransactionBuilder page and select MyFirstContract from the dropdown menu. First, to interact with the transfer function, select the recipient wallet as the sig recipientSig argument from the dropdown.
Navigate to the Wallets page and copy the recipient’s Nexa address. Then, navigate back to the TransactionBuilder page and paste the recipient’s address as output #0’s receiver’s address. Set the satoshi amount to 750 satoshi to send 750 satoshi (7,5 NEX) worth of Nexa from the contract’s address to the recipient’s address.
Argument selected, recipient’s address and amount filled.
Click the pink Send button to call the transfer(..)
function; after a slight delay, you should get the following success alert with a link to the transaction in the Nexa testnet explorer.
transfer() function successfully called
Navigate to the Wallets page and click the pink refresh button in the recipient wallet. You can now see that it has a balance of 7,5 NEX or 750 sats (satoshis).
recipient wallet after refreshing
Navigate back to the TransactionBuilder page to interact with the timeout(..)
function. Select the sender wallet as the sig senderSig argument, navigate to the Wallets page, copy the sender’s address, and navigate back to the TransactionBuilder page. Paste in the address in the output #0 (receiver’s address) field and set the amount to 4200 satoshi for sending 42 NEX worth of Nexa from the contract’s address to the sender’s address
An argument is selected, and the recipient’s address and amount are filled out.
Click the pink Send button to send the transaction and get the same success popup as before. Navigate to the Wallets page and click the pink refresh button in the sender’s wallet to update the balance and verify that the contract worked.
Congratulation! You have successfully deployed a nexa smart contract and interacted with its functions using NexScript.
Further, join the NexScript Telegram channel to ask questions and keep exploring NexScript!
Disclaimer: The original article was written by @jQrgen on Medium and can be found here.