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