UNPKG

@gear-js/api

Version:

A JavaScript library that provides functionality to connect GEAR Component APIs.

166 lines (163 loc) 6.13 kB
import { randomAsHex } from '@polkadot/util-crypto'; import { SubmitProgramError, ProgramDoesNotExistError, ProgramHasNoMetahash } from '../errors/program.errors.js'; import '@polkadot/util'; import { generateCodeHash, generateProgramId } from '../utils/generate.js'; import { getIdsFromKeys } from '../utils/prefixes.js'; import { validateValue, validateGasLimit, validateProgramId } from '../utils/validate.js'; import '@polkadot/api'; import { encodePayload } from '../utils/create-payload.js'; import { getExtrinsic } from '../utils/getExtrinsic.js'; import { GearGas } from './Gas.js'; import { GearTransaction } from './Transaction.js'; class GearProgram extends GearTransaction { _api; calculateGas; // public resumeSession: GearResumeSession; constructor(_api) { super(_api); this._api = _api; this.calculateGas = new GearGas(_api); // this.resumeSession = new GearResumeSession(_api); } upload(args, metaOrHexRegistry, typeIndexOrTypeName) { validateValue(args.value, this._api); validateGasLimit(args.gasLimit, this._api); const salt = args.salt || randomAsHex(20); const code = typeof args.code === 'string' ? args.code : this._api.createType('Bytes', Array.from(args.code)); const payload = encodePayload(args.initPayload, metaOrHexRegistry, 'init', typeIndexOrTypeName); const codeId = generateCodeHash(code); const programId = generateProgramId(codeId, salt); try { const txArgs = [code, salt, payload, args.gasLimit, args.value || 0, args.keepAlive]; this.extrinsic = getExtrinsic(this._api, 'gear', 'uploadProgram', txArgs); return { programId, codeId, salt, extrinsic: this.extrinsic }; } catch (error) { console.log(error); throw new SubmitProgramError(); } } create({ codeId, initPayload, value, gasLimit, ...args }, metaOrHexRegistry, typeIndexOrTypeName) { validateValue(value, this._api); validateGasLimit(gasLimit, this._api); const payload = encodePayload(initPayload, metaOrHexRegistry, 'init', typeIndexOrTypeName); const salt = args.salt || randomAsHex(20); const programId = generateProgramId(codeId, salt); try { const txArgs = [codeId, salt, payload, gasLimit, value || 0, args.keepAlive]; this.extrinsic = getExtrinsic(this._api, 'gear', 'createProgram', txArgs); return { programId, salt, extrinsic: this.extrinsic }; } catch (_) { throw new SubmitProgramError(); } } /** * ### Pay program rent * @param programId * @param blockCount * @returns * @example * ```javascript * const tx = await api.program.payRent('0x...', 100_000); * tx.signAndSend(account, (events) => { * events.forEach(({event}) => console.log(event.toHuman())) * }) * ``` */ async payRent(programId, blockCount) { await validateProgramId(programId, this._api); return this._api.tx.gear.payProgramRent(programId, blockCount); } /** * ### Calculate the cost of rent for a certain number of blocks * @param blockCount * @returns u128 number */ calcualtePayRent(blockCount) { return this.costPerBlock.muln(blockCount); } /** * Get ids of all uploaded programs * @returns Array of program ids */ async allUploadedPrograms(count) { const prefix = this._api.query.gearProgram.programStorage.keyPrefix(); const programIds = []; if (count) { const keys = await this._api.rpc.state.getKeysPaged(prefix, count); programIds.push(...getIdsFromKeys(keys, prefix)); } else { count = 1000; const keys = await this._api.rpc.state.getKeysPaged(prefix, count); programIds.push(...getIdsFromKeys(keys, prefix)); let keysLength = keys.length; let lastKey = keys.at(-1); while (keysLength === count) { const keys = await this._api.rpc.state.getKeysPaged(prefix, count, lastKey); programIds.push(...getIdsFromKeys(keys, prefix)); lastKey = keys.at(-1); keysLength = keys.length; } } return programIds; } /** * * @param id A program id * @returns `true` if address belongs to program, and `false` otherwise */ async exists(id) { const program = (await this._api.query.gearProgram.programStorage(id)); return program.isSome; } /** * @deprecated use `api.program.codeId` instead */ async codeHash(id) { return this.codeId(id); } /** * Get code's id of the program uploaded on chain * @param programId * @returns codeId of the program code */ async codeId(id) { const program = await this._api.programStorage.getProgram(id); return program.codeId.toHex(); } /** * ### Get hash of program metadata * @param programId * @param at (optional) block hash * @returns */ async metaHash(programId, at) { try { const metaHash = (await this._api.rpc.gear.readMetahash(programId, at || null)); return metaHash.toHex(); } catch (error) { if (error.code === 8000) { if (error.data.includes('Program not found')) { throw new ProgramDoesNotExistError(programId); } if (error.data.includes('unreachable')) { throw new ProgramHasNoMetahash(programId); } } throw error; } } get costPerBlock() { return this._api.consts.gear.programRentCostPerBlock; } get rentMinimalResumePeriod() { return this._api.consts.gear.programRentMinimalResumePeriod; } get rentFreePeriod() { return this._api.consts.gear.programRentFreePeriod; } } export { GearProgram };