import * as vscode from 'vscode' ; import { Keyring } from '@polkadot/keyring' ; import { KeyringPair$Json } from '@polkadot/keyring/types' ; import { KeypairType } from '@polkadot/util-crypto/types' ; import { ApiPromise , WsProvider } from '@polkadot/api' ; const fs = require ( 'fs' ) ; export type Contracts = { [ index ] : Contract [ ] ; } ; export type Contract = { name : string ; address : string ; abiJson : any ; } ; export class Substrate { private keyring = new Keyring ( { type : 'sr25519' } ) ; private api ? : ApiPromise ; private wsEndpoint ? : string ; getConnection ( ) { return this . api ; } constructor ( private context ) { } async connectTo ( wsEndpoint ) { this . disconnect ( ) ; this . wsEndpoint = wsEndpoint ; const api = new ApiPromise ( { provider : new WsProvider ( wsEndpoint ) } ) ; await api . isReady ; this . api = api ; } async disconnect ( ) { if ( this . api ) { this . api ! . disconnect ( ) ; } this . wsEndpoint = undefined ; this . api = undefined ; } getAccounts ( ) { const accounts = this . context . globalState . get < string > ( 'accounts' ) ; if ( ! accounts ) { return [ ] ; } return JSON . parse ( accounts ) ; } getKeyring ( ) { return this . keyring ; } isAccountExists ( name ) { const result = this . getAccounts ( ) ; const exKey = result . find ( ( val ) => val . meta . name === name ) ; if ( ! exKey ) { return false ; } return true ; } async updateAccounts ( accounts ) { await this . context . globalState . update ( 'accounts' , JSON . stringify ( accounts ) ) ; } async createKeyringPair ( key , name , type ) { const pair = this . keyring . addFromUri ( key , { name } , type ) ; const accounts = this . getAccounts ( ) ; accounts . push ( pair . toJson ( ) ) ; await this . updateAccounts ( accounts ) ; } async createKeyringPairWithPassword ( key , name , type , pass ) { const pair = this . keyring . addFromUri ( key , { name } , type ) ; const json = pair . toJson ( pass ) ; json . meta . whenEdited = Date . now ( ) ; const accounts = this . getAccounts ( ) ; accounts . push ( json ) ; await this . updateAccounts ( accounts ) ; } async removeAccount ( name ) { const accounts = this . getAccounts ( ) ; const index = accounts . findIndex ( ( val ) => val . meta [ 'name' ] === name ) ; accounts . splice ( index , 1 ) ; await this . updateAccounts ( accounts ) ; } async renameAccount ( oldName , newName ) { const accounts = this . getAccounts ( ) ; for ( const account of accounts ) { if ( account . meta [ 'name' ] === oldName ) { account . meta [ 'name' ] = newName ; break ; } } await this . updateAccounts ( accounts ) ; } async importKeyringPair ( path ) { const rawdata = fs . readFileSync ( path ) ; const pair = JSON . parse ( rawdata . toString ( ) ) ; if ( this . isAccountExists ( pair . meta [ 'name' ] as string ) ) { vscode . window . showWarningMessage ( 'Account with same key already exists. Account not added' ) ; return ; } const accounts = this . getAccounts ( ) ; accounts . push ( pair ) ; await this . updateAccounts ( accounts ) ; } getConnectionContracts ( ) { if ( ! this . wsEndpoint ) return [ ] ; const contractCodes = this . getContracts ( ) ; const nodeContractCodes = contractCodes [ this . wsEndpoint ] || [ ] ; return nodeContractCodes ; } getContracts ( ) { const contractsString = this . context . globalState . get < string > ( 'contracts' ) ; if ( ! contractsString ) { return { } ; } return JSON . parse ( contractsString ) ; } async saveContract ( contractName , contractAddress , abiJson ) { const contracts = this . getConnectionContracts ( ) ; const existingContract = contracts . find ( contract => contract . name === contractName || contract . address === contractAddress ) ; if ( existingContract ) { existingContract . name = contractName ; existingContract . address = contractAddress ; existingContract . abiJson = abiJson ; } else { contracts . push ( { name : contractName , address : contractAddress , abiJson : abiJson , } ) ; } await this . updateConnectionContracts ( contracts ) ; } async updateConnectionContracts ( codes ) { const connectedNode = this . wsEndpoint ; if ( ! connectedNode ) { throw Error ( 'Not connected to node' ) ; } const contracts = this . getContracts ( ) ; contracts [ connectedNode ] = codes ; await this . updateContracts ( contracts ) ; } async updateContracts ( codes ) { await this . context . globalState . update ( 'contracts' , JSON . stringify ( codes ) ) ; await vscode . commands . executeCommand ( 'substrate.refreshContracts' ) ; } }