Develop WebApps with Vue using Polkadot.js

Element

个别的,以下三个因素会呈现在任何程序上的一次操作中

  • 发/收信方:Account钱包地址
  • 通道: WebSocket长连贯
  • 信息: Message可被加密

Account


依赖:

  • @polkadot/util-crypto 用于生成随机的密钥
  • @polkadot/keyring 用于治理钱包账户,/testing能够同步开发测试账户
  • @vue-polkadot/vue-settings 同步链节点的根本信息(比方转账时要用到的货币单位)
  • @vue-polkadot/vue-identicon 用于显示账户头像
  • @polkadot/util 一些工具,例如数据格式化

装置keyring

//  store.tsimport { cryptoWaitReady } from '@polkadot/util-crypto'import testKeyring from '@polkadot/keyring/testing'const myKeyring = async (store: any) => {  await cryptoWaitReady()  const keyring = testKeyring({ type: 'sr25519' })  Vue.prototype.$keyring = keyring}

在组件中调用keyring生成钱包账户

//  Account.vueimport { Vue } from 'vue-property-decorator'export default class Account extends Vue {    public newAccount: any = {        name: '',        mnemonicSeed: '',        address: '',        password: ''    }    private getAddressFromSeed(mnemonicSeed: string): any {        return this.$keyring.createFromUri(            mnemonicSeed.trim(),            this.getMeta(),            'sr25519'        )    }    private getMeta(): any {        return {            name: this.newAccount?.name || '',            whereCreated: 'Earth',            whenCreated: Date.now()        }    }}

creat接口用于创立账户,add接口用于在本地内存里增加账户。

 const json = pair.toJson(password) this.$keyring.addFromJson(json)

交易转账时,金额数据须要额定解决

static sendBalance(        sender: string | any,        recipient: string,        amount: number,        tokenDecimals: number    ): Promise<any> {        let value = numberToHex(amount * 1e3 * 10 ** (tokenDecimals || 12))        return exec(sender, 'balances', 'transfer', [recipient, value])    }

Link to Chain

将web客户端与链侧利用建设websocket长连贯,以放弃数据通信,随后将polkdot-api实例化。
执行的机会个别只需一次,产生在页面加载后。

  • connect with websocket
  • make the api global

Code

//  引入依赖import { ApiPromise, WsProvider } from '@polkadot/api'import { EventEmitter } from 'events'//  定义接口类型export interface ApiService {    connect(apiUrl: string, types: any): Promise<ApiPromise | Error>    disconnect(): void    // registerCustomTypes(userTypes: string, apiUrl?: string): Promise<ApiPromise | Error>;}/** * Singleton instance for @polkadot/api. */export default class Api extends EventEmitter implements ApiService {    private static _instance: Api = new Api()    private _api!: ApiPromise    private _apiUrl!: string    /**     * getInstance     * @returns Api Instance     */    public static getInstance(): Api {        return Api._instance    }    private constructor() {        super()    }    /**     * connect     * @requires apiUrl: string     * @returns instance of polkadot-js/api instance     */    public async connect(        apiUrl: string,        types: Record<any, any>    ): Promise<ApiPromise | Error> {        if (!apiUrl) {            throw new TypeError(                `[VUE API] ERR: Unable to init api with apiUrl ${apiUrl}`            )        }        try {            const provider = new WsProvider(apiUrl)            const apiPromise = await ApiPromise.create({ provider, types })            this.setApi(apiPromise)            this._emit('connect', apiPromise)            // const isReady = apiPromise.isReady.then(api => {            //     this.setApi(apiPromise)            //     this._emit('connect', apiPromise)            // })        } catch (err) {            this._emit('error', err)            throw err        }        this.setUrl(apiUrl)        return this._api    }    /**     * disconnect     */    public disconnect(): void {        if (this._api) {            // this._api.once('disconnected', () => this._emit('disconnect', this._apiUrl));            this._api.disconnect()            this.setUrl('')        }    }    private setApi(api: ApiPromise) {        this._api = api    }    private setUrl(apiUrl: string) {        this._apiUrl = apiUrl    }    get api(): ApiPromise {        return this._api    }    /**     * tryEmit     *     */    public _emit(message = 'event', payload?: ApiPromise | Error): void {        this.emit(message, payload)    }}

Tips:

  • websocket 连贯失败的异样无奈捕捉,暂不思考解决。
  • event 依赖次要解决connect事件的胜利/失败监听,若果在内部已有其余的异样捕捉机制则能够去掉此处。
  • @vue-polkadot/vue-api 插件和此代码性能统一,前者有些针对vue的封装。
  • @vue-polkadot/vue-api在实例化时没有传入type参数,如果有自定义type须要传入的要另做解决。

Query & Transactions

Query

import Connector from '@/api/util/connector'static async getBalance(address: string): Promise<any> {        let { api } = Connector.getInstance()        const { data: balance } = await api.query.system.account(address)        return balance.free    }

Transactions

import Connector from '@/api/util/connector'let { api } = Connector.getInstance()const transfer = await api.tx[section][method](...params)/*unsub将执行继续的监听。 返回的回调函数能够在出块或确认块后进行监听。*/const unsub = await transfer.signAndSend(     sender,    // account: AddressOrPair,      {},    //options: Partial<SignerOptions>     ()=>{   //statusCb         // after isFinalized         unsub()     })

Transactions with Extension

import Connector from '@/lib/substrate/Api'import {    web3Accounts,    web3Enable,    web3FromAddress} from '@polkadot/extension-dapp'let { api } = Connector.getInstance()const allInjected = await web3Enable('Dipole')const allAccounts = await web3Accounts()// finds an injector for an addressconst sender = allAccounts[0].addressconst injector = await web3FromAddress(sender)api.setSigner(injector.signer)

Transactions with password

if (!sender.isLocked) {    await unSubFoo(payload)} else {    try {         //  unlock account success         sender.decodePkcs8(password)         await unSubFoo(payload)    } catch (err){         //  unlock password failed         console.log(err)    }}

参考

  • polkadot.js
  • vue-polkadot
  • polkadot-js/chromeExtension
  • 区块链(BlockChain)中私钥、公钥和钱包地址三者关系