modifying b1 lint config to use 4 spaces and semicolons for readability

This commit is contained in:
Cody Douglass
2019-02-12 11:38:07 -05:00
parent f5ca3dd330
commit ed56a35e51
17 changed files with 2412 additions and 2409 deletions
+29 -30
View File
@@ -1,67 +1,66 @@
// copyright defined in eosjs/LICENSE.txt // copyright defined in eosjs/LICENSE.txt
import { Abi, PushTransactionArgs } from './eosjs-rpc-interfaces' import { Abi, PushTransactionArgs } from './eosjs-rpc-interfaces';
/** Arguments to `getRequiredKeys` */ /** Arguments to `getRequiredKeys` */
export interface AuthorityProviderArgs { export interface AuthorityProviderArgs {
/** Transaction that needs to be signed */ /** Transaction that needs to be signed */
transaction: any transaction: any;
/** Public keys associated with the private keys that the `SignatureProvider` holds */ /** Public keys associated with the private keys that the `SignatureProvider` holds */
availableKeys: string[] availableKeys: string[];
} }
/** Get subset of `availableKeys` needed to meet authorities in `transaction` */ /** Get subset of `availableKeys` needed to meet authorities in `transaction` */
export interface AuthorityProvider { export interface AuthorityProvider {
/** Get subset of `availableKeys` needed to meet authorities in `transaction` */ /** Get subset of `availableKeys` needed to meet authorities in `transaction` */
getRequiredKeys: (args: AuthorityProviderArgs) => Promise<string[]> getRequiredKeys: (args: AuthorityProviderArgs) => Promise<string[]>;
} }
/** Retrieves raw ABIs for a specified accountName */ /** Retrieves raw ABIs for a specified accountName */
export interface AbiProvider { export interface AbiProvider {
/** Retrieve the BinaryAbi */ /** Retrieve the BinaryAbi */
getRawAbi: (accountName: string) => Promise<BinaryAbi> getRawAbi: (accountName: string) => Promise<BinaryAbi>;
} }
/** Structure for the raw form of ABIs */ /** Structure for the raw form of ABIs */
export interface BinaryAbi { export interface BinaryAbi {
/** account which has deployed the ABI */
accountName: string;
/** account which has deployed the ABI */ /** abi in binary form */
accountName: string abi: Uint8Array;
/** abi in binary form */
abi: Uint8Array
} }
/** Holds a fetched abi */ /** Holds a fetched abi */
export interface CachedAbi { export interface CachedAbi {
/** abi in binary form */ /** abi in binary form */
rawAbi: Uint8Array rawAbi: Uint8Array;
/** abi in structured form */ /** abi in structured form */
abi: Abi abi: Abi;
} }
/** Arguments to `sign` */ /** Arguments to `sign` */
export interface SignatureProviderArgs { export interface SignatureProviderArgs {
/** Chain transaction is for */ /** Chain transaction is for */
chainId: string chainId: string;
/** Public keys associated with the private keys needed to sign the transaction */ /** Public keys associated with the private keys needed to sign the transaction */
requiredKeys: string[] requiredKeys: string[];
/** Transaction to sign */ /** Transaction to sign */
serializedTransaction: Uint8Array serializedTransaction: Uint8Array;
/** ABIs for all contracts with actions included in `serializedTransaction` */ /** ABIs for all contracts with actions included in `serializedTransaction` */
abis: BinaryAbi[] abis: BinaryAbi[];
} }
/** Signs transactions */ /** Signs transactions */
export interface SignatureProvider { export interface SignatureProvider {
/** Public keys associated with the private keys that the `SignatureProvider` holds */ /** Public keys associated with the private keys that the `SignatureProvider` holds */
getAvailableKeys: () => Promise<string[]> getAvailableKeys: () => Promise<string[]>;
/** Sign a transaction */ /** Sign a transaction */
sign: (args: SignatureProviderArgs) => Promise<PushTransactionArgs> sign: (args: SignatureProviderArgs) => Promise<PushTransactionArgs>;
} }
+177 -177
View File
@@ -3,44 +3,44 @@
*/ */
// copyright defined in eosjs/LICENSE.txt // copyright defined in eosjs/LICENSE.txt
import { AbiProvider, AuthorityProvider, BinaryAbi, CachedAbi, SignatureProvider } from './eosjs-api-interfaces' import { AbiProvider, AuthorityProvider, BinaryAbi, CachedAbi, SignatureProvider } from './eosjs-api-interfaces';
import { JsonRpc } from './eosjs-jsonrpc' import { JsonRpc } from './eosjs-jsonrpc';
import { Abi, GetInfoResult, PushTransactionArgs } from './eosjs-rpc-interfaces' import { Abi, GetInfoResult, PushTransactionArgs } from './eosjs-rpc-interfaces';
import * as ser from './eosjs-serialize' import * as ser from './eosjs-serialize';
const abiAbi = require('../src/abi.abi.json') const abiAbi = require('../src/abi.abi.json');
const transactionAbi = require('../src/transaction.abi.json') const transactionAbi = require('../src/transaction.abi.json');
export class Api { export class Api {
/** Issues RPC calls */ /** Issues RPC calls */
public rpc: JsonRpc public rpc: JsonRpc;
/** Get subset of `availableKeys` needed to meet authorities in a `transaction` */ /** Get subset of `availableKeys` needed to meet authorities in a `transaction` */
public authorityProvider: AuthorityProvider public authorityProvider: AuthorityProvider;
/** Supplies ABIs in raw form (binary) */ /** Supplies ABIs in raw form (binary) */
public abiProvider: AbiProvider public abiProvider: AbiProvider;
/** Signs transactions */ /** Signs transactions */
public signatureProvider: SignatureProvider public signatureProvider: SignatureProvider;
/** Identifies chain */ /** Identifies chain */
public chainId: string public chainId: string;
public textEncoder: TextEncoder public textEncoder: TextEncoder;
public textDecoder: TextDecoder public textDecoder: TextDecoder;
/** Converts abi files between binary and structured form (`abi.abi.json`) */ /** Converts abi files between binary and structured form (`abi.abi.json`) */
public abiTypes: Map<string, ser.Type> public abiTypes: Map<string, ser.Type>;
/** Converts transactions between binary and structured form (`transaction.abi.json`) */ /** Converts transactions between binary and structured form (`transaction.abi.json`) */
public transactionTypes: Map<string, ser.Type> public transactionTypes: Map<string, ser.Type>;
/** Holds information needed to serialize contract actions */ /** Holds information needed to serialize contract actions */
public contracts = new Map<string, ser.Contract>() public contracts = new Map<string, ser.Contract>();
/** Fetched abis */ /** Fetched abis */
public cachedAbis = new Map<string, CachedAbi>() public cachedAbis = new Map<string, CachedAbi>();
/** /**
* @param args * @param args
@@ -52,153 +52,153 @@ export class Api {
* * `textEncoder`: `TextEncoder` instance to use. Pass in `null` if running in a browser * * `textEncoder`: `TextEncoder` instance to use. Pass in `null` if running in a browser
* * `textDecoder`: `TextDecoder` instance to use. Pass in `null` if running in a browser * * `textDecoder`: `TextDecoder` instance to use. Pass in `null` if running in a browser
*/ */
constructor(args: { constructor(args: {
rpc: JsonRpc, rpc: JsonRpc,
authorityProvider?: AuthorityProvider, authorityProvider?: AuthorityProvider,
abiProvider?: AbiProvider, abiProvider?: AbiProvider,
signatureProvider: SignatureProvider, signatureProvider: SignatureProvider,
chainId?: string, chainId?: string,
textEncoder?: TextEncoder, textEncoder?: TextEncoder,
textDecoder?: TextDecoder, textDecoder?: TextDecoder,
}) { }) {
this.rpc = args.rpc this.rpc = args.rpc;
this.authorityProvider = args.authorityProvider || args.rpc this.authorityProvider = args.authorityProvider || args.rpc;
this.abiProvider = args.abiProvider || args.rpc this.abiProvider = args.abiProvider || args.rpc;
this.signatureProvider = args.signatureProvider this.signatureProvider = args.signatureProvider;
this.chainId = args.chainId this.chainId = args.chainId;
this.textEncoder = args.textEncoder this.textEncoder = args.textEncoder;
this.textDecoder = args.textDecoder this.textDecoder = args.textDecoder;
this.abiTypes = ser.getTypesFromAbi(ser.createInitialTypes(), abiAbi) this.abiTypes = ser.getTypesFromAbi(ser.createInitialTypes(), abiAbi);
this.transactionTypes = ser.getTypesFromAbi(ser.createInitialTypes(), transactionAbi) this.transactionTypes = ser.getTypesFromAbi(ser.createInitialTypes(), transactionAbi);
} }
/** Decodes an abi as Uint8Array into json. */ /** Decodes an abi as Uint8Array into json. */
public rawAbiToJson(rawAbi: Uint8Array): Abi { public rawAbiToJson(rawAbi: Uint8Array): Abi {
const buffer = new ser.SerialBuffer({ const buffer = new ser.SerialBuffer({
textEncoder: this.textEncoder, textEncoder: this.textEncoder,
textDecoder: this.textDecoder, textDecoder: this.textDecoder,
array: rawAbi, array: rawAbi,
}) });
if (!ser.supportedAbiVersion(buffer.getString())) { if (!ser.supportedAbiVersion(buffer.getString())) {
throw new Error('Unsupported abi version') throw new Error('Unsupported abi version');
}
buffer.restartRead();
return this.abiTypes.get('abi_def').deserialize(buffer);
} }
buffer.restartRead()
return this.abiTypes.get('abi_def').deserialize(buffer)
}
/** Get abi in both binary and structured forms. Fetch when needed. */ /** Get abi in both binary and structured forms. Fetch when needed. */
public async getCachedAbi(accountName: string, reload = false): Promise<CachedAbi> { public async getCachedAbi(accountName: string, reload = false): Promise<CachedAbi> {
if (!reload && this.cachedAbis.get(accountName)) { if (!reload && this.cachedAbis.get(accountName)) {
return this.cachedAbis.get(accountName) return this.cachedAbis.get(accountName);
}
let cachedAbi: CachedAbi;
try {
const rawAbi = (await this.abiProvider.getRawAbi(accountName)).abi;
const abi = this.rawAbiToJson(rawAbi);
cachedAbi = { rawAbi, abi };
} catch (e) {
e.message = `fetching abi for ${accountName}: ${e.message}`;
throw e;
}
if (!cachedAbi) {
throw new Error(`Missing abi for ${accountName}`);
}
this.cachedAbis.set(accountName, cachedAbi);
return cachedAbi;
} }
let cachedAbi: CachedAbi
try {
const rawAbi = (await this.abiProvider.getRawAbi(accountName)).abi
const abi = this.rawAbiToJson(rawAbi)
cachedAbi = { rawAbi, abi }
} catch (e) {
e.message = `fetching abi for ${accountName}: ${e.message}`
throw e
}
if (!cachedAbi) {
throw new Error(`Missing abi for ${accountName}`)
}
this.cachedAbis.set(accountName, cachedAbi)
return cachedAbi
}
/** Get abi in structured form. Fetch when needed. */ /** Get abi in structured form. Fetch when needed. */
public async getAbi(accountName: string, reload = false): Promise<Abi> { public async getAbi(accountName: string, reload = false): Promise<Abi> {
return (await this.getCachedAbi(accountName, reload)).abi return (await this.getCachedAbi(accountName, reload)).abi;
} }
/** Get abis needed by a transaction */ /** Get abis needed by a transaction */
public async getTransactionAbis(transaction: any, reload = false): Promise<BinaryAbi[]> { public async getTransactionAbis(transaction: any, reload = false): Promise<BinaryAbi[]> {
const accounts: string[] = transaction.actions.map((action: ser.Action): string => action.account) const accounts: string[] = transaction.actions.map((action: ser.Action): string => action.account);
const uniqueAccounts: Set<string> = new Set(accounts) const uniqueAccounts: Set<string> = new Set(accounts);
const actionPromises: Array<Promise<BinaryAbi>> = [...uniqueAccounts].map( const actionPromises: Array<Promise<BinaryAbi>> = [...uniqueAccounts].map(
async (account: string): Promise<BinaryAbi> => ({ async (account: string): Promise<BinaryAbi> => ({
accountName: account, abi: (await this.getCachedAbi(account, reload)).rawAbi, accountName: account, abi: (await this.getCachedAbi(account, reload)).rawAbi,
})) }));
return Promise.all(actionPromises) return Promise.all(actionPromises);
} }
/** Get data needed to serialize actions in a contract */ /** Get data needed to serialize actions in a contract */
public async getContract(accountName: string, reload = false): Promise<ser.Contract> { public async getContract(accountName: string, reload = false): Promise<ser.Contract> {
if (!reload && this.contracts.get(accountName)) { if (!reload && this.contracts.get(accountName)) {
return this.contracts.get(accountName) return this.contracts.get(accountName);
}
const abi = await this.getAbi(accountName, reload);
const types = ser.getTypesFromAbi(ser.createInitialTypes(), abi);
const actions = new Map<string, ser.Type>();
for (const { name, type } of abi.actions) {
actions.set(name, ser.getType(types, type));
}
const result = { types, actions };
this.contracts.set(accountName, result);
return result;
} }
const abi = await this.getAbi(accountName, reload)
const types = ser.getTypesFromAbi(ser.createInitialTypes(), abi)
const actions = new Map<string, ser.Type>()
for (const { name, type } of abi.actions) {
actions.set(name, ser.getType(types, type))
}
const result = { types, actions }
this.contracts.set(accountName, result)
return result
}
/** Convert `value` to binary form. `type` must be a built-in abi type or in `transaction.abi.json`. */ /** Convert `value` to binary form. `type` must be a built-in abi type or in `transaction.abi.json`. */
public serialize(buffer: ser.SerialBuffer, type: string, value: any): void { public serialize(buffer: ser.SerialBuffer, type: string, value: any): void {
this.transactionTypes.get(type).serialize(buffer, value) this.transactionTypes.get(type).serialize(buffer, value);
} }
/** Convert data in `buffer` to structured form. `type` must be a built-in abi type or in `transaction.abi.json`. */ /** Convert data in `buffer` to structured form. `type` must be a built-in abi type or in `transaction.abi.json`. */
public deserialize(buffer: ser.SerialBuffer, type: string): any { public deserialize(buffer: ser.SerialBuffer, type: string): any {
return this.transactionTypes.get(type).deserialize(buffer) return this.transactionTypes.get(type).deserialize(buffer);
} }
/** Convert a transaction to binary */ /** Convert a transaction to binary */
public serializeTransaction(transaction: any): Uint8Array { public serializeTransaction(transaction: any): Uint8Array {
const buffer = new ser.SerialBuffer({ textEncoder: this.textEncoder, textDecoder: this.textDecoder }) const buffer = new ser.SerialBuffer({ textEncoder: this.textEncoder, textDecoder: this.textDecoder });
this.serialize(buffer, 'transaction', { this.serialize(buffer, 'transaction', {
max_net_usage_words: 0, max_net_usage_words: 0,
max_cpu_usage_ms: 0, max_cpu_usage_ms: 0,
delay_sec: 0, delay_sec: 0,
context_free_actions: [], context_free_actions: [],
actions: [], actions: [],
transaction_extensions: [], transaction_extensions: [],
...transaction, ...transaction,
}) });
return buffer.asUint8Array() return buffer.asUint8Array();
} }
/** Convert a transaction from binary. Leaves actions in hex. */ /** Convert a transaction from binary. Leaves actions in hex. */
public deserializeTransaction(transaction: Uint8Array): any { public deserializeTransaction(transaction: Uint8Array): any {
const buffer = new ser.SerialBuffer({ textEncoder: this.textEncoder, textDecoder: this.textDecoder }) const buffer = new ser.SerialBuffer({ textEncoder: this.textEncoder, textDecoder: this.textDecoder });
buffer.pushArray(transaction) buffer.pushArray(transaction);
return this.deserialize(buffer, 'transaction') return this.deserialize(buffer, 'transaction');
} }
/** Convert actions to hex */ /** Convert actions to hex */
public async serializeActions(actions: ser.Action[]): Promise<ser.SerializedAction[]> { public async serializeActions(actions: ser.Action[]): Promise<ser.SerializedAction[]> {
return await Promise.all(actions.map(async ({ account, name, authorization, data }) => { return await Promise.all(actions.map(async ({ account, name, authorization, data }) => {
const contract = await this.getContract(account) const contract = await this.getContract(account);
return ser.serializeAction( return ser.serializeAction(
contract, account, name, authorization, data, this.textEncoder, this.textDecoder) contract, account, name, authorization, data, this.textEncoder, this.textDecoder);
})) }));
} }
/** Convert actions from hex */ /** Convert actions from hex */
public async deserializeActions(actions: ser.Action[]): Promise<ser.Action[]> { public async deserializeActions(actions: ser.Action[]): Promise<ser.Action[]> {
return await Promise.all(actions.map(async ({ account, name, authorization, data }) => { return await Promise.all(actions.map(async ({ account, name, authorization, data }) => {
const contract = await this.getContract(account) const contract = await this.getContract(account);
return ser.deserializeAction( return ser.deserializeAction(
contract, account, name, authorization, data, this.textEncoder, this.textDecoder) contract, account, name, authorization, data, this.textEncoder, this.textDecoder);
})) }));
} }
/** Convert a transaction from binary. Also deserializes actions. */ /** Convert a transaction from binary. Also deserializes actions. */
public async deserializeTransactionWithActions(transaction: Uint8Array | string): Promise<any> { public async deserializeTransactionWithActions(transaction: Uint8Array | string): Promise<any> {
if (typeof transaction === 'string') { if (typeof transaction === 'string') {
transaction = ser.hexToUint8Array(transaction) transaction = ser.hexToUint8Array(transaction);
}
const deserializedTransaction = this.deserializeTransaction(transaction);
const deserializedActions = await this.deserializeActions(deserializedTransaction.actions);
return { ...deserializedTransaction, actions: deserializedActions };
} }
const deserializedTransaction = this.deserializeTransaction(transaction)
const deserializedActions = await this.deserializeActions(deserializedTransaction.actions)
return { ...deserializedTransaction, actions: deserializedActions }
}
/** /**
* Create and optionally broadcast a transaction. * Create and optionally broadcast a transaction.
@@ -211,59 +211,59 @@ export class Api {
* use it as a reference for TAPoS, and expire the transaction `expireSeconds` after that block's time. * use it as a reference for TAPoS, and expire the transaction `expireSeconds` after that block's time.
* @returns node response if `broadcast`, `{signatures, serializedTransaction}` if `!broadcast` * @returns node response if `broadcast`, `{signatures, serializedTransaction}` if `!broadcast`
*/ */
public async transact(transaction: any, { broadcast = true, sign = true, blocksBehind, expireSeconds }: public async transact(transaction: any, { broadcast = true, sign = true, blocksBehind, expireSeconds }:
{ broadcast?: boolean; sign?: boolean; blocksBehind?: number; expireSeconds?: number; } = {}): Promise<any> { { broadcast?: boolean; sign?: boolean; blocksBehind?: number; expireSeconds?: number; } = {}): Promise<any> {
let info: GetInfoResult let info: GetInfoResult;
if (!this.chainId) { if (!this.chainId) {
info = await this.rpc.get_info() info = await this.rpc.get_info();
this.chainId = info.chain_id this.chainId = info.chain_id;
} }
if (typeof blocksBehind === 'number' && expireSeconds) { // use config fields to generate TAPOS if they exist if (typeof blocksBehind === 'number' && expireSeconds) { // use config fields to generate TAPOS if they exist
if (!info) { if (!info) {
info = await this.rpc.get_info() info = await this.rpc.get_info();
} }
const refBlock = await this.rpc.get_block(info.head_block_num - blocksBehind) const refBlock = await this.rpc.get_block(info.head_block_num - blocksBehind);
transaction = { ...ser.transactionHeader(refBlock, expireSeconds), ...transaction } transaction = { ...ser.transactionHeader(refBlock, expireSeconds), ...transaction };
} }
if (!this.hasRequiredTaposFields(transaction)) { if (!this.hasRequiredTaposFields(transaction)) {
throw new Error('Required configuration or TAPOS fields are not present') throw new Error('Required configuration or TAPOS fields are not present');
} }
const abis: BinaryAbi[] = await this.getTransactionAbis(transaction) const abis: BinaryAbi[] = await this.getTransactionAbis(transaction);
transaction = { ...transaction, actions: await this.serializeActions(transaction.actions) } transaction = { ...transaction, actions: await this.serializeActions(transaction.actions) };
const serializedTransaction = this.serializeTransaction(transaction) const serializedTransaction = this.serializeTransaction(transaction);
let pushTransactionArgs: PushTransactionArgs = { serializedTransaction, signatures: [] } let pushTransactionArgs: PushTransactionArgs = { serializedTransaction, signatures: [] };
if (sign) { if (sign) {
const availableKeys = await this.signatureProvider.getAvailableKeys() const availableKeys = await this.signatureProvider.getAvailableKeys();
const requiredKeys = await this.authorityProvider.getRequiredKeys({ transaction, availableKeys }) const requiredKeys = await this.authorityProvider.getRequiredKeys({ transaction, availableKeys });
pushTransactionArgs = await this.signatureProvider.sign({ pushTransactionArgs = await this.signatureProvider.sign({
chainId: this.chainId, chainId: this.chainId,
requiredKeys, requiredKeys,
serializedTransaction, serializedTransaction,
abis, abis,
}) });
}
if (broadcast) {
return this.pushSignedTransaction(pushTransactionArgs);
}
return pushTransactionArgs;
} }
if (broadcast) {
return this.pushSignedTransaction(pushTransactionArgs)
}
return pushTransactionArgs
}
/** Broadcast a signed transaction */ /** Broadcast a signed transaction */
public async pushSignedTransaction({ signatures, serializedTransaction }: PushTransactionArgs): Promise<any> { public async pushSignedTransaction({ signatures, serializedTransaction }: PushTransactionArgs): Promise<any> {
return this.rpc.push_transaction({ return this.rpc.push_transaction({
signatures, signatures,
serializedTransaction, serializedTransaction,
}) });
} }
// eventually break out into TransactionValidator class // eventually break out into TransactionValidator class
private hasRequiredTaposFields({ expiration, ref_block_num, ref_block_prefix, ...transaction }: any): boolean { private hasRequiredTaposFields({ expiration, ref_block_num, ref_block_prefix, ...transaction }: any): boolean {
return !!(expiration && ref_block_num && ref_block_prefix) return !!(expiration && ref_block_num && ref_block_prefix);
} }
} // Api } // Api
+1 -1
View File
@@ -1 +1 @@
declare module "eosjs-ecc" declare module "eosjs-ecc";
+145 -145
View File
@@ -3,130 +3,130 @@
*/ */
// copyright defined in eosjs/LICENSE.txt // copyright defined in eosjs/LICENSE.txt
import { AbiProvider, AuthorityProvider, AuthorityProviderArgs, BinaryAbi } from './eosjs-api-interfaces' import { AbiProvider, AuthorityProvider, AuthorityProviderArgs, BinaryAbi } from './eosjs-api-interfaces';
import { base64ToBinary, convertLegacyPublicKeys } from './eosjs-numeric' import { base64ToBinary, convertLegacyPublicKeys } from './eosjs-numeric';
import { GetAbiResult, GetBlockResult, GetCodeResult, GetInfoResult, GetRawCodeAndAbiResult, PushTransactionArgs } from "./eosjs-rpc-interfaces" // tslint:disable-line import { GetAbiResult, GetBlockResult, GetCodeResult, GetInfoResult, GetRawCodeAndAbiResult, PushTransactionArgs } from "./eosjs-rpc-interfaces" // tslint:disable-line
import { RpcError } from './eosjs-rpcerror' import { RpcError } from './eosjs-rpcerror';
function arrayToHex(data: Uint8Array) { function arrayToHex(data: Uint8Array) {
let result = '' let result = '';
for (const x of data) { for (const x of data) {
result += ('00' + x.toString(16)).slice(-2) result += ('00' + x.toString(16)).slice(-2);
} }
return result return result;
} }
/** Make RPC calls */ /** Make RPC calls */
export class JsonRpc implements AuthorityProvider, AbiProvider { export class JsonRpc implements AuthorityProvider, AbiProvider {
public endpoint: string public endpoint: string;
public fetchBuiltin: (input?: Request | string, init?: RequestInit) => Promise<Response> public fetchBuiltin: (input?: Request | string, init?: RequestInit) => Promise<Response>;
/** /**
* @param args * @param args
* * `fetch`: * * `fetch`:
* * browsers: leave `null` or `undefined` * * browsers: leave `null` or `undefined`
* * node: provide an implementation * * node: provide an implementation
*/ */
constructor(endpoint: string, args: constructor(endpoint: string, args:
{ fetch?: (input?: string | Request, init?: RequestInit) => Promise<Response> } = {}, { fetch?: (input?: string | Request, init?: RequestInit) => Promise<Response> } = {},
) { ) {
this.endpoint = endpoint this.endpoint = endpoint;
if (args.fetch) { if (args.fetch) {
this.fetchBuiltin = args.fetch this.fetchBuiltin = args.fetch;
} else { } else {
this.fetchBuiltin = (global as any).fetch this.fetchBuiltin = (global as any).fetch;
}
} }
}
/** Post `body` to `endpoint + path`. Throws detailed error information in `RpcError` when available. */ /** Post `body` to `endpoint + path`. Throws detailed error information in `RpcError` when available. */
public async fetch(path: string, body: any) { public async fetch(path: string, body: any) {
let response let response;
let json let json;
try { try {
const f = this.fetchBuiltin const f = this.fetchBuiltin;
response = await f(this.endpoint + path, { response = await f(this.endpoint + path, {
body: JSON.stringify(body), body: JSON.stringify(body),
method: 'POST', method: 'POST',
}) });
json = await response.json() json = await response.json();
if (json.processed && json.processed.except) { if (json.processed && json.processed.except) {
throw new RpcError(json) throw new RpcError(json);
} }
} catch (e) { } catch (e) {
e.isFetchError = true e.isFetchError = true;
throw e throw e;
}
if (!response.ok) {
throw new RpcError(json);
}
return json;
} }
if (!response.ok) {
throw new RpcError(json) /** Raw call to `/v1/chain/get_abi` */
public async get_abi(accountName: string): Promise<GetAbiResult> {
return await this.fetch('/v1/chain/get_abi', { account_name: accountName });
} }
return json
}
/** Raw call to `/v1/chain/get_abi` */ /** Raw call to `/v1/chain/get_account` */
public async get_abi(accountName: string): Promise<GetAbiResult> { public async get_account(accountName: string): Promise<any> {
return await this.fetch('/v1/chain/get_abi', { account_name: accountName }) return await this.fetch('/v1/chain/get_account', { account_name: accountName });
} }
/** Raw call to `/v1/chain/get_account` */ /** Raw call to `/v1/chain/get_block_header_state` */
public async get_account(accountName: string): Promise<any> { public async get_block_header_state(blockNumOrId: number | string): Promise<any> {
return await this.fetch('/v1/chain/get_account', { account_name: accountName }) return await this.fetch('/v1/chain/get_block_header_state', { block_num_or_id: blockNumOrId });
} }
/** Raw call to `/v1/chain/get_block_header_state` */ /** Raw call to `/v1/chain/get_block` */
public async get_block_header_state(blockNumOrId: number | string): Promise<any> { public async get_block(blockNumOrId: number | string): Promise<GetBlockResult> {
return await this.fetch('/v1/chain/get_block_header_state', { block_num_or_id: blockNumOrId }) return await this.fetch('/v1/chain/get_block', { block_num_or_id: blockNumOrId });
} }
/** Raw call to `/v1/chain/get_block` */ /** Raw call to `/v1/chain/get_code` */
public async get_block(blockNumOrId: number | string): Promise<GetBlockResult> { public async get_code(accountName: string): Promise<GetCodeResult> {
return await this.fetch('/v1/chain/get_block', { block_num_or_id: blockNumOrId }) return await this.fetch('/v1/chain/get_code', { account_name: accountName });
} }
/** Raw call to `/v1/chain/get_code` */ /** Raw call to `/v1/chain/get_currency_balance` */
public async get_code(accountName: string): Promise<GetCodeResult> { public async get_currency_balance(code: string, account: string, symbol: string = null): Promise<any> {
return await this.fetch('/v1/chain/get_code', { account_name: accountName }) return await this.fetch('/v1/chain/get_currency_balance', { code, account, symbol });
} }
/** Raw call to `/v1/chain/get_currency_balance` */ /** Raw call to `/v1/chain/get_currency_stats` */
public async get_currency_balance(code: string, account: string, symbol: string = null): Promise<any> { public async get_currency_stats(code: string, symbol: string): Promise<any> {
return await this.fetch('/v1/chain/get_currency_balance', { code, account, symbol }) return await this.fetch('/v1/chain/get_currency_stats', { code, symbol });
} }
/** Raw call to `/v1/chain/get_currency_stats` */ /** Raw call to `/v1/chain/get_info` */
public async get_currency_stats(code: string, symbol: string): Promise<any> { public async get_info(): Promise<GetInfoResult> {
return await this.fetch('/v1/chain/get_currency_stats', { code, symbol }) return await this.fetch('/v1/chain/get_info', {});
} }
/** Raw call to `/v1/chain/get_info` */ /** Raw call to `/v1/chain/get_producer_schedule` */
public async get_info(): Promise<GetInfoResult> { public async get_producer_schedule(): Promise<any> {
return await this.fetch('/v1/chain/get_info', {}) return await this.fetch('/v1/chain/get_producer_schedule', {});
} }
/** Raw call to `/v1/chain/get_producer_schedule` */ /** Raw call to `/v1/chain/get_producers` */
public async get_producer_schedule(): Promise<any> { public async get_producers(json = true, lowerBound = '', limit = 50): Promise<any> {
return await this.fetch('/v1/chain/get_producer_schedule', {}) return await this.fetch('/v1/chain/get_producers', { json, lower_bound: lowerBound, limit });
} }
/** Raw call to `/v1/chain/get_producers` */ /** Raw call to `/v1/chain/get_raw_code_and_abi` */
public async get_producers(json = true, lowerBound = '', limit = 50): Promise<any> { public async get_raw_code_and_abi(accountName: string): Promise<GetRawCodeAndAbiResult> {
return await this.fetch('/v1/chain/get_producers', { json, lower_bound: lowerBound, limit }) return await this.fetch('/v1/chain/get_raw_code_and_abi', { account_name: accountName });
} }
/** Raw call to `/v1/chain/get_raw_code_and_abi` */ /** calls `/v1/chain/get_raw_code_and_abi` and pulls out unneeded raw wasm code */
public async get_raw_code_and_abi(accountName: string): Promise<GetRawCodeAndAbiResult> { // TODO: use `/v1/chain/get_raw_abi` directly when it becomes available
return await this.fetch('/v1/chain/get_raw_code_and_abi', { account_name: accountName }) public async getRawAbi(accountName: string): Promise<BinaryAbi> {
} const rawCodeAndAbi = await this.get_raw_code_and_abi(accountName);
const abi = base64ToBinary(rawCodeAndAbi.abi);
return { accountName: rawCodeAndAbi.account_name, abi };
}
/** calls `/v1/chain/get_raw_code_and_abi` and pulls out unneeded raw wasm code */ /** Raw call to `/v1/chain/get_table_rows` */
// TODO: use `/v1/chain/get_raw_abi` directly when it becomes available public async get_table_rows({
public async getRawAbi(accountName: string): Promise<BinaryAbi> {
const rawCodeAndAbi = await this.get_raw_code_and_abi(accountName)
const abi = base64ToBinary(rawCodeAndAbi.abi)
return { accountName: rawCodeAndAbi.account_name, abi }
}
/** Raw call to `/v1/chain/get_table_rows` */
public async get_table_rows({
json = true, json = true,
code, code,
scope, scope,
@@ -138,59 +138,59 @@ export class JsonRpc implements AuthorityProvider, AbiProvider {
key_type = '', key_type = '',
limit = 10, limit = 10,
}: any): Promise<any> { }: any): Promise<any> {
return await this.fetch( return await this.fetch(
'/v1/chain/get_table_rows', { '/v1/chain/get_table_rows', {
json, json,
code, code,
scope, scope,
table, table,
table_key, table_key,
lower_bound, lower_bound,
upper_bound, upper_bound,
index_position, index_position,
key_type, key_type,
limit, limit,
}) });
} }
/** Get subset of `availableKeys` needed to meet authorities in `transaction`. Implements `AuthorityProvider` */ /** Get subset of `availableKeys` needed to meet authorities in `transaction`. Implements `AuthorityProvider` */
public async getRequiredKeys(args: AuthorityProviderArgs): Promise<string[]> { public async getRequiredKeys(args: AuthorityProviderArgs): Promise<string[]> {
return convertLegacyPublicKeys((await this.fetch('/v1/chain/get_required_keys', { return convertLegacyPublicKeys((await this.fetch('/v1/chain/get_required_keys', {
transaction: args.transaction, transaction: args.transaction,
available_keys: args.availableKeys, available_keys: args.availableKeys,
})).required_keys) })).required_keys);
} }
/** Push a serialized transaction */ /** Push a serialized transaction */
public async push_transaction({ signatures, serializedTransaction }: PushTransactionArgs): Promise<any> { public async push_transaction({ signatures, serializedTransaction }: PushTransactionArgs): Promise<any> {
return await this.fetch('/v1/chain/push_transaction', { return await this.fetch('/v1/chain/push_transaction', {
signatures, signatures,
compression: 0, compression: 0,
packed_context_free_data: '', packed_context_free_data: '',
packed_trx: arrayToHex(serializedTransaction), packed_trx: arrayToHex(serializedTransaction),
}) });
} }
/** Raw call to `/v1/db_size/get` */ /** Raw call to `/v1/db_size/get` */
public async db_size_get() { return await this.fetch('/v1/db_size/get', {}) } public async db_size_get() { return await this.fetch('/v1/db_size/get', {}); }
/** Raw call to `/v1/history/get_actions` */ /** Raw call to `/v1/history/get_actions` */
public async history_get_actions(accountName: string, pos: number = null, offset: number = null) { public async history_get_actions(accountName: string, pos: number = null, offset: number = null) {
return await this.fetch('/v1/history/get_actions', { account_name: accountName, pos, offset }) return await this.fetch('/v1/history/get_actions', { account_name: accountName, pos, offset });
} }
/** Raw call to `/v1/history/get_transaction` */ /** Raw call to `/v1/history/get_transaction` */
public async history_get_transaction(id: string, blockNumHint: number = null) { public async history_get_transaction(id: string, blockNumHint: number = null) {
return await this.fetch('/v1/history/get_transaction', { id, block_num_hint: blockNumHint }) return await this.fetch('/v1/history/get_transaction', { id, block_num_hint: blockNumHint });
} }
/** Raw call to `/v1/history/get_key_accounts` */ /** Raw call to `/v1/history/get_key_accounts` */
public async history_get_key_accounts(publicKey: string) { public async history_get_key_accounts(publicKey: string) {
return await this.fetch('/v1/history/get_key_accounts', { public_key: publicKey }) return await this.fetch('/v1/history/get_key_accounts', { public_key: publicKey });
} }
/** Raw call to `/v1/history/get_controlled_accounts` */ /** Raw call to `/v1/history/get_controlled_accounts` */
public async history_get_controlled_accounts(controllingAccount: string) { public async history_get_controlled_accounts(controllingAccount: string) {
return await this.fetch('/v1/history/get_controlled_accounts', { controlling_account: controllingAccount }) return await this.fetch('/v1/history/get_controlled_accounts', { controlling_account: controllingAccount });
} }
} // JsonRpc } // JsonRpc
+22 -22
View File
@@ -3,40 +3,40 @@
*/ */
// copyright defined in eosjs/LICENSE.txt // copyright defined in eosjs/LICENSE.txt
import * as ecc from 'eosjs-ecc' import * as ecc from 'eosjs-ecc';
import { SignatureProvider, SignatureProviderArgs } from './eosjs-api-interfaces' import { SignatureProvider, SignatureProviderArgs } from './eosjs-api-interfaces';
import { convertLegacyPublicKey } from './eosjs-numeric' import { convertLegacyPublicKey } from './eosjs-numeric';
/** Signs transactions using in-process private keys */ /** Signs transactions using in-process private keys */
export class JsSignatureProvider implements SignatureProvider { export class JsSignatureProvider implements SignatureProvider {
/** map public to private keys */ /** map public to private keys */
public keys = new Map<string, string>() public keys = new Map<string, string>();
/** public keys */ /** public keys */
public availableKeys = [] as string[] public availableKeys = [] as string[];
/** @param privateKeys private keys to sign with */ /** @param privateKeys private keys to sign with */
constructor(privateKeys: string[]) { constructor(privateKeys: string[]) {
for (const k of privateKeys) { for (const k of privateKeys) {
const pub = convertLegacyPublicKey(ecc.PrivateKey.fromString(k).toPublic().toString()) const pub = convertLegacyPublicKey(ecc.PrivateKey.fromString(k).toPublic().toString());
this.keys.set(pub, k) this.keys.set(pub, k);
this.availableKeys.push(pub) this.availableKeys.push(pub);
}
} }
}
/** Public keys associated with the private keys that the `SignatureProvider` holds */ /** Public keys associated with the private keys that the `SignatureProvider` holds */
public async getAvailableKeys() { public async getAvailableKeys() {
return this.availableKeys return this.availableKeys;
} }
/** Sign a transaction */ /** Sign a transaction */
public async sign({ chainId, requiredKeys, serializedTransaction }: SignatureProviderArgs) { public async sign({ chainId, requiredKeys, serializedTransaction }: SignatureProviderArgs) {
const signBuf = Buffer.concat([ const signBuf = Buffer.concat([
new Buffer(chainId, 'hex'), new Buffer(serializedTransaction), new Buffer(new Uint8Array(32)), new Buffer(chainId, 'hex'), new Buffer(serializedTransaction), new Buffer(new Uint8Array(32)),
]) ]);
const signatures = requiredKeys.map( const signatures = requiredKeys.map(
(pub) => ecc.Signature.sign(signBuf, this.keys.get(convertLegacyPublicKey(pub))).toString(), (pub) => ecc.Signature.sign(signBuf, this.keys.get(convertLegacyPublicKey(pub))).toString(),
) );
return { signatures, serializedTransaction } return { signatures, serializedTransaction };
} }
} }
+227 -227
View File
@@ -3,45 +3,45 @@
*/ */
// copyright defined in eosjs/LICENSE.txt // copyright defined in eosjs/LICENSE.txt
const ripemd160 = require('./ripemd').RIPEMD160.hash as (a: Uint8Array) => ArrayBuffer const ripemd160 = require('./ripemd').RIPEMD160.hash as (a: Uint8Array) => ArrayBuffer;
const base58Chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' const base58Chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
function create_base58_map() { function create_base58_map() {
const base58M = Array(256).fill(-1) as number[] const base58M = Array(256).fill(-1) as number[];
for (let i = 0; i < base58Chars.length; ++i) { for (let i = 0; i < base58Chars.length; ++i) {
base58M[base58Chars.charCodeAt(i)] = i base58M[base58Chars.charCodeAt(i)] = i;
} }
return base58M return base58M;
} }
const base58Map = create_base58_map() const base58Map = create_base58_map();
function create_base64_map() { function create_base64_map() {
const base64M = Array(256).fill(-1) as number[] const base64M = Array(256).fill(-1) as number[];
for (let i = 0; i < base64Chars.length; ++i) { for (let i = 0; i < base64Chars.length; ++i) {
base64M[base64Chars.charCodeAt(i)] = i base64M[base64Chars.charCodeAt(i)] = i;
} }
base64M['='.charCodeAt(0)] = 0 base64M['='.charCodeAt(0)] = 0;
return base64M return base64M;
} }
const base64Map = create_base64_map() const base64Map = create_base64_map();
/** Is `bignum` a negative number? */ /** Is `bignum` a negative number? */
export function isNegative(bignum: Uint8Array) { export function isNegative(bignum: Uint8Array) {
return (bignum[bignum.length - 1] & 0x80) !== 0 return (bignum[bignum.length - 1] & 0x80) !== 0;
} }
/** Negate `bignum` */ /** Negate `bignum` */
export function negate(bignum: Uint8Array) { export function negate(bignum: Uint8Array) {
let carry = 1 let carry = 1;
for (let i = 0; i < bignum.length; ++i) { for (let i = 0; i < bignum.length; ++i) {
const x = (~bignum[i] & 0xff) + carry const x = (~bignum[i] & 0xff) + carry;
bignum[i] = x bignum[i] = x;
carry = x >> 8 carry = x >> 8;
} }
} }
/** /**
@@ -49,23 +49,23 @@ export function negate(bignum: Uint8Array) {
* @param size bignum size (bytes) * @param size bignum size (bytes)
*/ */
export function decimalToBinary(size: number, s: string) { export function decimalToBinary(size: number, s: string) {
const result = new Uint8Array(size) const result = new Uint8Array(size);
for (let i = 0; i < s.length; ++i) { for (let i = 0; i < s.length; ++i) {
const srcDigit = s.charCodeAt(i) const srcDigit = s.charCodeAt(i);
if (srcDigit < '0'.charCodeAt(0) || srcDigit > '9'.charCodeAt(0)) { if (srcDigit < '0'.charCodeAt(0) || srcDigit > '9'.charCodeAt(0)) {
throw new Error('invalid number') throw new Error('invalid number');
}
let carry = srcDigit - '0'.charCodeAt(0);
for (let j = 0; j < size; ++j) {
const x = result[j] * 10 + carry;
result[j] = x;
carry = x >> 8;
}
if (carry) {
throw new Error('number is out of range');
}
} }
let carry = srcDigit - '0'.charCodeAt(0) return result;
for (let j = 0; j < size; ++j) {
const x = result[j] * 10 + carry
result[j] = x
carry = x >> 8
}
if (carry) {
throw new Error('number is out of range')
}
}
return result
} }
/** /**
@@ -73,20 +73,20 @@ export function decimalToBinary(size: number, s: string) {
* @param size bignum size (bytes) * @param size bignum size (bytes)
*/ */
export function signedDecimalToBinary(size: number, s: string) { export function signedDecimalToBinary(size: number, s: string) {
const negative = s[0] === '-' const negative = s[0] === '-';
if (negative) { if (negative) {
s = s.substr(1) s = s.substr(1);
}
const result = decimalToBinary(size, s)
if (negative) {
negate(result)
if (!isNegative(result)) {
throw new Error('number is out of range')
} }
} else if (isNegative(result)) { const result = decimalToBinary(size, s);
throw new Error('number is out of range') if (negative) {
} negate(result);
return result if (!isNegative(result)) {
throw new Error('number is out of range');
}
} else if (isNegative(result)) {
throw new Error('number is out of range');
}
return result;
} }
/** /**
@@ -94,21 +94,21 @@ export function signedDecimalToBinary(size: number, s: string) {
* @param minDigits 0-pad result to this many digits * @param minDigits 0-pad result to this many digits
*/ */
export function binaryToDecimal(bignum: Uint8Array, minDigits = 1) { export function binaryToDecimal(bignum: Uint8Array, minDigits = 1) {
const result = Array(minDigits).fill('0'.charCodeAt(0)) as number[] const result = Array(minDigits).fill('0'.charCodeAt(0)) as number[];
for (let i = bignum.length - 1; i >= 0; --i) { for (let i = bignum.length - 1; i >= 0; --i) {
let carry = bignum[i] let carry = bignum[i];
for (let j = 0; j < result.length; ++j) { for (let j = 0; j < result.length; ++j) {
const x = ((result[j] - '0'.charCodeAt(0)) << 8) + carry const x = ((result[j] - '0'.charCodeAt(0)) << 8) + carry;
result[j] = '0'.charCodeAt(0) + x % 10 result[j] = '0'.charCodeAt(0) + x % 10;
carry = (x / 10) | 0 carry = (x / 10) | 0;
}
while (carry) {
result.push('0'.charCodeAt(0) + carry % 10);
carry = (carry / 10) | 0;
}
} }
while (carry) { result.reverse();
result.push('0'.charCodeAt(0) + carry % 10) return String.fromCharCode(...result);
carry = (carry / 10) | 0
}
}
result.reverse()
return String.fromCharCode(...result)
} }
/** /**
@@ -116,12 +116,12 @@ export function binaryToDecimal(bignum: Uint8Array, minDigits = 1) {
* @param minDigits 0-pad result to this many digits * @param minDigits 0-pad result to this many digits
*/ */
export function signedBinaryToDecimal(bignum: Uint8Array, minDigits = 1) { export function signedBinaryToDecimal(bignum: Uint8Array, minDigits = 1) {
if (isNegative(bignum)) { if (isNegative(bignum)) {
const x = bignum.slice() const x = bignum.slice();
negate(x) negate(x);
return '-' + binaryToDecimal(x, minDigits) return '-' + binaryToDecimal(x, minDigits);
} }
return binaryToDecimal(bignum, minDigits) return binaryToDecimal(bignum, minDigits);
} }
/** /**
@@ -129,23 +129,23 @@ export function signedBinaryToDecimal(bignum: Uint8Array, minDigits = 1) {
* @param size bignum size (bytes) * @param size bignum size (bytes)
*/ */
export function base58ToBinary(size: number, s: string) { export function base58ToBinary(size: number, s: string) {
const result = new Uint8Array(size) const result = new Uint8Array(size);
for (let i = 0; i < s.length; ++i) { for (let i = 0; i < s.length; ++i) {
let carry = base58Map[s.charCodeAt(i)] let carry = base58Map[s.charCodeAt(i)];
if (carry < 0) { if (carry < 0) {
throw new Error('invalid base-58 value') throw new Error('invalid base-58 value');
}
for (let j = 0; j < size; ++j) {
const x = result[j] * 58 + carry;
result[j] = x;
carry = x >> 8;
}
if (carry) {
throw new Error('base-58 value is out of range');
}
} }
for (let j = 0; j < size; ++j) { result.reverse();
const x = result[j] * 58 + carry return result;
result[j] = x
carry = x >> 8
}
if (carry) {
throw new Error('base-58 value is out of range')
}
}
result.reverse()
return result
} }
/** /**
@@ -153,64 +153,64 @@ export function base58ToBinary(size: number, s: string) {
* @param minDigits 0-pad result to this many digits * @param minDigits 0-pad result to this many digits
*/ */
export function binaryToBase58(bignum: Uint8Array, minDigits = 1) { export function binaryToBase58(bignum: Uint8Array, minDigits = 1) {
const result = [] as number[] const result = [] as number[];
for (const byte of bignum) { for (const byte of bignum) {
let carry = byte let carry = byte;
for (let j = 0; j < result.length; ++j) { for (let j = 0; j < result.length; ++j) {
const x = (base58Map[result[j]] << 8) + carry const x = (base58Map[result[j]] << 8) + carry;
result[j] = base58Chars.charCodeAt(x % 58) result[j] = base58Chars.charCodeAt(x % 58);
carry = (x / 58) | 0 carry = (x / 58) | 0;
}
while (carry) {
result.push(base58Chars.charCodeAt(carry % 58));
carry = (carry / 58) | 0;
}
} }
while (carry) { for (const byte of bignum) {
result.push(base58Chars.charCodeAt(carry % 58)) if (byte) {
carry = (carry / 58) | 0 break;
} else {
result.push('1'.charCodeAt(0));
}
} }
} result.reverse();
for (const byte of bignum) { return String.fromCharCode(...result);
if (byte) {
break
} else {
result.push('1'.charCodeAt(0))
}
}
result.reverse()
return String.fromCharCode(...result)
} }
/** Convert an unsigned base-64 number in `s` to a bignum */ /** Convert an unsigned base-64 number in `s` to a bignum */
export function base64ToBinary(s: string) { export function base64ToBinary(s: string) {
let len = s.length let len = s.length;
if ((len & 3) === 1 && s[len - 1] === '=') { if ((len & 3) === 1 && s[len - 1] === '=') {
len -= 1 len -= 1;
} // fc appends an extra '=' } // fc appends an extra '='
if ((len & 3) !== 0) { if ((len & 3) !== 0) {
throw new Error('base-64 value is not padded correctly') throw new Error('base-64 value is not padded correctly');
}
const groups = len >> 2
let bytes = groups * 3
if (len > 0 && s[len - 1] === '=') {
if (s[len - 2] === '=') {
bytes -= 2
} else {
bytes -= 1
} }
} const groups = len >> 2;
const result = new Uint8Array(bytes) let bytes = groups * 3;
if (len > 0 && s[len - 1] === '=') {
if (s[len - 2] === '=') {
bytes -= 2;
} else {
bytes -= 1;
}
}
const result = new Uint8Array(bytes);
for (let group = 0; group < groups; ++group) { for (let group = 0; group < groups; ++group) {
const digit0 = base64Map[s.charCodeAt(group * 4 + 0)] const digit0 = base64Map[s.charCodeAt(group * 4 + 0)];
const digit1 = base64Map[s.charCodeAt(group * 4 + 1)] const digit1 = base64Map[s.charCodeAt(group * 4 + 1)];
const digit2 = base64Map[s.charCodeAt(group * 4 + 2)] const digit2 = base64Map[s.charCodeAt(group * 4 + 2)];
const digit3 = base64Map[s.charCodeAt(group * 4 + 3)] const digit3 = base64Map[s.charCodeAt(group * 4 + 3)];
result[group * 3 + 0] = (digit0 << 2) | (digit1 >> 4) result[group * 3 + 0] = (digit0 << 2) | (digit1 >> 4);
if (group * 3 + 1 < bytes) { if (group * 3 + 1 < bytes) {
result[group * 3 + 1] = ((digit1 & 15) << 4) | (digit2 >> 2) result[group * 3 + 1] = ((digit1 & 15) << 4) | (digit2 >> 2);
}
if (group * 3 + 2 < bytes) {
result[group * 3 + 2] = ((digit2 & 3) << 6) | digit3;
}
} }
if (group * 3 + 2 < bytes) { return result;
result[group * 3 + 2] = ((digit2 & 3) << 6) | digit3
}
}
return result
} }
/** Key types this library supports */ /** Key types this library supports */
@@ -220,150 +220,150 @@ export const enum KeyType {
} }
/** Public key data size, excluding type field */ /** Public key data size, excluding type field */
export const publicKeyDataSize = 33 export const publicKeyDataSize = 33;
/** Private key data size, excluding type field */ /** Private key data size, excluding type field */
export const privateKeyDataSize = 32 export const privateKeyDataSize = 32;
/** Signature data size, excluding type field */ /** Signature data size, excluding type field */
export const signatureDataSize = 65 export const signatureDataSize = 65;
/** Public key, private key, or signature in binary form */ /** Public key, private key, or signature in binary form */
export interface Key { export interface Key {
type: KeyType type: KeyType;
data: Uint8Array data: Uint8Array;
} }
function digestSuffixRipemd160(data: Uint8Array, suffix: string) { function digestSuffixRipemd160(data: Uint8Array, suffix: string) {
const d = new Uint8Array(data.length + suffix.length) const d = new Uint8Array(data.length + suffix.length);
for (let i = 0; i < data.length; ++i) { for (let i = 0; i < data.length; ++i) {
d[i] = data[i] d[i] = data[i];
} }
for (let i = 0; i < suffix.length; ++i) { for (let i = 0; i < suffix.length; ++i) {
d[data.length + i] = suffix.charCodeAt(i) d[data.length + i] = suffix.charCodeAt(i);
} }
return ripemd160(d) return ripemd160(d);
} }
function stringToKey(s: string, type: KeyType, size: number, suffix: string): Key { function stringToKey(s: string, type: KeyType, size: number, suffix: string): Key {
const whole = base58ToBinary(size + 4, s) const whole = base58ToBinary(size + 4, s);
const result = { type, data: new Uint8Array(whole.buffer, 0, size) } const result = { type, data: new Uint8Array(whole.buffer, 0, size) };
const digest = new Uint8Array(digestSuffixRipemd160(result.data, suffix)) const digest = new Uint8Array(digestSuffixRipemd160(result.data, suffix));
if (digest[0] !== whole[size + 0] || digest[1] !== whole[size + 1] if (digest[0] !== whole[size + 0] || digest[1] !== whole[size + 1]
|| digest[2] !== whole[size + 2] || digest[3] !== whole[size + 3]) { || digest[2] !== whole[size + 2] || digest[3] !== whole[size + 3]) {
throw new Error('checksum doesn\'t match') throw new Error('checksum doesn\'t match');
} }
return result return result;
} }
function keyToString(key: Key, suffix: string, prefix: string) { function keyToString(key: Key, suffix: string, prefix: string) {
const digest = new Uint8Array(digestSuffixRipemd160(key.data, suffix)) const digest = new Uint8Array(digestSuffixRipemd160(key.data, suffix));
const whole = new Uint8Array(key.data.length + 4) const whole = new Uint8Array(key.data.length + 4);
for (let i = 0; i < key.data.length; ++i) { for (let i = 0; i < key.data.length; ++i) {
whole[i] = key.data[i] whole[i] = key.data[i];
} }
for (let i = 0; i < 4; ++i) { for (let i = 0; i < 4; ++i) {
whole[i + key.data.length] = digest[i] whole[i + key.data.length] = digest[i];
} }
return prefix + binaryToBase58(whole) return prefix + binaryToBase58(whole);
} }
/** Convert key in `s` to binary form */ /** Convert key in `s` to binary form */
export function stringToPublicKey(s: string): Key { export function stringToPublicKey(s: string): Key {
if (typeof s !== 'string') { if (typeof s !== 'string') {
throw new Error('expected string containing public key') throw new Error('expected string containing public key');
}
if (s.substr(0, 3) === 'EOS') {
const whole = base58ToBinary(publicKeyDataSize + 4, s.substr(3))
const key = { type: KeyType.k1, data: new Uint8Array(publicKeyDataSize) }
for (let i = 0; i < publicKeyDataSize; ++i) {
key.data[i] = whole[i]
} }
const digest = new Uint8Array(ripemd160(key.data)) if (s.substr(0, 3) === 'EOS') {
if (digest[0] !== whole[publicKeyDataSize] || digest[1] !== whole[34] const whole = base58ToBinary(publicKeyDataSize + 4, s.substr(3));
const key = { type: KeyType.k1, data: new Uint8Array(publicKeyDataSize) };
for (let i = 0; i < publicKeyDataSize; ++i) {
key.data[i] = whole[i];
}
const digest = new Uint8Array(ripemd160(key.data));
if (digest[0] !== whole[publicKeyDataSize] || digest[1] !== whole[34]
|| digest[2] !== whole[35] || digest[3] !== whole[36]) { || digest[2] !== whole[35] || digest[3] !== whole[36]) {
throw new Error('checksum doesn\'t match') throw new Error('checksum doesn\'t match');
}
return key;
} else if (s.substr(0, 7) === 'PUB_K1_') {
return stringToKey(s.substr(7), KeyType.k1, publicKeyDataSize, 'K1');
} else if (s.substr(0, 7) === 'PUB_R1_') {
return stringToKey(s.substr(7), KeyType.r1, publicKeyDataSize, 'R1');
} else {
throw new Error('unrecognized public key format');
} }
return key
} else if (s.substr(0, 7) === 'PUB_K1_') {
return stringToKey(s.substr(7), KeyType.k1, publicKeyDataSize, 'K1')
} else if (s.substr(0, 7) === 'PUB_R1_') {
return stringToKey(s.substr(7), KeyType.r1, publicKeyDataSize, 'R1')
} else {
throw new Error('unrecognized public key format')
}
} }
/** Convert `key` to string (base-58) form */ /** Convert `key` to string (base-58) form */
export function publicKeyToString(key: Key) { export function publicKeyToString(key: Key) {
if (key.type === KeyType.k1 && key.data.length === publicKeyDataSize) { if (key.type === KeyType.k1 && key.data.length === publicKeyDataSize) {
return keyToString(key, 'K1', 'PUB_K1_') return keyToString(key, 'K1', 'PUB_K1_');
} else if (key.type === KeyType.r1 && key.data.length === publicKeyDataSize) { } else if (key.type === KeyType.r1 && key.data.length === publicKeyDataSize) {
return keyToString(key, 'R1', 'PUB_R1_') return keyToString(key, 'R1', 'PUB_R1_');
} else { } else {
throw new Error('unrecognized public key format') throw new Error('unrecognized public key format');
} }
} }
/** If a key is in the legacy format (`EOS` prefix), then convert it to the new format (`PUB_K1_`). /** If a key is in the legacy format (`EOS` prefix), then convert it to the new format (`PUB_K1_`).
* Leaves other formats untouched * Leaves other formats untouched
*/ */
export function convertLegacyPublicKey(s: string) { export function convertLegacyPublicKey(s: string) {
if (s.substr(0, 3) === 'EOS') { if (s.substr(0, 3) === 'EOS') {
return publicKeyToString(stringToPublicKey(s)) return publicKeyToString(stringToPublicKey(s));
} }
return s return s;
} }
/** If a key is in the legacy format (`EOS` prefix), then convert it to the new format (`PUB_K1_`). /** If a key is in the legacy format (`EOS` prefix), then convert it to the new format (`PUB_K1_`).
* Leaves other formats untouched * Leaves other formats untouched
*/ */
export function convertLegacyPublicKeys(keys: string[]) { export function convertLegacyPublicKeys(keys: string[]) {
return keys.map(convertLegacyPublicKey) return keys.map(convertLegacyPublicKey);
} }
/** Convert key in `s` to binary form */ /** Convert key in `s` to binary form */
export function stringToPrivateKey(s: string): Key { export function stringToPrivateKey(s: string): Key {
if (typeof s !== 'string') { if (typeof s !== 'string') {
throw new Error('expected string containing private key') throw new Error('expected string containing private key');
} }
if (s.substr(0, 7) === 'PVT_R1_') { if (s.substr(0, 7) === 'PVT_R1_') {
return stringToKey(s.substr(7), KeyType.r1, privateKeyDataSize, 'R1') return stringToKey(s.substr(7), KeyType.r1, privateKeyDataSize, 'R1');
} else { } else {
throw new Error('unrecognized private key format') throw new Error('unrecognized private key format');
} }
} }
/** Convert `key` to string (base-58) form */ /** Convert `key` to string (base-58) form */
export function privateKeyToString(key: Key) { export function privateKeyToString(key: Key) {
if (key.type === KeyType.r1) { if (key.type === KeyType.r1) {
return keyToString(key, 'R1', 'PVT_R1_') return keyToString(key, 'R1', 'PVT_R1_');
} else { } else {
throw new Error('unrecognized private key format') throw new Error('unrecognized private key format');
} }
} }
/** Convert key in `s` to binary form */ /** Convert key in `s` to binary form */
export function stringToSignature(s: string): Key { export function stringToSignature(s: string): Key {
if (typeof s !== 'string') { if (typeof s !== 'string') {
throw new Error('expected string containing signature') throw new Error('expected string containing signature');
} }
if (s.substr(0, 7) === 'SIG_K1_') { if (s.substr(0, 7) === 'SIG_K1_') {
return stringToKey(s.substr(7), KeyType.k1, signatureDataSize, 'K1') return stringToKey(s.substr(7), KeyType.k1, signatureDataSize, 'K1');
} else if (s.substr(0, 7) === 'SIG_R1_') { } else if (s.substr(0, 7) === 'SIG_R1_') {
return stringToKey(s.substr(7), KeyType.r1, signatureDataSize, 'R1') return stringToKey(s.substr(7), KeyType.r1, signatureDataSize, 'R1');
} else { } else {
throw new Error('unrecognized signature format') throw new Error('unrecognized signature format');
} }
} }
/** Convert `signature` to string (base-58) form */ /** Convert `signature` to string (base-58) form */
export function signatureToString(signature: Key) { export function signatureToString(signature: Key) {
if (signature.type === KeyType.k1) { if (signature.type === KeyType.k1) {
return keyToString(signature, 'K1', 'SIG_K1_') return keyToString(signature, 'K1', 'SIG_K1_');
} else if (signature.type === KeyType.r1) { } else if (signature.type === KeyType.r1) {
return keyToString(signature, 'R1', 'SIG_R1_') return keyToString(signature, 'R1', 'SIG_R1_');
} else { } else {
throw new Error('unrecognized signature format') throw new Error('unrecognized signature format');
} }
} }
+47 -47
View File
@@ -2,79 +2,79 @@
/** Structured format for abis */ /** Structured format for abis */
export interface Abi { export interface Abi {
version: string version: string;
types: Array<{ new_type_name: string, type: string }> types: Array<{ new_type_name: string, type: string }>;
structs: Array<{ name: string, base: string, fields: Array<{ name: string, type: string }> }> structs: Array<{ name: string, base: string, fields: Array<{ name: string, type: string }> }>;
actions: Array<{ name: string, type: string, ricardian_contract: string }> actions: Array<{ name: string, type: string, ricardian_contract: string }>;
tables: Array<{ name: string, type: string, index_type: string, key_names: string[], key_types: string[] }> tables: Array<{ name: string, type: string, index_type: string, key_names: string[], key_types: string[] }>;
ricardian_clauses: Array<{ id: string, body: string }> ricardian_clauses: Array<{ id: string, body: string }>;
error_messages: Array<{ error_code: string, error_msg: string }> error_messages: Array<{ error_code: string, error_msg: string }>;
abi_extensions: Array<{ tag: number, value: string }> abi_extensions: Array<{ tag: number, value: string }>;
variants?: Array<{ name: string, types: string[] }> variants?: Array<{ name: string, types: string[] }>;
} }
/** Return value of `/v1/chain/get_abi` */ /** Return value of `/v1/chain/get_abi` */
export interface GetAbiResult { export interface GetAbiResult {
account_name: string account_name: string;
abi: Abi abi: Abi;
} }
/** Subset of `GetBlockResult` needed to calculate TAPoS fields in transactions */ /** Subset of `GetBlockResult` needed to calculate TAPoS fields in transactions */
export interface BlockTaposInfo { export interface BlockTaposInfo {
timestamp: string timestamp: string;
block_num: number block_num: number;
ref_block_prefix: number ref_block_prefix: number;
} }
/** Return value of `/v1/chain/get_block` */ /** Return value of `/v1/chain/get_block` */
export interface GetBlockResult { export interface GetBlockResult {
timestamp: string timestamp: string;
producer: string producer: string;
confirmed: number confirmed: number;
previous: string previous: string;
transaction_mroot: string transaction_mroot: string;
action_mroot: string action_mroot: string;
schedule_version: number schedule_version: number;
producer_signature: string producer_signature: string;
id: string id: string;
block_num: number block_num: number;
ref_block_prefix: number ref_block_prefix: number;
} }
/** Return value of `/v1/chain/get_code` */ /** Return value of `/v1/chain/get_code` */
export interface GetCodeResult { export interface GetCodeResult {
account_name: string account_name: string;
code_hash: string code_hash: string;
wast: string wast: string;
wasm: string wasm: string;
abi: Abi abi: Abi;
} }
/** Return value of `/v1/chain/get_info` */ /** Return value of `/v1/chain/get_info` */
export interface GetInfoResult { export interface GetInfoResult {
server_version: string server_version: string;
chain_id: string chain_id: string;
head_block_num: number head_block_num: number;
last_irreversible_block_num: number last_irreversible_block_num: number;
last_irreversible_block_id: string last_irreversible_block_id: string;
head_block_id: string head_block_id: string;
head_block_time: string head_block_time: string;
head_block_producer: string head_block_producer: string;
virtual_block_cpu_limit: number virtual_block_cpu_limit: number;
virtual_block_net_limit: number virtual_block_net_limit: number;
block_cpu_limit: number block_cpu_limit: number;
block_net_limit: number block_net_limit: number;
} }
/** Return value of `/v1/chain/get_raw_code_and_abi` */ /** Return value of `/v1/chain/get_raw_code_and_abi` */
export interface GetRawCodeAndAbiResult { export interface GetRawCodeAndAbiResult {
account_name: string account_name: string;
wasm: string wasm: string;
abi: string abi: string;
} }
/** Arguments for `push_transaction` */ /** Arguments for `push_transaction` */
export interface PushTransactionArgs { export interface PushTransactionArgs {
signatures: string[] signatures: string[];
serializedTransaction: Uint8Array serializedTransaction: Uint8Array;
} }
+11 -11
View File
@@ -6,17 +6,17 @@
/** Holds detailed error information */ /** Holds detailed error information */
export class RpcError extends Error { export class RpcError extends Error {
/** Detailed error information */ /** Detailed error information */
public json: any public json: any;
constructor(json: any) { constructor(json: any) {
if (json.error && json.error.details && json.error.details.length && json.error.details[0].message) { if (json.error && json.error.details && json.error.details.length && json.error.details[0].message) {
super(json.error.details[0].message) super(json.error.details[0].message);
} else if (json.processed && json.processed.except && json.processed.except.message) { } else if (json.processed && json.processed.except && json.processed.except.message) {
super(json.processed.except.message) super(json.processed.except.message);
} else { } else {
super(json.message) super(json.message);
}
Object.setPrototypeOf(this, RpcError.prototype);
this.json = json;
} }
Object.setPrototypeOf(this, RpcError.prototype)
this.json = json
}
} }
+768 -768
View File
File diff suppressed because it is too large Load Diff
+7 -7
View File
@@ -1,8 +1,8 @@
import { Api } from './eosjs-api' import { Api } from './eosjs-api';
import * as ApiInterfaces from './eosjs-api-interfaces' import * as ApiInterfaces from './eosjs-api-interfaces';
import { JsonRpc } from './eosjs-jsonrpc' import { JsonRpc } from './eosjs-jsonrpc';
import * as RpcInterfaces from './eosjs-rpc-interfaces' import * as RpcInterfaces from './eosjs-rpc-interfaces';
import { RpcError } from './eosjs-rpcerror' import { RpcError } from './eosjs-rpcerror';
import * as Serialize from './eosjs-serialize' import * as Serialize from './eosjs-serialize';
export { Api, ApiInterfaces, JsonRpc, RpcInterfaces, RpcError, Serialize } export { Api, ApiInterfaces, JsonRpc, RpcInterfaces, RpcError, Serialize };
+3 -3
View File
@@ -1,4 +1,4 @@
import { JsonRpc } from './eosjs-jsonrpc' import { JsonRpc } from './eosjs-jsonrpc';
import { RpcError } from './eosjs-rpcerror' import { RpcError } from './eosjs-rpcerror';
export { JsonRpc, RpcError } export { JsonRpc, RpcError };
+160 -160
View File
@@ -1,194 +1,194 @@
import { TextDecoder, TextEncoder } from 'text-encoding' import { TextDecoder, TextEncoder } from 'text-encoding';
import { Api } from '../eosjs-api' import { Api } from '../eosjs-api';
import { JsonRpc } from '../eosjs-jsonrpc' import { JsonRpc } from '../eosjs-jsonrpc';
import { JsSignatureProvider } from '../eosjs-jssig' import { JsSignatureProvider } from '../eosjs-jssig';
const transaction = { const transaction = {
expiration: '2018-09-04T18:42:49', expiration: '2018-09-04T18:42:49',
ref_block_num: 38096, ref_block_num: 38096,
ref_block_prefix: 505360011, ref_block_prefix: 505360011,
max_net_usage_words: 0, max_net_usage_words: 0,
max_cpu_usage_ms: 0, max_cpu_usage_ms: 0,
delay_sec: 0, delay_sec: 0,
context_free_actions: [] as any, context_free_actions: [] as any,
actions: [ actions: [
{
account: 'testeostoken',
name: 'transfer',
authorization: [
{ {
actor: 'thegazelle', account: 'testeostoken',
permission: 'active', name: 'transfer',
}, authorization: [
], {
data: { actor: 'thegazelle',
from: 'thegazelle', permission: 'active',
to: 'remasteryoda', },
quantity: '1.0000 EOS', ],
memo: 'For a secure future.', data: {
}, from: 'thegazelle',
hex_data: `00808a517dc354cb6012f557656ca4ba102700000000000004454f530000000014466f722 to: 'remasteryoda',
quantity: '1.0000 EOS',
memo: 'For a secure future.',
},
hex_data: `00808a517dc354cb6012f557656ca4ba102700000000000004454f530000000014466f722
06120736563757265206675747572652e`, 06120736563757265206675747572652e`,
},
{
account: 'testeostoken',
name: 'transfer',
authorization: [
{
actor: 'thegazelle',
permission: 'active',
}, },
], {
data: { account: 'testeostoken',
from: 'thegazelle', name: 'transfer',
to: 'remasteryoda', authorization: [
quantity: '2.0000 EOS', {
memo: 'For a second secure future (multiverse?)', actor: 'thegazelle',
}, permission: 'active',
hex_data: `00808a517dc354cb6012f557656ca4ba204e00000000000004454f530000000028466f722061207365636f6e642073656 },
],
data: {
from: 'thegazelle',
to: 'remasteryoda',
quantity: '2.0000 EOS',
memo: 'For a second secure future (multiverse?)',
},
hex_data: `00808a517dc354cb6012f557656ca4ba204e00000000000004454f530000000028466f722061207365636f6e642073656
37572652066757475726520286d756c746976657273653f29`, 37572652066757475726520286d756c746976657273653f29`,
}, },
], ],
transaction_extensions: [] as any, transaction_extensions: [] as any,
} };
const serializedTx = [ const serializedTx = [
41, 210, 142, 91, 208, 148, 139, 46, 31, 30, 0, 0, 0, 0, 2, 48, 21, 164, 41, 210, 142, 91, 208, 148, 139, 46, 31, 30, 0, 0, 0, 0, 2, 48, 21, 164,
25, 83, 149, 177, 202, 0, 0, 0, 87, 45, 60, 205, 205, 1, 0, 128, 138, 81, 25, 83, 149, 177, 202, 0, 0, 0, 87, 45, 60, 205, 205, 1, 0, 128, 138, 81,
125, 195, 84, 203, 0, 0, 0, 0, 168, 237, 50, 50, 0, 48, 21, 164, 25, 83, 125, 195, 84, 203, 0, 0, 0, 0, 168, 237, 50, 50, 0, 48, 21, 164, 25, 83,
149, 177, 202, 0, 0, 0, 87, 45, 60, 205, 205, 1, 0, 128, 138, 81, 125, 149, 177, 202, 0, 0, 0, 87, 45, 60, 205, 205, 1, 0, 128, 138, 81, 125,
195, 84, 203, 0, 0, 0, 0, 168, 237, 50, 50, 0, 0, 195, 84, 203, 0, 0, 0, 0, 168, 237, 50, 50, 0, 0,
] ];
const deserializedTx = { const deserializedTx = {
actions: [ actions: [
{ {
account: 'testeostoken', account: 'testeostoken',
authorization: [{ actor: 'thegazelle', permission: 'active' }], authorization: [{ actor: 'thegazelle', permission: 'active' }],
data: '', data: '',
name: 'transfer', name: 'transfer',
}, },
{ {
account: 'testeostoken', account: 'testeostoken',
authorization: [{ actor: 'thegazelle', permission: 'active' }], authorization: [{ actor: 'thegazelle', permission: 'active' }],
data: '', data: '',
name: 'transfer', name: 'transfer',
}, },
], ],
context_free_actions: [] as any, context_free_actions: [] as any,
delay_sec: 0, delay_sec: 0,
expiration: '2018-09-04T18:42:49.000', expiration: '2018-09-04T18:42:49.000',
max_cpu_usage_ms: 0, max_cpu_usage_ms: 0,
max_net_usage_words: 0, max_net_usage_words: 0,
ref_block_num: 38096, ref_block_num: 38096,
ref_block_prefix: 505360011, ref_block_prefix: 505360011,
transaction_extensions: [] as any, transaction_extensions: [] as any,
} };
const serializedActions = [ const serializedActions = [
{ {
account: 'testeostoken', account: 'testeostoken',
authorization: [{ actor: 'thegazelle', permission: 'active' }], authorization: [{ actor: 'thegazelle', permission: 'active' }],
data: "00808A517DC354CB6012F557656CA4BA102700000000000004454F530000000014466F72206120736563757265206675747572652E", // tslint:disable-line data: "00808A517DC354CB6012F557656CA4BA102700000000000004454F530000000014466F72206120736563757265206675747572652E", // tslint:disable-line
name: 'transfer', name: 'transfer',
}, },
{ {
account: 'testeostoken', account: 'testeostoken',
authorization: [{ actor: 'thegazelle', permission: 'active' }], authorization: [{ actor: 'thegazelle', permission: 'active' }],
data: "00808A517DC354CB6012F557656CA4BA204E00000000000004454F530000000028466F722061207365636F6E64207365637572652066757475726520286D756C746976657273653F29", // tslint:disable-line data: "00808A517DC354CB6012F557656CA4BA204E00000000000004454F530000000028466F722061207365636F6E64207365637572652066757475726520286D756C746976657273653F29", // tslint:disable-line
name: 'transfer', name: 'transfer',
}, },
] ];
const deserializedActions = [ const deserializedActions = [
{ {
account: 'testeostoken', account: 'testeostoken',
authorization: [{ actor: 'thegazelle', permission: 'active' }], authorization: [{ actor: 'thegazelle', permission: 'active' }],
data: { data: {
from: 'thegazelle', from: 'thegazelle',
memo: 'For a secure future.', memo: 'For a secure future.',
quantity: '1.0000 EOS', quantity: '1.0000 EOS',
to: 'remasteryoda', to: 'remasteryoda',
},
name: 'transfer',
}, },
name: 'transfer', {
}, account: 'testeostoken',
{ authorization: [{ actor: 'thegazelle', permission: 'active' }],
account: 'testeostoken', data: {
authorization: [{ actor: 'thegazelle', permission: 'active' }], from: 'thegazelle',
data: { memo: 'For a second secure future (multiverse?)',
from: 'thegazelle', quantity: '2.0000 EOS',
memo: 'For a second secure future (multiverse?)', to: 'remasteryoda',
quantity: '2.0000 EOS', },
to: 'remasteryoda', name: 'transfer',
}, },
name: 'transfer', ];
},
]
describe('eosjs-api', () => { describe('eosjs-api', () => {
let api: any let api: any;
const fetch = async (input: any, init: any): Promise<any> => ({ const fetch = async (input: any, init: any): Promise<any> => ({
ok: true, ok: true,
json: async () => { json: async () => {
if (input === '/v1/chain/get_raw_code_and_abi') { if (input === '/v1/chain/get_raw_code_and_abi') {
return { return {
account_name: 'testeostoken', account_name: 'testeostoken',
abi: "DmVvc2lvOjphYmkvMS4wAQxhY2NvdW50X25hbWUEbmFtZQUIdHJhbnNmZXIABARmcm9tDGFjY291bnRfbmFtZQJ0bwxhY2NvdW50X25hbWUIcXVhbnRpdHkFYXNzZXQEbWVtbwZzdHJpbmcGY3JlYXRlAAIGaXNzdWVyDGFjY291bnRfbmFtZQ5tYXhpbXVtX3N1cHBseQVhc3NldAVpc3N1ZQADAnRvDGFjY291bnRfbmFtZQhxdWFudGl0eQVhc3NldARtZW1vBnN0cmluZwdhY2NvdW50AAEHYmFsYW5jZQVhc3NldA5jdXJyZW5jeV9zdGF0cwADBnN1cHBseQVhc3NldAptYXhfc3VwcGx5BWFzc2V0Bmlzc3VlcgxhY2NvdW50X25hbWUDAAAAVy08zc0IdHJhbnNmZXLnBSMjIFRyYW5zZmVyIFRlcm1zICYgQ29uZGl0aW9ucwoKSSwge3tmcm9tfX0sIGNlcnRpZnkgdGhlIGZvbGxvd2luZyB0byBiZSB0cnVlIHRvIHRoZSBiZXN0IG9mIG15IGtub3dsZWRnZToKCjEuIEkgY2VydGlmeSB0aGF0IHt7cXVhbnRpdHl9fSBpcyBub3QgdGhlIHByb2NlZWRzIG9mIGZyYXVkdWxlbnQgb3IgdmlvbGVudCBhY3Rpdml0aWVzLgoyLiBJIGNlcnRpZnkgdGhhdCwgdG8gdGhlIGJlc3Qgb2YgbXkga25vd2xlZGdlLCB7e3RvfX0gaXMgbm90IHN1cHBvcnRpbmcgaW5pdGlhdGlvbiBvZiB2aW9sZW5jZSBhZ2FpbnN0IG90aGVycy4KMy4gSSBoYXZlIGRpc2Nsb3NlZCBhbnkgY29udHJhY3R1YWwgdGVybXMgJiBjb25kaXRpb25zIHdpdGggcmVzcGVjdCB0byB7e3F1YW50aXR5fX0gdG8ge3t0b319LgoKSSB1bmRlcnN0YW5kIHRoYXQgZnVuZHMgdHJhbnNmZXJzIGFyZSBub3QgcmV2ZXJzaWJsZSBhZnRlciB0aGUge3t0cmFuc2FjdGlvbi5kZWxheX19IHNlY29uZHMgb3Igb3RoZXIgZGVsYXkgYXMgY29uZmlndXJlZCBieSB7e2Zyb219fSdzIHBlcm1pc3Npb25zLgoKSWYgdGhpcyBhY3Rpb24gZmFpbHMgdG8gYmUgaXJyZXZlcnNpYmx5IGNvbmZpcm1lZCBhZnRlciByZWNlaXZpbmcgZ29vZHMgb3Igc2VydmljZXMgZnJvbSAne3t0b319JywgSSBhZ3JlZSB0byBlaXRoZXIgcmV0dXJuIHRoZSBnb29kcyBvciBzZXJ2aWNlcyBvciByZXNlbmQge3txdWFudGl0eX19IGluIGEgdGltZWx5IG1hbm5lci4KAAAAAAClMXYFaXNzdWUAAAAAAKhs1EUGY3JlYXRlAAIAAAA4T00RMgNpNjQBCGN1cnJlbmN5AQZ1aW50NjQHYWNjb3VudAAAAAAAkE3GA2k2NAEIY3VycmVuY3kBBnVpbnQ2NA5jdXJyZW5jeV9zdGF0cwAAAA===", // tslint:disable-line abi: "DmVvc2lvOjphYmkvMS4wAQxhY2NvdW50X25hbWUEbmFtZQUIdHJhbnNmZXIABARmcm9tDGFjY291bnRfbmFtZQJ0bwxhY2NvdW50X25hbWUIcXVhbnRpdHkFYXNzZXQEbWVtbwZzdHJpbmcGY3JlYXRlAAIGaXNzdWVyDGFjY291bnRfbmFtZQ5tYXhpbXVtX3N1cHBseQVhc3NldAVpc3N1ZQADAnRvDGFjY291bnRfbmFtZQhxdWFudGl0eQVhc3NldARtZW1vBnN0cmluZwdhY2NvdW50AAEHYmFsYW5jZQVhc3NldA5jdXJyZW5jeV9zdGF0cwADBnN1cHBseQVhc3NldAptYXhfc3VwcGx5BWFzc2V0Bmlzc3VlcgxhY2NvdW50X25hbWUDAAAAVy08zc0IdHJhbnNmZXLnBSMjIFRyYW5zZmVyIFRlcm1zICYgQ29uZGl0aW9ucwoKSSwge3tmcm9tfX0sIGNlcnRpZnkgdGhlIGZvbGxvd2luZyB0byBiZSB0cnVlIHRvIHRoZSBiZXN0IG9mIG15IGtub3dsZWRnZToKCjEuIEkgY2VydGlmeSB0aGF0IHt7cXVhbnRpdHl9fSBpcyBub3QgdGhlIHByb2NlZWRzIG9mIGZyYXVkdWxlbnQgb3IgdmlvbGVudCBhY3Rpdml0aWVzLgoyLiBJIGNlcnRpZnkgdGhhdCwgdG8gdGhlIGJlc3Qgb2YgbXkga25vd2xlZGdlLCB7e3RvfX0gaXMgbm90IHN1cHBvcnRpbmcgaW5pdGlhdGlvbiBvZiB2aW9sZW5jZSBhZ2FpbnN0IG90aGVycy4KMy4gSSBoYXZlIGRpc2Nsb3NlZCBhbnkgY29udHJhY3R1YWwgdGVybXMgJiBjb25kaXRpb25zIHdpdGggcmVzcGVjdCB0byB7e3F1YW50aXR5fX0gdG8ge3t0b319LgoKSSB1bmRlcnN0YW5kIHRoYXQgZnVuZHMgdHJhbnNmZXJzIGFyZSBub3QgcmV2ZXJzaWJsZSBhZnRlciB0aGUge3t0cmFuc2FjdGlvbi5kZWxheX19IHNlY29uZHMgb3Igb3RoZXIgZGVsYXkgYXMgY29uZmlndXJlZCBieSB7e2Zyb219fSdzIHBlcm1pc3Npb25zLgoKSWYgdGhpcyBhY3Rpb24gZmFpbHMgdG8gYmUgaXJyZXZlcnNpYmx5IGNvbmZpcm1lZCBhZnRlciByZWNlaXZpbmcgZ29vZHMgb3Igc2VydmljZXMgZnJvbSAne3t0b319JywgSSBhZ3JlZSB0byBlaXRoZXIgcmV0dXJuIHRoZSBnb29kcyBvciBzZXJ2aWNlcyBvciByZXNlbmQge3txdWFudGl0eX19IGluIGEgdGltZWx5IG1hbm5lci4KAAAAAAClMXYFaXNzdWUAAAAAAKhs1EUGY3JlYXRlAAIAAAA4T00RMgNpNjQBCGN1cnJlbmN5AQZ1aW50NjQHYWNjb3VudAAAAAAAkE3GA2k2NAEIY3VycmVuY3kBBnVpbnQ2NA5jdXJyZW5jeV9zdGF0cwAAAA===", // tslint:disable-line
} };
} }
return transaction return transaction;
}, },
}) });
beforeEach(() => { beforeEach(() => {
const rpc = new JsonRpc('', { fetch }) const rpc = new JsonRpc('', { fetch });
const signatureProvider = new JsSignatureProvider(['5JtUScZK2XEp3g9gh7F8bwtPTRAkASmNrrftmx4AxDKD5K4zDnr']) const signatureProvider = new JsSignatureProvider(['5JtUScZK2XEp3g9gh7F8bwtPTRAkASmNrrftmx4AxDKD5K4zDnr']);
const chainId = '038f4b0fc8ff18a4f0842a8f0564611f6e96e8535901dd45e43ac8691a1c4dca' const chainId = '038f4b0fc8ff18a4f0842a8f0564611f6e96e8535901dd45e43ac8691a1c4dca';
api = new Api({ api = new Api({
rpc, signatureProvider, chainId, textDecoder: new TextDecoder(), textEncoder: new TextEncoder(), rpc, signatureProvider, chainId, textDecoder: new TextDecoder(), textEncoder: new TextEncoder(),
}) });
}) });
it('Doesnt crash', () => { it('Doesnt crash', () => {
expect(api).toBeTruthy() expect(api).toBeTruthy();
}) });
it('getAbi returns an abi', async () => { it('getAbi returns an abi', async () => {
const response = await api.getAbi('testeostoken') const response = await api.getAbi('testeostoken');
expect(response).toBeTruthy() expect(response).toBeTruthy();
}) });
it('getTransactionAbis returns abis by transactions', async () => { it('getTransactionAbis returns abis by transactions', async () => {
const response = await api.getTransactionAbis(transaction) const response = await api.getTransactionAbis(transaction);
expect(response[0].abi.length).toBeGreaterThan(0) expect(response[0].abi.length).toBeGreaterThan(0);
}) });
it('getContract returns a contract', async () => { it('getContract returns a contract', async () => {
const response = await api.getContract('testeostoken') const response = await api.getContract('testeostoken');
expect(response.actions).toBeTruthy() expect(response.actions).toBeTruthy();
}) });
it('deserializeTransaction converts tx from binary', () => { it('deserializeTransaction converts tx from binary', () => {
const tx = api.deserializeTransaction(serializedTx) const tx = api.deserializeTransaction(serializedTx);
expect(tx).toEqual(deserializedTx) expect(tx).toEqual(deserializedTx);
}) });
it('serializeActions converts actions to hex', async () => { it('serializeActions converts actions to hex', async () => {
const response = await api.serializeActions(transaction.actions) const response = await api.serializeActions(transaction.actions);
expect(response).toEqual(serializedActions) expect(response).toEqual(serializedActions);
}) });
it('deserializeActions converts actions from hex', async () => { it('deserializeActions converts actions from hex', async () => {
const response = await api.deserializeActions(serializedActions) const response = await api.deserializeActions(serializedActions);
expect(response).toEqual(deserializedActions) expect(response).toEqual(deserializedActions);
}) });
it('hasRequiredTaposFields returns true, if required fields are present', () => { it('hasRequiredTaposFields returns true, if required fields are present', () => {
const response = api.hasRequiredTaposFields(transaction) const response = api.hasRequiredTaposFields(transaction);
expect(response).toEqual(true) expect(response).toEqual(true);
}) });
}) });
File diff suppressed because it is too large Load Diff
+34 -34
View File
@@ -1,42 +1,42 @@
import * as ecc from 'eosjs-ecc' import * as ecc from 'eosjs-ecc';
import { JsSignatureProvider } from '../eosjs-jssig' import { JsSignatureProvider } from '../eosjs-jssig';
describe('JsSignatureProvider', () => { describe('JsSignatureProvider', () => {
const privateKeys = ['key1', 'key2', 'key3'] const privateKeys = ['key1', 'key2', 'key3'];
const publicKeys = [ const publicKeys = [
'PUB_K1_8iD9ABKFH5b9JyFgb5PE51BdCV74qGN9UMfg9V3TwaExCQWxJm', 'PUB_K1_8iD9ABKFH5b9JyFgb5PE51BdCV74qGN9UMfg9V3TwaExCQWxJm',
'PUB_K1_8f2o2LLQ3phteqyazxirQZnQzQFpnjLnXiUFEJcsSYhnjWNvSX', 'PUB_K1_8f2o2LLQ3phteqyazxirQZnQzQFpnjLnXiUFEJcsSYhnjWNvSX',
'PUB_K1_5imfbmmHC83VRxLRTcvovviAc6LPpyszcDuKtkwka9e9Jg37Hp', 'PUB_K1_5imfbmmHC83VRxLRTcvovviAc6LPpyszcDuKtkwka9e9Jg37Hp',
] ];
it('builds public keys from private when constructed', async () => { it('builds public keys from private when constructed', async () => {
const eccPkFromString = jest.spyOn(ecc.PrivateKey, 'fromString') const eccPkFromString = jest.spyOn(ecc.PrivateKey, 'fromString');
eccPkFromString.mockImplementation((k) => ecc.PrivateKey.fromHex(ecc.sha256(k))) eccPkFromString.mockImplementation((k) => ecc.PrivateKey.fromHex(ecc.sha256(k)));
const provider = new JsSignatureProvider(privateKeys) const provider = new JsSignatureProvider(privateKeys);
const actualPublicKeys = await provider.getAvailableKeys() const actualPublicKeys = await provider.getAvailableKeys();
expect(eccPkFromString).toHaveBeenCalledTimes(privateKeys.length) expect(eccPkFromString).toHaveBeenCalledTimes(privateKeys.length);
expect(actualPublicKeys).toEqual(publicKeys) expect(actualPublicKeys).toEqual(publicKeys);
}) });
it('signs a transaction', async () => { it('signs a transaction', async () => {
const eccSignatureSign = jest.spyOn(ecc.Signature, 'sign') const eccSignatureSign = jest.spyOn(ecc.Signature, 'sign');
eccSignatureSign.mockImplementation((buffer, signKey) => signKey) eccSignatureSign.mockImplementation((buffer, signKey) => signKey);
const provider = new JsSignatureProvider(privateKeys) const provider = new JsSignatureProvider(privateKeys);
const chainId = '12345' const chainId = '12345';
const requiredKeys = [ const requiredKeys = [
publicKeys[0], publicKeys[0],
publicKeys[2], publicKeys[2],
] ];
const serializedTransaction = new Uint8Array([ const serializedTransaction = new Uint8Array([
0, 16, 32, 128, 255, 0, 16, 32, 128, 255,
]) ]);
const abis: any[] = [] const abis: any[] = [];
const signOutput = await provider.sign({ chainId, requiredKeys, serializedTransaction, abis }) const signOutput = await provider.sign({ chainId, requiredKeys, serializedTransaction, abis });
expect(eccSignatureSign).toHaveBeenCalledTimes(2) expect(eccSignatureSign).toHaveBeenCalledTimes(2);
expect(signOutput).toEqual({ signatures: [privateKeys[0], privateKeys[2]], serializedTransaction }) expect(signOutput).toEqual({ signatures: [privateKeys[0], privateKeys[2]], serializedTransaction });
}) });
}) });
+1 -1
View File
@@ -1 +1 @@
global.fetch = require("jest-fetch-mock") global.fetch = require("jest-fetch-mock");
+145 -146
View File
@@ -4,154 +4,153 @@
<script src='../../dist-web/eosjs-jsonrpc.js'></script> <script src='../../dist-web/eosjs-jsonrpc.js'></script>
<script src='../../dist-web/eosjs-jssig.js'></script> <script src='../../dist-web/eosjs-jssig.js'></script>
<script> <script>
let pre = document.getElementsByTagName('pre')[0]; let pre = document.getElementsByTagName('pre')[0];
const privateKey = '5JuH9fCXmU3xbj8nRmhPZaVrxxXrdPaRmZLW1cznNTmTQR2Kg5Z'; // replace with "bob" account private key const privateKey = '5JuH9fCXmU3xbj8nRmhPZaVrxxXrdPaRmZLW1cznNTmTQR2Kg5Z'; // replace with "bob" account private key
/* new accounts for testing can be created by unlocking a cleos wallet then calling: /* new accounts for testing can be created by unlocking a cleos wallet then calling:
* 1) cleos create key --to-console (copy this privateKey & publicKey) * 1) cleos create key --to-console (copy this privateKey & publicKey)
* 2) cleos wallet import * 2) cleos wallet import
* 3) cleos create account bob publicKey * 3) cleos create account bob publicKey
* 4) cleos create account alice publicKey * 4) cleos create account alice publicKey
*/ */
const rpc = new eosjs_jsonrpc.JsonRpc('http://localhost:8888'); const rpc = new eosjs_jsonrpc.JsonRpc('http://localhost:8888');
const signatureProvider = new eosjs_jssig.JsSignatureProvider([privateKey]); const signatureProvider = new eosjs_jssig.JsSignatureProvider([privateKey]);
const api = new eosjs_api.Api({ rpc, signatureProvider }); const api = new eosjs_api.Api({ rpc, signatureProvider });
function waitTwoSeconds() { function waitTwoSeconds() {
return new Promise(resolve => setTimeout(resolve, 2000)); return new Promise(resolve => setTimeout(resolve, 2000));
}
(async () => {
try {
const resultWithConfig = await api.transact({
actions: [{
account: 'eosio.token',
name: 'transfer',
authorization: [{
actor: 'bob',
permission: 'active',
}],
data: {
from: 'bob',
to: 'alice',
quantity: '0.0001 SYS',
memo: '',
},
}]
}, {
blocksBehind: 3,
expireSeconds: 30,
});
pre.textContent += '\n\nTransaction with configured TAPOS pushed!\n\n' + JSON.stringify(resultWithConfig, null, 2);
await waitTwoSeconds(); // run additional tests after 2 second delay
const resultWithoutBroadcast = await api.transact({
actions: [{
account: 'eosio.token',
name: 'transfer',
authorization: [{
actor: 'bob',
permission: 'active',
}],
data: {
from: 'bob',
to: 'alice',
quantity: '0.0001 SYS',
memo: '',
},
}]
}, {
broadcast: false,
blocksBehind: 3,
expireSeconds: 30,
});
pre.textContent = '\n\nTransaction serialized and signed but not pushed!\n\n' + JSON.stringify(resultWithoutBroadcast, null, 2);
await waitTwoSeconds();
const broadcastResult = await api.pushSignedTransaction(resultWithoutBroadcast);
pre.textContent = '\n\nSerialized Transaction and signatures pushed!\n\n' + JSON.stringify(broadcastResult, null, 2);
await waitTwoSeconds();
const blockInfo = await rpc.get_block(broadcastResult.processed.block_num)
const currentDate = new Date();
const timePlusTen = currentDate.getTime() + 10000;
const timeInISOString = (new Date(timePlusTen)).toISOString();
const expiration = timeInISOString.substr(0, timeInISOString.length - 1);
const resultWithoutConfig = await api.transact({
expiration,
ref_block_num: blockInfo.block_num & 0xffff,
ref_block_prefix: blockInfo.ref_block_prefix,
actions: [{
account: 'eosio.token',
name: 'transfer',
authorization: [{
actor: 'bob',
permission: 'active',
}],
data: {
from: 'bob',
to: 'alice',
quantity: '0.0001 SYS',
memo: '',
},
}]
});
pre.textContent = '\n\nTransaction with manual TAPOS pushed!\n\n' + JSON.stringify(resultWithoutConfig, null, 2);
} }
catch(e) {
throw new Error('Web Integration Test Failed Unexpectedly: ' + e.message) (async () => {
} try {
await waitTwoSeconds(); const resultWithConfig = await api.transact({
actions: [{
let failedAsPlanned; account: 'eosio.token',
try { name: 'transfer',
failedAsPlanned = true; authorization: [{
const resultShouldFail = await api.transact({ actor: 'bob',
actions: [{ permission: 'active',
account: 'eosio.token', }],
name: 'transfer', data: {
authorization: [{ from: 'bob',
actor: 'bob', to: 'alice',
permission: 'active', quantity: '0.0001 SYS',
}], memo: '',
data: { },
from: 'bob', }]
to: 'alice', }, {
quantity: '0.0001 SYS', blocksBehind: 3,
memo: '', expireSeconds: 30,
}, });
}] pre.textContent += '\n\nTransaction with configured TAPOS pushed!\n\n' + JSON.stringify(resultWithConfig, null, 2);
}); await waitTwoSeconds(); // run additional tests after 2 second delay
failedAsPlanned = false;
} catch (e) { const resultWithoutBroadcast = await api.transact({
if (e.message == 'Required configuration or TAPOS fields are not present') { actions: [{
pre.textContent = '\n\nCaught Exception successfully: \n\n' + e; account: 'eosio.token',
} name: 'transfer',
else { failedAsPlanned = false } authorization: [{
} actor: 'bob',
if (!failedAsPlanned) { permission: 'active',
throw new Error('The final transact call (lacking TAPoS and config) did not fail as expected'); }],
} data: {
await waitTwoSeconds(); from: 'bob',
to: 'alice',
try { quantity: '0.0001 SYS',
failedAsPlanned = true; memo: '',
const invalidRpcCall = await rpc.get_block(-1); },
failedAsPlanned = false; }]
} }, {
catch(e) { broadcast: false,
if (e instanceof eosjs_jsonrpc.RpcError) { blocksBehind: 3,
pre.textContent = '\n\nCaught RpcError successfully: \n\n' + JSON.stringify(e.json, null, 2); expireSeconds: 30,
} });
else { pre.textContent = '\n\nTransaction serialized and signed but not pushed!\n\n' + JSON.stringify(resultWithoutBroadcast, null, 2);
await waitTwoSeconds();
const broadcastResult = await api.pushSignedTransaction(resultWithoutBroadcast);
pre.textContent = '\n\nSerialized Transaction and signatures pushed!\n\n' + JSON.stringify(broadcastResult, null, 2);
await waitTwoSeconds();
const blockInfo = await rpc.get_block(broadcastResult.processed.block_num)
const currentDate = new Date();
const timePlusTen = currentDate.getTime() + 10000;
const timeInISOString = (new Date(timePlusTen)).toISOString();
const expiration = timeInISOString.substr(0, timeInISOString.length - 1);
const resultWithoutConfig = await api.transact({
expiration,
ref_block_num: blockInfo.block_num & 0xffff,
ref_block_prefix: blockInfo.ref_block_prefix,
actions: [{
account: 'eosio.token',
name: 'transfer',
authorization: [{
actor: 'bob',
permission: 'active',
}],
data: {
from: 'bob',
to: 'alice',
quantity: '0.0001 SYS',
memo: '',
},
}]
});
pre.textContent = '\n\nTransaction with manual TAPOS pushed!\n\n' + JSON.stringify(resultWithoutConfig, null, 2);
}
catch(e) {
throw new Error('Web Integration Test Failed Unexpectedly: ' + e.message)
}
await waitTwoSeconds();
let failedAsPlanned;
try {
failedAsPlanned = true;
const resultShouldFail = await api.transact({
actions: [{
account: 'eosio.token',
name: 'transfer',
authorization: [{
actor: 'bob',
permission: 'active',
}],
data: {
from: 'bob',
to: 'alice',
quantity: '0.0001 SYS',
memo: '',
},
}]
});
failedAsPlanned = false; failedAsPlanned = false;
} } catch (e) {
} if (e.message == 'Required configuration or TAPOS fields are not present') {
if (!failedAsPlanned) { pre.textContent = '\n\nCaught Exception successfully: \n\n' + e;
throw new Error('An rpc error is not being thrown for invalid rpc calls'); }
} else { failedAsPlanned = false }
await waitTwoSeconds(); }
if (!failedAsPlanned) {
})(); throw new Error('The final transact call (lacking TAPoS and config) did not fail as expected');
}
await waitTwoSeconds();
try {
failedAsPlanned = true;
const invalidRpcCall = await rpc.get_block(-1);
failedAsPlanned = false;
}
catch(e) {
if (e instanceof eosjs_jsonrpc.RpcError) {
pre.textContent = '\n\nCaught RpcError successfully: \n\n' + JSON.stringify(e.json, null, 2);
}
else {
failedAsPlanned = false;
}
}
if (!failedAsPlanned) {
throw new Error('An rpc error is not being thrown for invalid rpc calls');
}
await waitTwoSeconds();
})();
</script> </script>
+12 -7
View File
@@ -1,9 +1,14 @@
{ {
"defaultSeverity": "error", "defaultSeverity": "error",
"extends": [ "extends": [
"@blockone/tslint-config-blockone/tslint-config" "@blockone/tslint-config-blockone/tslint-config"
], ],
"jsRules": {}, "jsRules": {},
"rules": { "no-bitwise": false, "no-var-requires": false }, "rules": {
"rulesDirectory": [] "no-bitwise": false,
"no-var-requires": false,
"semicolon": [true, "always"],
"ter-indent": [true, 4]
},
"rulesDirectory": []
} }