Tutorial

This is a small (but growing) collection of simple recipes to perform common tasks with the Maxonrow blockchain.

If there is a simple recipe you would like to add, please send suggestions to support@maxonrow.com.


Learning Objectives:

This tutorial will show you how to create a list of sample methods used in Online Learning application. TypeScript will be usedas the example programming language. This tutorial assumes some basic understanding of blockchain.


Prerequisites:

Before proceeding, make sure you have installed:

* VS Code version 1.42 or newer
* Node.js v10.x or newer
* npm v6.x or newer (will be installed alongside node)

You can check your installed versions by running the following commands from a terminal: | node --version | npm --version


Flight Ticketing System Tutorial

Introduction:
This tutorial shows various basic usage of mxw-sdk-js in creating a flight ticketing system.

1. Initial setup

To begin, let’s set up project directory such as:

/flight-ticket-tutorial
/src
/package.json

Create a new file name ‘flight-ticket.ts’ in folder [/flight-ticket-tutorial/src/].

2. Create NFT

Firstly, we need to create an NFT. In this case, the airline is responsible for creating the NFT.

//set NFT properties
let ntfProperties = {
   name: "my2sgFlightTicket05",
   symbol: "my2sg05",
   fee: {
      to: "mxw1qgwzdxf66tp5mjpkpfe593nvsst7qzfxzqq73d",
      value: bigNumberify("1")
   },
   properties: "fMYtSG@5",
   metadata: "nothing"
};

//create NFT token using properties shown above
token.NonFungibleToken.create(ntfProperties,issuer).then((token)=>{
   console.log(JSON.stringify(token))
});

Note

properties can’t be changed afterwards, it can use as a notes for imporant details,while metadata can be changed.

3. Query NFT

After the NFT is created we can use fromSymbol() method to query the NFT, and get its details.

//Query token, to update/ refresh all data of the token
mxw.nonFungibleToken.NonFungibleToken.fromSymbol("my2sg05",issuer).then((token)=>{
   console.log(JSON.stringify(token))
});

3. Authorise NFT

Before the NFT can be use inside Maxonrow blockchain, it have to be authorized by three parties (provider, issuer and middleware).

//setup token state in order to authorise token
let tokenState = {
   tokenFees: [
      { action: NonFungibleTokenActions.transfer, feeName: "default" },
      { action: NonFungibleTokenActions.transferOwnership, feeName: "default" },
      { action: NonFungibleTokenActions.acceptOwnership, feeName: "default" }
   ],
   endorserList: [],
   mintLimit: 10,
   transferLimit: 1,
   burnable: false,
   pub: false
};

//authorise token
token.NonFungibleToken.approveNonFungibleToken("my2sg05", provider, tokenState).then((transaction) => {
   token.NonFungibleToken.signNonFungibleTokenStatusTransaction(transaction, issuer).then((transaction) => {
      token.NonFungibleToken.sendNonFungibleTokenStatusTransaction(transaction, middleware).then((receipt) => {
            console.log("approve"+receipt);
      });
   });
});

4. Mint NFT item

After the NFT is authorized, the owner(airline) can start to mint items (print out tickets) to the passenger.

//setup item properties
let itemPro = {
symbol: "my2sg05",
itemID: "004",
properties: "from05,to06",
metadata:" nothing"
};

//mint item using the token created earlier by passing in the item properties
var minter = new NonFungibleToken("my2sg05",issuer);
minter.mint(issuer.address,itemPro).then((receipt)=>{
console.log(JSON.stringify(receipt));
});

5. Transfer NFT item

After the item is created, it will be owned by the NFT owner. So we have to transfer it to the passenger’s wallet.

//transfer item
var nonFungibleTokenItem = new NonFungibleTokenItem("my2sg05","001", issuer);
 nonFungibleTokenItem.transfer(wallet.address).then((receipt) => {
     console.log(receipt);
 })

6. Endorse item

On passenger boarding the plane, we can endorse the item by doing so we can ensure that the passenger, has been on the plane.

//endorse item
var nftInstance = new NonFungibleTokenItem("my2sg05","001", issuer);
nftInstance.endorse().then((receipt) => {
      console.log(receipt);
});

7. Overwrite the metadata

As we mentioned earlier, both metadata of the NFT and item can be change by using updateMetadata() method. For this case we will overwrite the item metadata.

//overwrite the item metadata with string "overwrite"
nftInstance.updateMetadata("overwrite")

var nftItemStatus;
nftInstance.getState().then((result)=>{
   nftItemStatus = result.metadata;
});

8. Add new info into the metadata

If we query the item metadata and cache it first. We can adding new infomation on exsiting metadata.

