Develop WebApps with Vue using Polkadot.js
Element
Generally, the following three elements will appear in an operation on any program
- Sender / receiver: account wallet address
- Channel: websocket long connection
- Message: message can be encrypted
Account
Dependency:
@polkadot/util-crypto
Used to generate random keys@polkadot/keyring
For managing wallet accounts,/testing
You can develop test accounts synchronously@vue-polkadot/vue-settings
Basic information of the synchronization chain node (such as the currency unit to be used in transfer)@vue-polkadot/vue-identicon
Used to display account Avatar@polkadot/util
Some tools, such as data formatting
Install Keyring
// store.ts
import { 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
}
Invoke Keyring in component to generate wallet account
// Account.vue
import { 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()
}
}
}
The create interface is used to create accounts, and the add interface is used to add accounts in local memory.
const json = pair.toJson(password)
this.$keyring.addFromJson(json)
During transaction transfer, the amount data needs additional processing
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
Establish a long websocket connection between the web client and the chain side application to maintain data communication, and then instantiate the polkdot API.
The execution time is usually only once, which occurs after the page is loaded.
- connect with websocket
- make the api global
Code
//Introduce dependency
import { ApiPromise, WsProvider } from '@polkadot/api'
import { EventEmitter } from 'events'
//Define interface type
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
The exception of connection failure cannot be caught and will not be solved temporarily.event
It depends on the success / failure listening that mainly handles connect events. If there are other exception capture mechanisms outside, you can remove them here.@vue-polkadot/vue-api
The plug-in has the same function as this code. The former has some encapsulation for Vue.@vue-polkadot/vue-api
The type parameter is not passed in during instantiation. If a custom type needs to be passed in, it needs to be processed separately.
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 will perform continuous listening. The returned callback function can stop listening after the block is out or confirmed*/
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 address
const sender = allAccounts[0].address
const 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)
}
}
reference resources
- polkadot.js
- vue-polkadot
- polkadot-js/chromeExtension
- The relationship among private key, public key and wallet address in blockchain