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)中私钥、公钥和钱包地址三者关系