Core API

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

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

Overview

The MetaID SDK currently targets the BTC chain, providing corresponding API methods from three dimensions: Wallet Layer, Connector Layer, and Entity Layer. Below is a detailed introduction to the relevant API methods.

Each layer's responsibilities and relationships are outlined.

Wallet Layer API

import { MetaletWalletForBtc } from '@metaid/metaid';
// Create a wallet object based on the currently logged-in wallet account
const _wallet = await MetaletWalletForBtc.create();

// Access the wallet object's public properties
const address = _wallet.address // Get address
const pubicKey = _wallet.pub // Get public key

// Access a series of methods provided by the wallet object (provided the wallet is connected, otherwise returns {status: 'not-connected' })
await _wallet.getAddress() // Get wallet address

await _wallet.getAddressType() // Get wallet address type

await _wallet.getPublicKey(path) // Get public key based on path

await _wallet.getBalance() // Get balance

await _wallet.signMessage(message) // Send signed message

await _wallet.signPsbt({
  psbtHex,
  options,
}: {
  psbtHex: string
  options?: { toSignInputs?: ToSignInput[]; autoFinalized: boolean }
}) // Sign the input psbtHex

// This is a low-level inscription API method; unless you have very customized inscription needs, it is not recommended to call it directly. 
// The connector layer has abstracted and encapsulated this method, along with related parameter descriptions.
await _wallet.inscribe({data, options} : \
  { data: InscriptionRequest, options: {noBroadcast : boolean }) 

Notes on Wallet Method Parameters and Return Types:

  1. Example return value for getBalance:

{total: 97901828, confirmed: 97901828, unconfirmed: 0}

where confirmed and unconfirmed represent the confirmed and unconfirmed balances respectively (unit: satoshi).

  1. Example return value for getAddressType:

{name: 'Taproot', addressType: 'P2TR', path: "m/86'/0'/0'/0/0"}

BTC address types mainly include four types: Legacy (P2PKH), Nested SegWit (P2SH), Native SegWit (Bech32), and Taproot addresses.

  1. Explanation of inscribe method parameters:

export type Operation = 'init' | 'create' | 'modify' | 'revoke'
export type Encryption = '0' | '1' | '2'

export type MetaidData = {
  operation: Operation
  body?: string | Buffer
  path?: string
  contentType?: string
  encryption?: '0' | '1' | '2'
  version?: string
  encoding?: BufferEncoding
  revealAddr: string
}

export type InscriptionRequest = {
  feeRate: number;
  metaidDataList: MetaidData[];
  revealOutValue: number;
  changeAddress: string;
  minChangeValue?: number;
}
  1. The inscribe method returns different transaction data formats depending on whether broadcasting is performed:

  • If noBroadcast is set to yes, meaning no broadcasting, the return format is:

{
  commitTxHex: string;
  revealTxsHex: string[];
  commitCost: string;
  revealCost: string;
}
  • If noBroadcast is set to no, meaning broadcasting is performed, the return format is:

{
  commitTxId: string;
  revealTxIds: string[];
  commitCost: string;
  revealCost: string;
}

Where, if not broadcasting, the transaction result is returned in txHex format; otherwise, the transaction result is returned as txid. The sum of commitCost and revealCost represents the estimated fee required for the current inscription transaction.

Connector Layer API

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

// Create a new connector based on the wallet object
const _btcConnector: BtcConnector = await btcConnect({ wallet, network }: { wallet?: MetaIDWalletForBtc; network: BtcNetwork });

// If the wallet object is not empty, you can use the following method to check if the wallet has created a MetaID
_btcConnector.hasMetaid()

// The connector provides a series of methods for operating MetaID related data

type BtcNetwork = "testnet" | "regtest" | "livenet"

// Inscription method
type Operation = 'init' | 'create' | 'modify'
type InscribeOptions= {
  operation: Operation
  body?: string | Buffer
  path?: string
  contentType?: string
  encryption?: '0' | '1' | '2'
  version?: string
  encoding?: BufferEncoding
}
await _btcConnector.inscribe(inscribeOptions: InscribeOptions[], noBroadcast: 'yes' | 'no')
// The return type of this method is the same as the wallet inscribe method.

// Create MetaID, the parameter avatar is processed into Buffer in chunks from the native File type in JS, and then converted to a base64 string
const metaIdRes = await _btcConnector.createMetaid(body?: { network?: BtcNetwork, name?: string; avatar?: string })
// Return type: metaIdRes: { metaid:string }

// Get user information associated with MetaID
const user = await _btcConnector.getUser({ network, currentAddress }: { network: BtcNetwork; currentAddress?: string })

// Update user information associated with MetaID
const isUpdateSuccess = await _btcConnector.updateUserInfo(body: { name?: string; bio?: string; avatar?: string })

// Get MetaID
const currentMetaId = await _btcConnector.getMetaid()

// Check the current connector status (whether the wallet is connected)
const isConnected = await _btcConnector.isConnected()

// Disconnect the current wallet
await _btcConnector.disconnect()

// Create an Entity object, this method bridges the Connector layer and the Entity layer
await _btcConnector.use(entitySymbol: string)

Notes on Connector Layer API:

  1. From the perspective of the MetaID Specification, issuing or modifying on-chain data involves sending a PIN, and the inscription interface handles this task. Whether it's creating a MetaID, updating user information, or calling the create method after generating an Entity object, it essentially sends a PIN to put the data on-chain.

  2. For the createMetaid method of the connector object, if you pass in a complete body parameter including name, bio, and avatar, the SDK will sequentially perform the following actions: first initialize at the root path / (operation=init), then create corresponding information under the paths /info/name, /info/bio, and /info/avatar (operation=create).

  3. Regarding data timeliness, when modifying on-chain data (operation=modify/revoke), there are relevant matters to note. Please refer to the second convention in the MetaID Specification regarding modify/revoke operations.

Entity Layer API

Once you create an entity through the connector, you can access a series of properties and methods provided by that entity.

Currently, the MetaID SDK provides basic entity calls based on the on-chain microblog example application, including buzzEntity, fileEntity, and likeEntity. If developers have their own customization needs, they can create their data protocol on the MetaProtocols website, and the MetaID SDK will automatically create the corresponding entity for that protocol.

// Example of creating a buzzEntity

type BtcNetwork = "testnet" | "regtest" | "livenet"

// Create a buzzEntity entity through the connector
const buzzEntity = await _btcConnector.use('buzz')

// Get all buzzes sent by the currently connected account in a paginated manner
const allBuzz = await buzzEntity.list({ page, limit, network }: { page: number; limit: number; network?: BtcNetwork })

// Get the details of a specific Pin by its pinId
const pid = 'XXXXXXXXX' 
const pinDetail = await buzzEntity.one({ pid, network }: { pid: string; network: BtcNetwork })

// Count the total number of Pins sent under the current entity (buzzEntity)
const pinTotal = await buzzEntity.total({ network }: { network?: BtcNetwork })

// Create a buzz
type CreateOptions = {
  body?: string | Buffer;
  contentType?: string;
  encryption?: "0" | "1" | "2";
  version?: string;
  encoding?: BufferEncoding;
}

// The return type of this method is the same as the wallet inscribe method.
const createRes = await buzzEntity.create({
  options,
  noBroadcast,
}: {
  options: CreateOptions[]
  noBroadcast: 'yes' | 'no'
})

Notes on the Entity's create Method:

  1. According to the MetaID Specification, you can think of the create method as creating new files under a certain folder (file path), essentially calling the connector's inscribe method. The results vary depending on the broadcast parameter, and the specific data format can be found in the connector's inscribe method description.

  2. Explanation of the option parameter corresponding to the MetaProtocols protocol:

    • The body parameter's specific fields should refer to the corresponding MetaProtocol protocol description for that entity (e.g., buzzEntity corresponds to the SimpleBuzz protocol).

    • The contentType field represents the data format, e.g., text/plain, image/png.

    • The encryption field indicates the encryption type of the content: 0 for no encryption, 1 for ECIES encryption, and 2 for ECDH negotiated key encryption.

    • The version field specifies the protocol version number of MetaProtocols.

    • The encoding field refers to the encoding format, which aligns with the global BufferEncoding parameter in TypeScript:

      type BufferEncoding = 
          | "ascii"
          | "utf8"
          | "utf-8"
          | "utf16le"
          | "utf-16le"
          | "ucs2"
          | "ucs-2"
          | "base64"
          | "base64url"
          | "latin1"
          | "binary"
          | "hex";

      Examples for the Option Parameter

      (1) For the buzz entity, the option parameter should be:

      {
          body: "buzz content"
      }

      (2) For the file entity, assuming you are passing an image file, the option parameter should be:

      {
          body: Buffer.from('image raw hex string', "hex").toString("base64"),
          contentType: "image/jpeg",
          encoding: "base64"
      }

3. Instructions for Batch Creation (Inscription): You may have noticed that the CreateOptions parameter is passed in as an array. This means you can create multiple pieces of data for a particular type of entity simultaneously. Here's a specific example: when you post a buzz with multiple image attachments, you only need to call the inscription interface twice. First, batch inscribe multiple images using the fileEntity. The generated transaction hash array is then passed into the attachments field of the buzzEntity create method for the second inscription.