var nftItemStatus;
nftInstance.getState().then((result)=>{
   nftItemStatus = result.metadata;
});

//adding new info into the item metadata
nftInstance.updateMetadata(nftItemStatus+ "adding new").then((receipt)=>{
   console.log(receipt.status);
});
nftInstance.getState().then((result)=>{
   nftItemStatus = result.metadata;
});

9. Freeze item

In some cases, we might have to cancel or delay the flight. We can use the freeze the item to prevent owner using it, but this operation must be authorized by three parties.

//freeze item
token.NonFungibleToken.freezeNonFungibleTokenItem("my2sg05","003",provider).then((transaction) => {
   token.NonFungibleToken.signNonFungibleTokenItemStatusTransaction(transaction, issuer).then((transaction) => {
      token.NonFungibleToken.sendNonFungibleTokenItemStatusTransaction(transaction, middleware).then((receipt) => {
            console.log(JSON.stringify(receipt));
            return receipt
      });
   });
});

10. Unfreeze item

After the freezing, we can unfreeze it back. As unfreeze and freeze are administrative operation, it must be authorized by three parties.

//unfreeze item
token.NonFungibleToken.unfreezeNonFungibleTokenItem("my2sg05","003",provider).then((transaction) => {
   token.NonFungibleToken.signNonFungibleTokenItemStatusTransaction(transaction, issuer).then((transaction) => {
      token.NonFungibleToken.sendNonFungibleTokenItemStatusTransaction(transaction, middleware).then((receipt) => {
            console.log(JSON.stringify(receipt));
            return receipt
      });
   });
});

11. Burn item

At last, the owner of the item can choose to burn the item(ticket) he owned.

//burn item
var nftInstance = new NonFungibleTokenItem("my2sg05","005", issuer);
nftInstance.burn().then((receipt) => {
   console.log(JSON.stringify(receipt));
});

Note

Flight Ticketing System tutorial is organized like a module. To run the code, first compile using tsc, then run with command:
node dist/flight-ticket.js

Online Learning Tutorial

Introduction:
This tutorial create a simple Online Learning application. The functions included here are: enrol student, add and approve course, student enrol to course.

1. Initial setup

To start with, we’ll setup project directory like the following:

/online-learning-tutorial
/src
/package.json

Note

You can create package.json file using npm init command.

1. On the command line, navigate to the root directory of your package
cd /path/to/OnlineLearning
2. Run the following command:
npm init
3. Answer the questions in the command line questionnaire

Please refer to Getting Started guide “Installing in Node.js” to include mxw-sdk-js library in the project.

Let’s start by creating a file named online-learning.ts in folder [/online-learning-tutorial/src].

2. Enrol new Student (create new Wallet instance)

Wallet is an “account” created by each user inside Maxonrow blockchain. But for this tutorial, the wallet instance will represent student who wants to enroll this online course.

registerNewStudent() {
   // create wallet instance
   let student: mxw.Wallet = mxw.Wallet.createRandom();

   console.log("Wallet address:", student.address);
   // sample output: mxw18mt86al0xpgh2qhvyeqgf8m96xpwz55sdfwc8n
   console.log("Wallet mnemonic:", student.mnemonic);
   // sample output: unaware timber engage dust away host narrow market hurry wave inherit bracket

   // connect to provider
   student.connect(this.providerConn);
}

Once a Wallet is created using createRandom() method, we can use the Wallet fromMnemonic() method to load an instance of the wallet that we just created.

let student: mxw.Wallet = mxw.Wallet.fromMnemonic("unaware timber engage dust away host narrow market hurry wave inherit bracket");

Note

For various options on how to create a Wallet instance, please refer to Wallet SDK. This tutorial is using simplest way to create Wallet instance.

connect() - to connect the Wallet instance to Provider.

3. Add new course

Non-Fungible-Token (NFT) is a token created and hold by a course owner, it can use to mint item (create seats) to the student who wants to attend the course.

Please note that the NFT properties symbol must be unique.
If we attempt to create NFT using same symbol, an error will be thrown.
createNewCourse(courseName: string) {

   nonFungibleTokenProperties = {
      name: courseName,
      symbol: courseName,
      fee: {
            to: nodeProvider.nonFungibleToken.feeCollector,
            value: bigNumberify("1")
      },
      metadata: "Course " + courseName,
      properties: courseName
   };

   // create NFT using above properties
   return token.NonFungibleToken.create(nonFungibleTokenProperties, issuer, defaultOverrides).then((token) => {
      console.log("Symbol:", nonFungibleTokenProperties.symbol);
   });
}

If we want to check on the course details, we can use the symbol to query the NFT.

var minter = new NonFungibleToken(courseSymbol, issuer);

