Quick Example

MetaID-TS-SDK 源代码已发布在 Github 上,相关 API 和示例代码请以 Github 最新页面为准

https://github.com/metaid-developers/metaid

Intro

Bitbuzz is a front-end social application based on the MetaID protocol and running on the testnet of BTC blockchain. It has the following basic functions: new user registration, setting user basic information, publishing buzz (with attached pictures), liking buzz. In this article, I will show you how to build this project with MetaID SDK step by step. I will presume you have a basic understanding of MetaID Specification.

Creating a MetaID Account With SDK

Creating a MetaID Account is very easy, the following code will use a connector which is connected to a Metalet wallet. Then it will check whether the Metalet account has built a MetaID account, if not , it will accept the body parameter(optional parameter, including name、bio、avatar) provided by the user to create a new MetaID account.

import { MetaletWalletForBtc, btcConnect } from '@metaid/metaid';

 
const _btcConnector: BtcConnector = await btcConnect(_wallet);

const handleCreateMetaid = async (userInfo) => {
  const userInfo = {name:'Bob', bio:'Success needs time.', avatar:'imageUrl'}
	if (!_btcConnector.hasMetaid()) {
      const createRes = await btcConnector.createMetaid({ ...userInfo, network });
    } else {
      const resUser = await _btcConnector.getUser();
    }
};

Connecting to BTC Blockchain

Like most blockchains, we need a wallet account to connect to the blockchain. Here we use Metalet wallet as an example. Assume you have created a MetaID account based on last step and have a handleLogin method for your application triggered when user clicks the login button. We need to apply MetaID SDK to establish a connection between the application and the wallet. This is the foundation for users to send data to the blockchain.

import {  MetaletWallet, connect } from "@metaid/metaid";

 
const handleLogin = async () => {
    const _wallet = await MetaletWallet.create();
    const baseConnector = await connect(_wallet);
 
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |. |

Define the required entities

On top of the foundation established in the previous step, it's time for Entity to come into play. We utilize theuse keyword to create an entity. For the buzzhub application, we need a “Buzz” entity. With this entity, we can get the existing buzz data and send a new buzz to the BTC blockchain. The following code block implements the 'getBuzzList' function. The 'page' parameter is used to query paginated data. It's worth noting that 'connect' can be passed an empty object, and based on this, the created entity can only retrieve data from the blockchain but cannot send data to the blockchain (used for displaying data in an unauthenticated state. (Remember every buzz is just a Pin result)

 
const getBuzzList = async ({ page, limit } ) => {
    const	buzzEntity = await baseConnector.use("buzz");
    const buzzList = await buzzEntity.list({ page, limit });;
 
};

Send data to the blockchain with Entity

When you get the buzzEntity variable, you can use its create method to publish a new buzz and store it on the blockchain. For each type of Entity, you need to set a Schema file which is used to define the format for on-chain data. For example, according to the definition of simplebuzz which comes from metaprotocols, we have our buzz.entity.ts schema file for the Buzz entity.

type EntitySchema = {
  name: string
  path:string
  versions: {
    version: number
    body: any[]
  }[]
}

const buzzSchema: EntitySchema = {
  name: 'buzz',
  path: '/protocols/simplebuzz',
  versions: [
    {
      version: 1,
      body: [
        {
          name: 'content',
          type: 'string',
        },
        {
          name: 'attachments',
          type: 'array',
        },
      ],
    },
  ],
}

Sending a buzz with only text information is simple; it only requires a few lines of code. The first argument passed to the 'create' method comes from the 'body' field defined in the 'buzzSchema'.

const	buzzEntity = await baseConnector.use("buzz");
const finalBodybody = { content: "Hello World", attachments: [] }
const createRes = await buzzEntity.create({
				options: [{ body: JSON.stringify(finalBody) }],
				noBroadcast: "no",
			});

Send multiple entities’ data to the blockchain

Assuming you need to post a buzz with some image attachments. That is, we need to populate the attachments field of the body parameter. A unique pinID(transaction id of this file create pin) is generated for each image file uploaded to the blockchain. Each string element in the attachments array relies on this txid, and the exact string prefix will vary depending on the type of file protocol (metacontract, sensible, etc.).We need to define a new File entity to implement the logic described above, according to the MetaFile protocol, we have the following code definition for the File entity schema.

const fileSchema = {
  name: 'file',
  nodeName: 'MetaFile',
  encoding: 'binary',
  versions: [
    {
      version: '1.0.1',
      body: '',
    },
  ],
}

then we can generate txid based on this schema. It is worth noting that you need to transform binary image data to hex format with Buffer.from method.

const finalBody: any = { content: buzz.content };
if (!isEmpty(buzz.images)) {
	const fileOptions = [];

	const fileEntity = await btcConnector!.use("file");

	for (const image of buzz.images) {
			fileOptions.push({
			body: Buffer.from(image.data, "hex").toString("base64"),
			contentType: "image/jpeg",
			encoding: "base64", // this encoding field is for wallet inscription API,
			toEncoding: fileSchema.encoding
		});
	}
	const imageRes = await fileEntity.create({
		options: fileOptions,
		noBroadcast: "no",
	});

		finalBody.attachments = imageRes.revealTxIds.map(
		(rid) => "metafile://" + rid + "i0"
	);
}

As you can see, The create method accepts options parameter.

type CreateOptions = {
    body?: string | Buffer;
    contentType?: string;   
    encryption?: "0" | "1" | "2"; 
    version?: string;  
    encoding?: BufferEncoding;  
}
const createRes = await buzzEntity.create({
    options,
    noBroadcast,
  }: {
    options: CreateOptions[]
    noBroadcast: 'yes' | 'no'
  })

When you need to send multiple entities data to the blockchain. Until the last create method, you need to set the value of the options.serialAction parameter to combo in the previous create method.The purpose of this action is to bundle multiple transactions, thus avoiding multiple pop-ups when signing the transaction with the Metalet wallet and achieving a better user experience.

Finally, we can create a buzz with three image attachments:

const createRes = await buzzEntity!.create({
				options: [{ body: JSON.stringify(finalBody) }],
				noBroadcast: "no",
			});

Build relationships between different user’s data

Imagine a scenario where as a BuzzHub user, you come across a buzz posted by someone else and you want to like it. Essentially, this scenario involves establishing an association between the data of two end-user accounts.

First we need a new Like entity, base on its metaprocols definition, we have the following like entity schema definition.

const likeSchema = {
  name: 'like',
  path: '/protocols/payLike',
  versions: [
    {
      version: 1,
      body: [
        {
          name: 'likeTo',
          type: 'string',
        },
        {
          name: 'isLike',
          type: 'string',
        },
      ],
    },
  ],
}
const likeEntity = btcConnector.use('like')

And then, based on a logged-in MetaID account, you can like any buzz by calling this likeEntity.create method.The corresponding code is quite simple.


const res = await likeEntity.create({ likeTo: pinId, isLike: '1' }, 
                                     { signMessage: 'like buzz' })
 //  pinId is from the buzz bin you want to like,
 //  it is caculated by the buzz's txid + 'io'                    

Live Example

Code Link

Website Link