ghost-portal/packages/ui-api/src/Api.tsx
2019-04-02 15:12:58 +02:00

139 lines
3.7 KiB
TypeScript

// Copyright 2017-2019 @polkadot/ui-api authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ProviderInterface } from '@polkadot/rpc-provider/types';
import { QueueTx$ExtrinsicAdd, QueueTx$MessageSetStatus } from '@polkadot/ui-app/Status/types';
import { ApiProps } from './types';
import React from 'react';
import ApiPromise from '@polkadot/api/promise';
import defaults from '@polkadot/rpc-provider/defaults';
import { WsProvider } from '@polkadot/rpc-provider';
import { InputNumber } from '@polkadot/ui-app/InputNumber';
import keyring from '@polkadot/ui-keyring';
import ApiSigner from '@polkadot/ui-signer/ApiSigner';
import { ChainProperties } from '@polkadot/types';
import { formatBalance, isTestChain } from '@polkadot/util';
import ApiContext from './ApiContext';
type Props = {
children: React.ReactNode,
queueExtrinsic: QueueTx$ExtrinsicAdd,
queueSetTxStatus: QueueTx$MessageSetStatus,
url?: string
};
type State = ApiProps & {
chain?: string
};
export default class ApiWrapper extends React.PureComponent<Props, State> {
state: State = {} as State;
constructor (props: Props) {
super(props);
const { queueExtrinsic, queueSetTxStatus, url } = props;
const provider = new WsProvider(url);
const signer = new ApiSigner(queueExtrinsic, queueSetTxStatus);
const setApi = (provider: ProviderInterface): void => {
const api = new ApiPromise({ provider, signer });
this.setState({ api }, () => {
this.subscribeEvents();
});
};
const setApiUrl = (url: string = defaults.WS_URL): void =>
setApi(new WsProvider(url));
this.state = {
isApiConnected: false,
isApiReady: false,
api: new ApiPromise({ provider, signer }),
setApiUrl
} as State;
}
componentDidMount () {
this.subscribeEvents();
}
private subscribeEvents () {
const { api } = this.state;
api.on('connected', () => {
this.setState({ isApiConnected: true });
});
api.on('disconnected', () => {
this.setState({ isApiConnected: false });
});
api.on('ready', async () => {
try {
await this.loadOnReady(api);
} catch (error) {
console.error('Unable to load chain', error);
}
});
}
private async loadOnReady (api: ApiPromise) {
const [properties = new ChainProperties(), value] = await Promise.all([
api.rpc.system.properties() as Promise<ChainProperties | undefined>,
api.rpc.system.chain() as Promise<any>
]);
const section = Object.keys(api.tx)[0];
const method = Object.keys(api.tx[section])[0];
const chain = value
? value.toString()
: null;
const isDevelopment = isTestChain(chain);
console.log('api: found chain', chain, JSON.stringify(properties));
// first setup the UI helpers
formatBalance.setDefaults({
decimals: properties.tokenDecimals,
unit: properties.tokenSymbol
});
InputNumber.setUnit(properties.tokenSymbol);
// finally load the keyring
keyring.loadAll({
addressPrefix: properties.get('networkId'),
isDevelopment,
type: 'ed25519'
});
this.setState({
isApiReady: true,
apiDefaultTx: api.tx[section][method],
chain,
isDevelopment
});
}
render () {
const { api, apiDefaultTx, chain, isApiConnected, isApiReady, isDevelopment, setApiUrl } = this.state;
return (
<ApiContext.Provider
value={{
api,
apiDefaultTx,
isApiConnected,
isApiReady: isApiReady && !!chain,
isDevelopment,
setApiUrl
}}
>
{this.props.children}
</ApiContext.Provider>
);
}
}