4. Approve course

Before the course owner can start to mint item, the NFT must be authorized by three parties, (provider, issuer and middleware). As part the procedure of authorization, inside the approveNonFungibleToken() method, we need to pass in the NFT state.

approveCourse(courseSymbol: string, seatLimit: number) {
   let nftState = {
      tokenFees: [
            { action: NonFungibleTokenActions.transfer, feeName: "default" },
            { action: NonFungibleTokenActions.transferOwnership, feeName: "default" },
            { action: NonFungibleTokenActions.acceptOwnership, feeName: "default" }
      ],
      endorserList: [],
      mintLimit: seatLimit,
      transferLimit: 1,
      burnable: true,
      transferable: true,
      modifiable: true,
      pub: false   // not public
   };

   // provider approves NFT, at same time, set NFT with above state
   return token.NonFungibleToken.approveNonFungibleToken(courseSymbol, provider, nftState)
      .then((transaction) => {
            // issuer signs NFT status transaction
            return token.NonFungibleToken.signNonFungibleTokenStatusTransaction(transaction, issuer);
      }).then((transaction) => {
            // middleware sends NFT NFT status transaction
            return token.NonFungibleToken.sendNonFungibleTokenStatusTransaction(transaction, middleware)
               .then((receipt) => {
                  console.log(receipt);
                  return receipt;
               });
      });
}

5. Student enrol course

In this part will performs two actions:

1. Mint an item (issue course entry pass)
2. Transfer item to wallet (transfer entry pass to student)
enrolStudentToCourse(student: mxw.Wallet, courseSymbol: string, theId: number) {
   return this.mintItem(courseSymbol, theId) // mint course entry pass
      .then((nftItem) => {
            let itemId = courseSymbol + "#" + theId;
            return this.transferItem(nftItem, itemId, student); // transfer pass to student
      })
      .catch(error => { // handle error, if any
            console.log("enrolStudentToCourse", error);
            throw error;
      });
}

mintItem() method mints an item. When item is created, by default it will be owned by the NFT token owner. A token can’t mint item more that its mint limit. The item’s symbol must same the course symbol. Use getNftItemState() method to queries and prints out the NFT item state.

mintItem(courseSymbol: string, theId: number) { // query NFT created before
   var minter = new NonFungibleToken(courseSymbol, issuer);
   let itemId = courseSymbol + '#' + theId;
   let properties = "Course " + courseSymbol + " - Seat #" + theId;
   let itemProp = {
      symbol: courseSymbol, // value must be same with NFT symbol, the parent
      itemID: itemId, // value must be unique for same NFT
      properties: properties,
      metadata: properties
   } as token.NonFungibleTokenItem;

   // mint item to issuer wallet, with item properties defined above
   return minter.mint(issuer.address, itemProp)
      .then((receipt) => {
            console.log("Mint item receipt:", receipt);
            return NonFungibleTokenItem.fromSymbol(courseSymbol, itemId, issuer);
      }).then((nftItem) => {
            return this.getNftItemState(nftItem); // print out the NFT item state
      })
      .catch(error => { // handle error, if any
            console.log("mintItem", error);
            throw error;
      });
}

transferItem() transfers NFT item ownership to the recipient wallet, in this case, the student. overrides is optional when transferring item.

transferItem(nftItem: NonFungibleTokenItem, itemId: string, student: mxw.Wallet) {
   let overrides = { memo: itemId + " transferred to " + student.address }; // optional

   // transfer NFT item to student
   return nftItem.transfer(student.address, overrides)
      .then((receipt) => {
            console.log("Transfer NFT item receipt:", JSON.stringify(receipt));
            return nftItem;
      }).then((nftItem) => {
            return this.getNftItemState(nftItem); // print out the NFT item state
      })
      .catch(error => { // handle error, if any
            console.log("transferItem", error);
            throw error;
      });
}

getNftItemState() queries and prints out the NFT item state.

getNftItemState(nftItem: NonFungibleTokenItem) {
   return nftItem.getState() // query NFT item state
      .then((itemState) => {
            console.log("Item state:", JSON.stringify(itemState)); // print NFT item state
            return nftItem;
      })
      .catch(error => { // handle error, if any
            console.log("getNftItemState", error);
            throw error;
      });
}

Note

Online Learning tutorial is organized into methods for individual functions, so you can pass in different parameters to see how things work. To run the code, first compile using tsc, then run with command:
node dist/online-learning.js <method_name>
Third argument is the method to call, followed by the method’s parameter(s), if any. For example, below command shows how we can trigger addCourse() method using parameter Art:
node dist/online-learning.js addCourse Art

For complete source code, please download from here GitHub.