diff --git a/README.md b/README.md index 1811a03b..7747b81b 100644 --- a/README.md +++ b/README.md @@ -86,3 +86,5 @@ The browser test suite for the current version of the library is available at: h Instructions and notes on debugging typescript in your IDE. Explains how to match the Mocha test configuration found in the Makefile. [Notes on setting up IDE Debuggers](docs/IDE_Debug.md) + +Made with ☕️ & ❤️ by [Greymass](https://greymass.com), if you find this useful please consider [supporting us](https://greymass.com/support-us). diff --git a/package.json b/package.json index 318c60c9..cc893b3b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@wharfkit/antelope", "description": "Library for working with Antelope powered blockchains.", - "version": "0.8.0", + "version": "0.9.0-rc1", "homepage": "https://github.com/wharfkit/antelope", "license": "BSD-3-Clause-No-Military-License", "main": "lib/antelope.js", diff --git a/src/api/client.ts b/src/api/client.ts index d2ac1740..afe9d102 100644 --- a/src/api/client.ts +++ b/src/api/client.ts @@ -1,17 +1,13 @@ import {APIProvider, APIResponse, FetchProvider, FetchProviderOptions} from './provider' import {ABISerializableConstructor, ABISerializableType} from '../serializer/serializable' import {abiDecode} from '../serializer/decoder' -import {ChainAPI} from './v1/chain' -import {HistoryAPI} from './v1/history' import {BuiltinTypes} from '../serializer/builtins' -export {ChainAPI, HistoryAPI} - export interface APIClientOptions extends FetchProviderOptions { - /** URL to the API node to use, only used if the provider option is not set. */ - url?: string /** API provider to use, if omitted and the url option is set the default provider will be used. */ provider?: APIProvider + /** URL to the API node to use, only used if the provider option is not set. */ + url?: string } export interface APIErrorDetail { @@ -92,7 +88,7 @@ export class APIError extends Error { } } -export class APIClient { +export class BaseAPIClient { static __className = 'APIClient' readonly provider: APIProvider @@ -107,11 +103,6 @@ export class APIClient { } } - v1 = { - chain: new ChainAPI(this), - history: new HistoryAPI(this), - } - async call(args: { path: string params?: unknown diff --git a/src/api/types.ts b/src/api/types.ts deleted file mode 100644 index 3c5e31ed..00000000 --- a/src/api/types.ts +++ /dev/null @@ -1 +0,0 @@ -export * as v1 from './v1/types' diff --git a/src/api/v1/chain.ts b/src/api/v1/chain.ts deleted file mode 100644 index 48c6cedd..00000000 --- a/src/api/v1/chain.ts +++ /dev/null @@ -1,354 +0,0 @@ -import {APIClient} from '../client' - -import { - BlockIdType, - Bytes, - Checksum160, - Checksum256, - Checksum256Type, - Float128, - Float64, - Name, - NameType, - PackedTransaction, - SignedTransaction, - SignedTransactionType, - UInt128, - UInt32, - UInt32Type, - UInt64, -} from '../../chain' - -import { - AccountObject, - AccountsByAuthorizers, - GetAbiResponse, - GetAccountsByAuthorizersParams, - GetBlockHeaderStateResponse, - GetBlockResponse, - GetInfoResponse, - GetProducerScheduleResponse, - GetProtocolFeaturesParams, - GetProtocolFeaturesResponse, - GetRawAbiResponse, - GetTableByScopeParams, - GetTableByScopeResponse, - GetTableRowsParams, - GetTableRowsParamsKeyed, - GetTableRowsParamsTyped, - GetTableRowsResponse, - GetTransactionStatusResponse, - PushTransactionResponse, - SendTransaction2Options, - SendTransaction2Response, - SendTransactionResponse, - TableIndexType, - TableIndexTypes, -} from './types' - -import {ABISerializableConstructor, ABISerializableType, Serializer} from '../../serializer' -import {isInstanceOf} from '../../utils' - -export class ChainAPI { - constructor(private client: APIClient) {} - - async get_abi(accountName: NameType) { - return this.client.call({ - path: '/v1/chain/get_abi', - params: {account_name: Name.from(accountName)}, - }) - } - - async get_raw_abi(accountName: NameType) { - return this.client.call({ - path: '/v1/chain/get_raw_abi', - params: {account_name: Name.from(accountName)}, - responseType: GetRawAbiResponse, - }) - } - - async get_account(accountName: NameType) { - return this.client.call({ - path: '/v1/chain/get_account', - params: {account_name: Name.from(accountName)}, - responseType: AccountObject, - }) - } - - async get_accounts_by_authorizers(params: GetAccountsByAuthorizersParams) { - return this.client.call({ - path: '/v1/chain/get_accounts_by_authorizers', - params, - responseType: AccountsByAuthorizers, - }) - } - - async get_activated_protocol_features(params?: GetProtocolFeaturesParams) { - return this.client.call({ - path: '/v1/chain/get_activated_protocol_features', - params, - responseType: GetProtocolFeaturesResponse, - }) - } - - async get_block(block_num_or_id: BlockIdType | UInt32Type) { - return this.client.call({ - path: '/v1/chain/get_block', - params: {block_num_or_id}, - responseType: GetBlockResponse, - }) - } - - async get_block_header_state(block_num_or_id: BlockIdType | UInt32Type) { - return this.client.call({ - path: '/v1/chain/get_block_header_state', - params: {block_num_or_id}, - responseType: GetBlockHeaderStateResponse, - }) - } - - async get_currency_balance(contract: NameType, accountName: NameType, symbol?: string) { - const params: any = { - account: Name.from(accountName), - code: Name.from(contract), - } - if (symbol) { - params.symbol = symbol - } - return this.client.call({ - path: '/v1/chain/get_currency_balance', - params, - responseType: 'asset[]', - }) - } - - async get_info() { - return this.client.call({ - path: '/v1/chain/get_info', - responseType: GetInfoResponse, - }) - } - - async get_producer_schedule() { - return this.client.call({ - path: '/v1/chain/get_producer_schedule', - responseType: GetProducerScheduleResponse, - }) - } - - async compute_transaction(tx: SignedTransactionType | PackedTransaction) { - if (!isInstanceOf(tx, PackedTransaction)) { - tx = PackedTransaction.fromSigned(SignedTransaction.from(tx)) - } - return this.client.call({ - path: '/v1/chain/compute_transaction', - params: { - transaction: tx, - }, - }) - } - - async send_read_only_transaction(tx: SignedTransactionType | PackedTransaction) { - if (!isInstanceOf(tx, PackedTransaction)) { - tx = PackedTransaction.fromSigned(SignedTransaction.from(tx)) - } - return this.client.call({ - path: '/v1/chain/send_read_only_transaction', - params: { - transaction: tx, - }, - }) - } - - async push_transaction(tx: SignedTransactionType | PackedTransaction) { - if (!isInstanceOf(tx, PackedTransaction)) { - tx = PackedTransaction.fromSigned(SignedTransaction.from(tx)) - } - return this.client.call({ - path: '/v1/chain/push_transaction', - params: tx, - }) - } - - async send_transaction(tx: SignedTransactionType | PackedTransaction) { - if (!isInstanceOf(tx, PackedTransaction)) { - tx = PackedTransaction.fromSigned(SignedTransaction.from(tx)) - } - return this.client.call({ - path: '/v1/chain/send_transaction', - params: tx, - }) - } - - async send_transaction2( - tx: SignedTransactionType | PackedTransaction, - options?: SendTransaction2Options - ) { - if (!isInstanceOf(tx, PackedTransaction)) { - tx = PackedTransaction.fromSigned(SignedTransaction.from(tx)) - } - return this.client.call({ - path: '/v1/chain/send_transaction2', - params: { - return_failure_trace: true, - retry_trx: false, - retry_trx_num_blocks: 0, - transaction: tx, - ...options, - }, - }) - } - - async get_table_rows( - params: GetTableRowsParams - ): Promise> - async get_table_rows( - params: GetTableRowsParamsKeyed - ): Promise> - async get_table_rows< - Row extends ABISerializableConstructor, - Index extends TableIndexType = Name - >( - params: GetTableRowsParamsTyped - ): Promise>> - async get_table_rows( - params: GetTableRowsParamsTyped & - GetTableRowsParamsKeyed - ): Promise>> - async get_table_rows( - params: GetTableRowsParams | GetTableRowsParamsTyped | GetTableRowsParamsKeyed - ) { - const type = (params as GetTableRowsParamsTyped).type - let key_type = (params as GetTableRowsParamsKeyed).key_type - const someBound = params.lower_bound || params.upper_bound - if (!key_type && someBound) { - // determine key type from bounds type - if (isInstanceOf(someBound, UInt64)) { - key_type = 'i64' - } else if (isInstanceOf(someBound, UInt128)) { - key_type = 'i128' - } else if (isInstanceOf(someBound, Checksum256)) { - key_type = 'sha256' - } else if (isInstanceOf(someBound, Checksum160)) { - key_type = 'ripemd160' - } - } - if (!key_type) { - key_type = 'name' - } - let json = params.json - if (json === undefined) { - // if we know the row type don't ask the node to perform abi decoding - json = type === undefined - } - let upper_bound = params.upper_bound - if (upper_bound && typeof upper_bound !== 'string') { - upper_bound = String(upper_bound) - } - let lower_bound = params.lower_bound - if (lower_bound && typeof lower_bound !== 'string') { - lower_bound = String(lower_bound) - } - let scope = params.scope - if (typeof scope === 'undefined') { - scope = String(Name.from(params.code)) - } else if (typeof scope !== 'string') { - scope = String(scope) - } - // eslint-disable-next-line prefer-const - let {rows, more, next_key} = await this.client.call({ - path: '/v1/chain/get_table_rows', - params: { - ...params, - code: Name.from(params.code), - table: Name.from(params.table), - limit: params.limit !== undefined ? UInt32.from(params.limit) : undefined, - scope, - key_type, - json, - upper_bound, - lower_bound, - }, - }) - let ram_payers: Name[] | undefined - if (params.show_payer) { - ram_payers = [] - rows = rows.map(({data, payer}) => { - ram_payers!.push(Name.from(payer)) - return data - }) - } - if (type) { - if (json) { - rows = rows.map((value) => { - if (typeof value === 'string' && Bytes.isBytes(value)) { - // this handles the case where nodeos bails on abi decoding and just returns a hex string - return Serializer.decode({data: Bytes.from(value), type}) - } else { - return Serializer.decode({object: value, type}) - } - }) - } else { - rows = rows - .map((hex) => Bytes.from(hex)) - .map((data) => Serializer.decode({data, type})) - } - } - if (next_key && next_key.length > 0) { - let indexType: ABISerializableType - // set index type so we can decode next_key in the response if present - switch (key_type) { - case 'i64': - indexType = UInt64 - break - case 'i128': - indexType = UInt128 - break - case 'name': - indexType = Name - break - case 'float64': - indexType = Float64 - break - case 'float128': - indexType = Float128 - break - case 'sha256': - indexType = Checksum256 - break - case 'ripemd160': - indexType = Checksum160 - break - default: - throw new Error(`Unsupported key type: ${key_type}`) - } - if (indexType === Name) { - // names are sent back as an uint64 string instead of a name string.. - next_key = Name.from(Serializer.decode({object: next_key, type: UInt64})) - } else { - next_key = Serializer.decode({object: next_key, type: indexType}) - } - } else { - next_key = undefined - } - return {rows, more, next_key, ram_payers} - } - - async get_table_by_scope(params: GetTableByScopeParams) { - return this.client.call({ - path: '/v1/chain/get_table_by_scope', - params, - responseType: GetTableByScopeResponse, - }) - } - - async get_transaction_status(id: Checksum256Type) { - return this.client.call({ - path: '/v1/chain/get_transaction_status', - params: { - id: Checksum256.from(id), - }, - responseType: GetTransactionStatusResponse, - }) - } -} diff --git a/src/api/v1/history.ts b/src/api/v1/history.ts deleted file mode 100644 index 4a21667b..00000000 --- a/src/api/v1/history.ts +++ /dev/null @@ -1,68 +0,0 @@ -import {APIClient} from '../client' - -import { - Checksum256, - Checksum256Type, - Int32, - Int32Type, - Name, - NameType, - PublicKey, - PublicKeyType, - UInt32, - UInt32Type, -} from '../../chain' - -import { - GetActionsResponse, - GetControlledAccountsResponse, - GetKeyAccountsResponse, - GetTransactionResponse, -} from './types' - -export class HistoryAPI { - constructor(private client: APIClient) {} - - async get_actions(accountName: NameType, pos: Int32Type, offset: Int32Type) { - return this.client.call({ - path: '/v1/history/get_actions', - params: { - account_name: Name.from(accountName), - pos: Int32.from(pos), - offset: Int32.from(offset), - }, - responseType: GetActionsResponse, - }) - } - - async get_transaction( - id: Checksum256Type, - options: {blockNumHint?: UInt32Type; excludeTraces?: boolean} = {} - ) { - return this.client.call({ - path: '/v1/history/get_transaction', - params: { - id: Checksum256.from(id), - block_num_hint: options.blockNumHint && UInt32.from(options.blockNumHint), - traces: options.excludeTraces === true ? false : undefined, - }, - responseType: GetTransactionResponse, - }) - } - - async get_key_accounts(publicKey: PublicKeyType) { - return this.client.call({ - path: '/v1/history/get_key_accounts', - params: {public_key: PublicKey.from(publicKey)}, - responseType: GetKeyAccountsResponse, - }) - } - - async get_controlled_accounts(controllingAccount: NameType) { - return this.client.call({ - path: '/v1/history/get_controlled_accounts', - params: {controlling_account: Name.from(controllingAccount)}, - responseType: GetControlledAccountsResponse, - }) - } -} diff --git a/src/api/v1/types.ts b/src/api/v1/types.ts deleted file mode 100644 index 9e18a8e8..00000000 --- a/src/api/v1/types.ts +++ /dev/null @@ -1,705 +0,0 @@ -import pako from 'pako' -import { - ABI, - AnyAction, - Asset, - Authority, - Blob, - BlockId, - BlockTimestamp, - Bytes, - Checksum160, - Checksum256, - Float128, - Float64, - Int32, - Int64, - KeyWeight, - Name, - NameType, - PermissionLevel, - PublicKey, - PublicKeyType, - Signature, - Struct, - TimePoint, - TimePointSec, - Transaction, - TransactionHeader, - TransactionReceipt, - UInt128, - UInt16, - UInt32, - UInt32Type, - UInt64, - Weight, -} from '../../chain' - -import {ABISerializableObject, ABISerializableType, Serializer} from '../../serializer' - -@Struct.type('account_linked_action') -export class AccountLinkedAction extends Struct { - @Struct.field('name') declare account: Name - @Struct.field('name', {optional: true}) declare action: Name -} - -@Struct.type('account_permission') -export class AccountPermission extends Struct { - @Struct.field('name') declare perm_name: Name - @Struct.field('name') declare parent: Name - @Struct.field(Authority) declare required_auth: Authority - @Struct.field(AccountLinkedAction, {optional: true, array: true}) - declare linked_actions: AccountLinkedAction[] -} - -@Struct.type('account_resource_limit') -export class AccountResourceLimit extends Struct { - @Struct.field('int64') declare used: Int64 - @Struct.field('int64') declare available: Int64 - @Struct.field('int64') declare max: Int64 -} - -@Struct.type('account_total_resources') -export class AccountTotalResources extends Struct { - @Struct.field('name') declare owner: Name - @Struct.field('asset') declare net_weight: Asset - @Struct.field('asset') declare cpu_weight: Asset - @Struct.field('uint64') declare ram_bytes: UInt64 -} - -@Struct.type('account_self_delegated_bandwidth') -export class AccountSelfDelegatedBandwidth extends Struct { - @Struct.field('name') declare from: Name - @Struct.field('name') declare to: Name - @Struct.field('asset') declare net_weight: Asset - @Struct.field('asset') declare cpu_weight: Asset -} - -@Struct.type('account_refund_request') -export class AccountRefundRequest extends Struct { - @Struct.field('name') declare owner: Name - @Struct.field('time_point') declare request_time: TimePoint - @Struct.field('asset') declare net_amount: Asset - @Struct.field('asset') declare cpu_amount: Asset -} - -@Struct.type('account_voter_info') -export class AccountVoterInfo extends Struct { - @Struct.field('name') declare owner: Name - @Struct.field('name') declare proxy: Name - @Struct.field('name', {array: true}) declare producers: Name[] - @Struct.field('int64', {optional: true}) staked?: Int64 - @Struct.field('float64') declare last_vote_weight: Float64 - @Struct.field('float64') declare proxied_vote_weight: Float64 - @Struct.field('bool') declare is_proxy: boolean - @Struct.field('uint32', {optional: true}) flags1?: UInt32 - @Struct.field('uint32') reserved2!: UInt32 - @Struct.field('string') reserved3!: string -} - -@Struct.type('account_rex_info_maturities') -export class AccountRexInfoMaturities extends Struct { - /** Expected results from after EOSIO.Contracts v1.9.0 */ - @Struct.field('time_point', {optional: true}) key?: TimePoint - @Struct.field('int64', {optional: true}) value?: Int64 - /** Expected results from before EOSIO.Contracts v1.9.0 */ - @Struct.field('time_point', {optional: true}) first?: TimePoint - @Struct.field('int64', {optional: true}) second?: Int64 -} - -@Struct.type('account_rex_info') -export class AccountRexInfo extends Struct { - @Struct.field('uint32') declare version: UInt32 - @Struct.field('name') declare owner: Name - @Struct.field('asset') declare vote_stake: Asset - @Struct.field('asset') declare rex_balance: Asset - @Struct.field('int64') declare matured_rex: Int64 - @Struct.field(AccountRexInfoMaturities, {array: true}) - declare rex_maturities: AccountRexInfoMaturities[] -} - -export interface GetAbiResponse { - account_name: string - abi?: ABI.Def -} - -@Struct.type('get_raw_abi_response') -export class GetRawAbiResponse extends Struct { - @Struct.field('name') declare account_name: Name - @Struct.field('checksum256') declare code_hash: Checksum256 - @Struct.field('checksum256') declare abi_hash: Checksum256 - @Struct.field(Blob) declare abi: Blob -} - -@Struct.type('account_object') -export class AccountObject extends Struct { - /** The account name of the retrieved account */ - @Struct.field('name') declare account_name: Name - /** Highest block number on the chain */ - @Struct.field('uint32') declare head_block_num: UInt32 - /** Highest block unix timestamp. */ - @Struct.field('time_point') declare head_block_time: TimePoint - /** Indicator of if this is a privileged system account */ - @Struct.field('bool') declare privileged: boolean - /** Last update to accounts contract as unix timestamp. */ - @Struct.field('time_point') declare last_code_update: TimePoint - /** Account created as unix timestamp. */ - @Struct.field('time_point') declare created: TimePoint - /** Account core token balance */ - @Struct.field('asset?') core_liquid_balance?: Asset - @Struct.field('int64') declare ram_quota: Int64 - @Struct.field('int64') declare net_weight: Int64 - @Struct.field('int64') declare cpu_weight: Int64 - @Struct.field(AccountResourceLimit) declare net_limit: AccountResourceLimit - @Struct.field(AccountResourceLimit) declare cpu_limit: AccountResourceLimit - @Struct.field('uint64') declare ram_usage: UInt64 - @Struct.field(AccountPermission, {array: true}) declare permissions: AccountPermission[] - @Struct.field(AccountTotalResources, {optional: true}) - declare total_resources: AccountTotalResources - @Struct.field(AccountSelfDelegatedBandwidth, {optional: true}) - self_delegated_bandwidth?: AccountSelfDelegatedBandwidth - @Struct.field(AccountRefundRequest, {optional: true}) refund_request?: AccountRefundRequest - @Struct.field(AccountVoterInfo, {optional: true}) voter_info?: AccountVoterInfo - @Struct.field(AccountRexInfo, {optional: true}) rex_info?: AccountRexInfo - - getPermission(permission: NameType): AccountPermission { - const name = Name.from(permission) - const match = this.permissions.find((p) => p.perm_name.equals(name)) - if (!match) { - throw new Error(`Unknown permission ${name} on account ${this.account_name}.`) - } - return match - } -} - -@Struct.type('account_by_authorizers_row') -export class AccountByAuthorizersRow extends Struct { - @Struct.field(Name) declare account_name: Name - @Struct.field(Name) declare permission_name: Name - @Struct.field(PublicKey, {optional: true}) declare authorizing_key: PublicKey - @Struct.field(PermissionLevel, {optional: true}) declare authorizing_account: PermissionLevel - @Struct.field(Weight) declare weight: Weight - @Struct.field(UInt32) declare threshold: UInt32 -} - -@Struct.type('account_by_authorizers') -export class AccountsByAuthorizers extends Struct { - @Struct.field(AccountByAuthorizersRow, {array: true}) - declare accounts: AccountByAuthorizersRow[] -} - -@Struct.type('new_producers_entry') -export class NewProducersEntry extends Struct { - @Struct.field('name') declare producer_name: Name - @Struct.field('public_key') declare block_signing_key: PublicKey -} - -@Struct.type('new_producers') -export class NewProducers extends Struct { - @Struct.field('uint32') declare version: UInt32 - @Struct.field(NewProducersEntry, {array: true}) declare producers: NewProducersEntry -} - -@Struct.type('block_extension') -export class BlockExtension extends Struct { - @Struct.field('uint16') declare type: UInt16 - @Struct.field('bytes') declare data: Bytes -} - -@Struct.type('header_extension') -export class HeaderExtension extends Struct { - @Struct.field('uint16') declare type: UInt16 - @Struct.field('bytes') declare data: Bytes -} - -// fc "mutable variant" returned by get_block api -export class TrxVariant implements ABISerializableObject { - static abiName = 'trx_variant' - - static from(data: any) { - let id: Checksum256 - let extra: Record - if (typeof data === 'string') { - id = Checksum256.from(data) - extra = {} - } else { - id = Checksum256.from(data.id) - extra = data - } - return new this(id, extra) - } - - constructor(readonly id: Checksum256, readonly extra: Record) {} - - get transaction(): Transaction | undefined { - if (this.extra.packed_trx) { - switch (this.extra.compression) { - case 'zlib': { - const inflated = pako.inflate(Buffer.from(this.extra.packed_trx, 'hex')) - return Serializer.decode({data: inflated, type: Transaction}) - } - case 'none': { - return Serializer.decode({data: this.extra.packed_trx, type: Transaction}) - } - default: { - throw new Error(`Unsupported compression type ${this.extra.compression}`) - } - } - } - } - - get signatures(): Signature[] | undefined { - if (this.extra.signatures) { - return this.extra.signatures.map(Signature.from) - } - } - - equals(other: any) { - return this.id.equals(other.id) - } - - toJSON() { - return this.id - } -} - -@Struct.type('get_block_response_receipt') -export class GetBlockResponseTransactionReceipt extends TransactionReceipt { - @Struct.field(TrxVariant) declare trx: TrxVariant - - get id(): Checksum256 { - return this.trx.id - } -} - -@Struct.type('get_block_response') -export class GetBlockResponse extends Struct { - @Struct.field('time_point') declare timestamp: TimePoint - @Struct.field('name') declare producer: Name - @Struct.field('uint16') declare confirmed: UInt16 - @Struct.field(BlockId) declare previous: BlockId - @Struct.field('checksum256') declare transaction_mroot: Checksum256 - @Struct.field('checksum256') declare action_mroot: Checksum256 - @Struct.field('uint32') declare schedule_version: UInt32 - @Struct.field(NewProducers, {optional: true}) new_producers?: NewProducers - @Struct.field('header_extension', {optional: true}) header_extensions?: HeaderExtension[] - @Struct.field('any', {optional: true}) new_protocol_features?: any - @Struct.field('signature') declare producer_signature: Signature - @Struct.field(GetBlockResponseTransactionReceipt, {array: true}) - declare transactions: GetBlockResponseTransactionReceipt[] - @Struct.field('block_extension', {optional: true}) declare block_extensions: BlockExtension[] - @Struct.field(BlockId) declare id: BlockId - @Struct.field('uint32') declare block_num: UInt32 - @Struct.field('uint32') declare ref_block_prefix: UInt32 -} - -@Struct.type('active_schedule_producer_authority') -export class ActiveScheduleProducerAuthority extends Struct { - @Struct.field('name') declare producer_name: Name - @Struct.field('any') declare authority: any -} - -@Struct.type('active_schedule_producer') -export class ActiveScheduleProducer extends Struct { - @Struct.field('name') declare producer_name: Name - @Struct.field(ActiveScheduleProducerAuthority) - declare authority: ActiveScheduleProducerAuthority -} - -@Struct.type('active_schedule') -export class ActiveSchedule extends Struct { - @Struct.field('uint32') declare version: UInt32 - @Struct.field(ActiveScheduleProducer, {array: true}) declare producers: ActiveScheduleProducer[] -} - -@Struct.type('block_state_header') -export class BlockStateHeader extends Struct { - @Struct.field('time_point') declare timestamp: TimePoint - @Struct.field('name') declare producer: Name - @Struct.field('uint16') declare confirmed: UInt16 - @Struct.field(BlockId) declare previous: BlockId - @Struct.field('checksum256') declare transaction_mroot: Checksum256 - @Struct.field('checksum256') declare action_mroot: Checksum256 - @Struct.field('uint32') declare schedule_version: UInt32 - @Struct.field(HeaderExtension, {array: true, optional: true}) - header_extensions?: HeaderExtension[] - @Struct.field('signature') declare producer_signature: Signature -} - -@Struct.type('get_block_header_state_response') -export class GetBlockHeaderStateResponse extends Struct { - @Struct.field('uint32') declare block_num: UInt32 - @Struct.field('uint32') declare dpos_proposed_irreversible_blocknum: UInt32 - @Struct.field('uint32') declare dpos_irreversible_blocknum: UInt32 - @Struct.field(BlockId) declare id: BlockId - @Struct.field(BlockStateHeader) declare header: BlockStateHeader - /** Unstructured any fields specific to header state calls */ - @Struct.field('any') declare active_schedule: any - @Struct.field('any') declare blockroot_merkle: any - @Struct.field('any') declare producer_to_last_produced: any - @Struct.field('any') declare producer_to_last_implied_irb: any - @Struct.field('any') declare valid_block_signing_authority: any - @Struct.field('any') declare confirm_count: any - @Struct.field('any') declare pending_schedule: any - @Struct.field('any') declare activated_protocol_features: any - @Struct.field('any') declare additional_signatures: any -} - -@Struct.type('get_info_response') -export class GetInfoResponse extends Struct { - /** Hash representing the last commit in the tagged release. */ - @Struct.field('string') declare server_version: string - /** Hash representing the ID of the chain. */ - @Struct.field('checksum256') declare chain_id: Checksum256 - /** Highest block number on the chain */ - @Struct.field('uint32') declare head_block_num: UInt32 - /** Highest block number on the chain that has been irreversibly applied to state. */ - @Struct.field('uint32') declare last_irreversible_block_num: UInt32 - /** Highest block ID on the chain that has been irreversibly applied to state. */ - @Struct.field(BlockId) declare last_irreversible_block_id: BlockId - /** Highest block ID on the chain. */ - @Struct.field(BlockId) declare head_block_id: BlockId - /** Highest block unix timestamp. */ - @Struct.field('time_point') declare head_block_time: TimePoint - /** Producer that signed the highest block (head block). */ - @Struct.field('name') declare head_block_producer: Name - /** CPU limit calculated after each block is produced, approximately 1000 times `blockCpuLimit`. */ - @Struct.field('uint64') declare virtual_block_cpu_limit: UInt64 - /** NET limit calculated after each block is produced, approximately 1000 times `blockNetLimit`. */ - @Struct.field('uint64') declare virtual_block_net_limit: UInt64 - /** Actual maximum CPU limit. */ - @Struct.field('uint64') declare block_cpu_limit: UInt64 - /** Actual maximum NET limit. */ - @Struct.field('uint64') declare block_net_limit: UInt64 - /** String representation of server version. */ - @Struct.field('string?') server_version_string?: string - /** Sequential block number representing the best known head in the fork database tree. */ - @Struct.field('uint32?') fork_db_head_block_num?: UInt32 - /** Hash representing the best known head in the fork database tree. */ - @Struct.field('block_id_type?') fork_db_head_block_id?: BlockId - - getTransactionHeader(secondsAhead = 120): TransactionHeader { - const expiration = TimePointSec.fromMilliseconds( - this.head_block_time.toMilliseconds() + secondsAhead * 1000 - ) - const id = this.last_irreversible_block_id - const prefixArray = id.array.subarray(8, 12) - const prefix = new Uint32Array(prefixArray.buffer, prefixArray.byteOffset, 1)[0] - return TransactionHeader.from({ - expiration, - ref_block_num: Number(this.last_irreversible_block_num) & 0xffff, - ref_block_prefix: prefix, - }) - } -} - -export interface PushTransactionResponse { - transaction_id: string - processed: { - id: string - block_num: number - block_time: string - receipt: {status: string; cpu_usage_us: number; net_usage_words: number} - elapsed: number - net_usage: number - scheduled: boolean - action_traces: any[] - account_ram_delta: any - } -} - -export interface SendTransactionResponseExceptionStack { - context: { - level: string - file: string - line: number - method: string - hostname: string - thread_name: string - timestamp: string - } - format: string - data: any -} - -export interface SendTransactionResponseException { - code: number - name: string - message: string - stack: SendTransactionResponseExceptionStack[] -} - -export interface SendTransactionResponse { - transaction_id: string - processed: { - id: string - block_num: number - block_time: string - receipt: {status: string; cpu_usage_us: number; net_usage_words: number} - elapsed: number - except?: SendTransactionResponseException - net_usage: number - scheduled: boolean - action_traces: any[] - account_ram_delta: any - } -} - -export interface SendTransaction2Options { - return_failure_trace?: boolean - retry_trx?: boolean - retry_trx_num_blocks?: number -} - -export interface SendTransaction2Response { - transaction_id: string - processed: { - id: string - block_num: number - block_time: string - receipt: {status: string; cpu_usage_us: number; net_usage_words: number} - elapsed: number - net_usage: number - scheduled: boolean - action_traces: any[] - account_ram_delta: any - } -} - -export interface TableIndexTypes { - float128: Float128 - float64: Float64 - i128: UInt128 - i64: UInt64 - name: Name - ripemd160: Checksum160 - sha256: Checksum256 -} - -export type TableIndexType = Name | UInt64 | UInt128 | Float64 | Checksum256 | Checksum160 - -export interface GetTableRowsParams { - /** The name of the smart contract that controls the provided table. */ - code: NameType - /** Name of the table to query. */ - table: NameType - /** The account to which this data belongs, if omitted will be set to be same as `code`. */ - scope?: string | TableIndexType - /** Lower lookup bound. */ - lower_bound?: Index - /** Upper lookup bound. */ - upper_bound?: Index - /** How many rows to fetch, defaults to 10 if unset. */ - limit?: UInt32Type - /** Whether to iterate records in reverse order. */ - reverse?: boolean - /** Position of the index used, defaults to primary. */ - index_position?: - | 'primary' - | 'secondary' - | 'tertiary' - | 'fourth' - | 'fifth' - | 'sixth' - | 'seventh' - | 'eighth' - | 'ninth' - | 'tenth' - /** - * Whether node should try to decode row data using code abi. - * Determined automatically based the `type` param if omitted. - */ - json?: boolean - /** - * Set to true to populate the ram_payers array in the response. - */ - show_payer?: boolean -} - -export interface GetTableRowsParamsKeyed - extends GetTableRowsParams { - /** Index key type, determined automatically when passing a typed `upper_bound` or `lower_bound`. */ - key_type: Key -} - -export interface GetTableRowsParamsTyped - extends GetTableRowsParams { - /** Result type for each row. */ - type: Row -} - -export interface GetTableRowsResponse { - rows: Row[] - more: boolean - ram_payers?: Name[] - next_key?: Index -} - -export interface GetTableByScopeParams { - code: NameType - table?: NameType - lower_bound?: string - upper_bound?: string - limit?: UInt32Type - reverse?: boolean -} - -@Struct.type('get_table_by_scope_response_row') -export class GetTableByScopeResponseRow extends Struct { - @Struct.field('name') declare code: Name - @Struct.field('name') declare scope: Name - @Struct.field('name') declare table: Name - @Struct.field('name') declare payer: Name - @Struct.field('uint32') declare count: UInt32 -} - -@Struct.type('get_table_by_scope_response') -export class GetTableByScopeResponse extends Struct { - @Struct.field(GetTableByScopeResponseRow, {array: true}) - declare rows: GetTableByScopeResponseRow[] - @Struct.field('string') declare more: string -} - -@Struct.type('ordered_action_result') -export class OrderedActionsResult extends Struct { - @Struct.field(UInt64) declare global_action_seq: UInt64 - @Struct.field(Int64) declare account_action_seq: Int64 - @Struct.field(UInt32) declare block_num: UInt32 - @Struct.field(BlockTimestamp) declare block_time: BlockTimestamp - @Struct.field('any') action_trace?: any - @Struct.field('boolean?') irrevirsible?: boolean -} - -@Struct.type('get_actions_response') -export class GetActionsResponse extends Struct { - @Struct.field(OrderedActionsResult, {array: true}) declare actions: OrderedActionsResult[] - @Struct.field(Int32) declare last_irreversible_block: Int32 - @Struct.field(Int32) declare head_block_num: Int32 - @Struct.field('boolean?') time_limit_exceeded_error?: boolean -} - -@Struct.type('transaction_trace') -export class TransactionTrace extends Struct {} - -@Struct.type('trx') -export class Trx extends Struct { - @Struct.field('any') declare actions: AnyAction[] - @Struct.field('any') declare context_free_actions: AnyAction[] - @Struct.field('any') declare context_free_data: any[] - @Struct.field('number') declare delay_sec: number - @Struct.field('string') declare expiration: string - @Struct.field('number') declare max_cpu_usage_ms: number - @Struct.field('number') declare max_net_usage_words: number - @Struct.field('number') declare ref_block_num: number - @Struct.field('number') declare ref_block_prefix: number - @Struct.field('string', {array: true}) declare signatures: string[] -} - -@Struct.type('transaction_info') -export class TransactionInfo extends Struct { - @Struct.field(TransactionReceipt) declare receipt: TransactionReceipt - @Struct.field('trx') declare trx: Trx -} - -@Struct.type('get_transaction_response') -export class GetTransactionResponse extends Struct { - @Struct.field(Checksum256) declare id: Checksum256 - @Struct.field(UInt32) declare block_num: UInt32 - @Struct.field(BlockTimestamp) declare block_time: BlockTimestamp - @Struct.field(UInt32) declare last_irreversible_block: UInt32 - @Struct.field('any?') traces?: TransactionTrace[] - @Struct.field('any') declare trx: TransactionInfo -} - -@Struct.type('get_key_accounts_response') -export class GetKeyAccountsResponse extends Struct { - @Struct.field('name', {array: true}) declare account_names: Name[] -} - -@Struct.type('get_controlled_accounts_response') -export class GetControlledAccountsResponse extends Struct { - @Struct.field('name', {array: true}) declare controlled_accounts: Name[] -} - -@Struct.type('get_transaction_status_response') -export class GetTransactionStatusResponse extends Struct { - @Struct.field('string') declare state: string - @Struct.field('uint32') declare head_number: UInt32 - @Struct.field(BlockId) declare head_id: BlockId - @Struct.field('time_point') declare head_timestamp: TimePoint - @Struct.field('uint32') declare irreversible_number: UInt32 - @Struct.field(BlockId) declare irreversible_id: BlockId - @Struct.field('time_point') declare irreversible_timestamp: TimePoint - @Struct.field(BlockId) declare earliest_tracked_block_id: BlockId - @Struct.field('uint32') declare earliest_tracked_block_number: UInt32 -} - -@Struct.type('producer_authority') -export class ProducerAuthority extends Struct { - @Struct.field(UInt32) threshold!: UInt32 - @Struct.field(KeyWeight, {array: true}) keys!: KeyWeight[] -} - -export type ProducerEntry = [number, ProducerAuthority] - -@Struct.type('producer') -export class Producer extends Struct { - @Struct.field('name') declare producer_name: Name - @Struct.field('any', {array: true}) declare authority: ProducerEntry - - static from(data: any) { - return super.from({ - ...data, - authority: [data.authority[0], ProducerAuthority.from(data.authority[1])], - }) - } -} - -@Struct.type('producer_schedule') -export class ProducerSchedule extends Struct { - @Struct.field('uint32') declare version: UInt32 - @Struct.field(Producer, {array: true}) declare producers: Producer[] -} - -@Struct.type('get_producer_schedule_response') -export class GetProducerScheduleResponse extends Struct { - @Struct.field(ProducerSchedule, {optional: true}) declare active: ProducerSchedule - @Struct.field(ProducerSchedule, {optional: true}) declare pending: ProducerSchedule - @Struct.field(ProducerSchedule, {optional: true}) declare proposed: ProducerSchedule -} - -@Struct.type('protocol_feature') -export class ProtocolFeature extends Struct { - @Struct.field('checksum256') declare feature_digest: Checksum256 - @Struct.field('uint32') declare activation_ordinal: UInt32 - @Struct.field('uint32') declare activation_block_num: UInt32 - @Struct.field('checksum256') declare description_digest: Checksum256 - @Struct.field('string', {array: true}) declare dependencies: string[] - @Struct.field('string') declare protocol_feature_type: string - @Struct.field('any', {array: true}) declare specification: any[] -} - -@Struct.type('get_protocol_features_response') -export class GetProtocolFeaturesResponse extends Struct { - @Struct.field(ProtocolFeature, {array: true}) - declare activated_protocol_features: ProtocolFeature[] - @Struct.field('uint32', {optional: true}) declare more: UInt32 -} - -export interface GetProtocolFeaturesParams { - /** Lower lookup bound. */ - lower_bound?: UInt32 | number - /** Upper lookup bound. */ - upper_bound?: UInt32 | number - /** How many rows to fetch, defaults to 10 if unset. */ - limit?: UInt32Type - /** Flag to indicate it is has to search by block number */ - search_by_block_num?: boolean - /** Whether to iterate records in reverse order. */ - reverse?: boolean -} - -export interface GetAccountsByAuthorizersParams { - accounts?: NameType[] - keys?: PublicKeyType[] -} diff --git a/src/index.ts b/src/index.ts index 99a2ec63..5c2d536e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,7 +9,6 @@ export {isInstanceOf} from './utils' // api export * from './api/client' export * from './api/provider' -export * as API from './api/types' // p2p export * from './p2p/client' diff --git a/test/api.ts b/test/api.ts index 0cbf64cf..4f34a61e 100644 --- a/test/api.ts +++ b/test/api.ts @@ -1,749 +1,56 @@ import {assert} from 'chai' +import {ABI, BaseAPIClient, Blob, Checksum256, Name, NameType, Struct} from '$lib' import {MockProvider} from './utils/mock-provider' -import {makeMockTransaction, signMockTransaction} from './utils/mock-transfer' -import { - ABI, - Action, - AnyAction, - API, - APIClient, - APIError, - Asset, - Blob, - BlockId, - Bytes, - Checksum256, - CompressionType, - Float64, - Name, - PackedTransaction, - PrivateKey, - Serializer, - SignedTransaction, - Struct, - Transaction, - TransactionReceipt, -} from '$lib' - -const jungle = new APIClient({ - provider: new MockProvider(), -}) - -const jungle4 = new APIClient({ - provider: new MockProvider('https://jungle4.api.eosnation.io'), -}) - -const eos = new APIClient({ - provider: new MockProvider('https://eos.greymass.com'), -}) - -const fio = new APIClient({ - provider: new MockProvider('https://fio.greymass.com'), -}) - -const beos = new APIClient({ - provider: new MockProvider('https://api.beos.world'), -}) - -const wax = new APIClient({ - provider: new MockProvider('https://wax.greymass.com'), -}) - -@Struct.type('transfer') -class Transfer extends Struct { - @Struct.field('name') from!: Name - @Struct.field('name') to!: Name - @Struct.field('asset') quantity!: Asset - @Struct.field('string') memo!: string -} - -suite('api v1', function () { - this.slow(200) - this.timeout(10 * 10000) - - test('chain get_abi', async function () { - const response = await jungle4.v1.chain.get_abi('eosio.token') - assert.equal(response.account_name, 'eosio.token') - assert.isObject(response.abi) - if (response.abi) { - assert.equal(response.abi.version, 'eosio::abi/1.2') - } - }) - - test('ABI to blob to ABI', async function () { - // Get an ABI from the API - const response = await jungle4.v1.chain.get_abi('eosio.token') - if (!response.abi) { - throw Error('unable to load ABI') - } - - // Convert the ABI in the response to an ABI serializable object - const originalAbi = ABI.from(response.abi) - - // Encode the ABI - const serializedABI = Serializer.encode({object: originalAbi, type: ABI}) - - // Convert the serialized ABI data into a blob - const blob = new Blob(serializedABI.array) - - // String representation of the blob - const string = String(blob) - - // Restore a new ABI instance from the string representation of the blob - const abiFromBlob = ABI.from(Blob.from(string)) - - // Ensure the two ABIs match - assert.isTrue(originalAbi.equals(abiFromBlob)) - assert.equal(abiFromBlob.tables[0].name, originalAbi.tables[0].name) - assert.equal(originalAbi.tables[0].name, abiFromBlob.tables[0].name) - }) - - test('chain get_raw_abi', async function () { - const response = await jungle4.v1.chain.get_raw_abi('eosio.token') - assert.instanceOf(response, API.v1.GetRawAbiResponse) - assert.instanceOf(response.account_name, Name) - assert.equal(response.account_name, 'eosio.token') - assert.instanceOf(response.code_hash, Checksum256) - assert.equal( - response.code_hash, - '33109b3dd5d354cab5a425c1d4c404c4db056717215f1a8b7ba036a6692811df' - ) - assert.isTrue( - response.code_hash.equals( - '33109b3dd5d354cab5a425c1d4c404c4db056717215f1a8b7ba036a6692811df' - ) - ) - assert.instanceOf(response.abi_hash, Checksum256) - assert.equal( - response.abi_hash, - 'd84356074da34a976528321472d73ac919227b9b01d9de59d8ade6d96440455c' - ) - assert.isTrue( - response.abi_hash.equals( - 'd84356074da34a976528321472d73ac919227b9b01d9de59d8ade6d96440455c' - ) - ) - assert.instanceOf(response.abi, Blob) - const abi = ABI.from(response.abi) - assert.instanceOf(abi, ABI) - assert.equal(abi.version, 'eosio::abi/1.2') - }) - - test('chain get_account', async function () { - const account = await jungle.v1.chain.get_account('teamgreymass') - assert.equal(String(account.account_name), 'teamgreymass') - }) - - test('chain get_account (voter info)', async function () { - const account = await eos.v1.chain.get_account('teamgreymass') - assert.equal(String(account.account_name), 'teamgreymass') - const voterinfo = account.voter_info - assert.instanceOf(voterinfo!.last_vote_weight, Float64) - assert.instanceOf(voterinfo!.proxied_vote_weight, Float64) - }) - - test('chain get_account (system account)', async function () { - const account = await jungle.v1.chain.get_account('eosio') - assert.equal(String(account.account_name), 'eosio') - }) - - test('chain get_account (fio)', async function () { - const account = await fio.v1.chain.get_account('lhp1ytjibtea') - assert.equal(String(account.account_name), 'lhp1ytjibtea') - }) - - test('chain get_account / getPermission with string', async function () { - const account = await jungle.v1.chain.get_account('teamgreymass') - const permission = account.getPermission('active') - assert.equal(permission instanceof API.v1.AccountPermission, true) - assert.equal(String(permission.perm_name), 'active') - }) - - test('chain get_account / getPermission with name', async function () { - const account = await jungle.v1.chain.get_account('teamgreymass') - const permission = account.getPermission(Name.from('active')) - assert.equal(permission instanceof API.v1.AccountPermission, true) - assert.equal(String(permission.perm_name), 'active') - }) - - test('chain get_account / getPermission throws error', async function () { - const account = await jungle.v1.chain.get_account('teamgreymass') - assert.throws(() => { - account.getPermission('invalid') - }) - }) - - test('chain get_account (linked actions)', async function () { - const account = await jungle4.v1.chain.get_account('wharfkit1115') - assert.equal(String(account.account_name), 'wharfkit1115') - const permission = account.getPermission(Name.from('test')) - assert.equal(permission.linked_actions.length, 1) - assert.isTrue(permission.linked_actions[0].account.equals('eosio.token')) - assert.isTrue(permission.linked_actions[0].action.equals('transfer')) - }) - - test('chain get_accounts_by_authorizers (keys)', async function () { - const response = await jungle4.v1.chain.get_accounts_by_authorizers({ - keys: ['PUB_K1_6RWZ1CmDL4B6LdixuertnzxcRuUDac3NQspJEvMnebGcXY4zZj'], - }) - assert.lengthOf(response.accounts, 13) - assert.isTrue(response.accounts[0].account_name.equals('testtestasdf')) - assert.isTrue(response.accounts[0].permission_name.equals('owner')) - assert.isTrue( - response.accounts[0].authorizing_key.equals( - 'PUB_K1_6RWZ1CmDL4B6LdixuertnzxcRuUDac3NQspJEvMnebGcXY4zZj' - ) - ) - assert.isTrue(response.accounts[0].weight.equals(1)) - assert.isTrue(response.accounts[0].threshold.equals(1)) - }) - - test('chain get_accounts_by_authorizers (accounts)', async function () { - const response = await jungle4.v1.chain.get_accounts_by_authorizers({ - accounts: ['eosio.prods'], - }) - assert.lengthOf(response.accounts, 1) - assert.isTrue(response.accounts[0].account_name.equals('eosio')) - assert.isTrue(response.accounts[0].permission_name.equals('active')) - assert.isTrue(response.accounts[0].authorizing_account.actor.equals('eosio.prods')) - assert.isTrue(response.accounts[0].authorizing_account.permission.equals('active')) - assert.isTrue(response.accounts[0].weight.equals(1)) - assert.isTrue(response.accounts[0].threshold.equals(1)) - }) - - test('chain get_activated_protocol_features', async function () { - const response = await jungle4.v1.chain.get_activated_protocol_features() - assert.lengthOf(response.activated_protocol_features, 10) - assert.isTrue(response.more.equals(10)) - const [feature] = response.activated_protocol_features - assert.isTrue( - feature.feature_digest.equals( - '0ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd' - ) - ) - assert.isTrue(feature.activation_ordinal.equals(0)) - assert.isTrue(feature.activation_block_num.equals(4)) - assert.isTrue( - feature.description_digest.equals( - '64fe7df32e9b86be2b296b3f81dfd527f84e82b98e363bc97e40bc7a83733310' - ) - ) - assert.isArray(feature.dependencies) - assert.lengthOf(feature.dependencies, 0) - assert.equal(feature.protocol_feature_type, 'builtin') - assert.isArray(feature.specification) - }) - - test('chain get_block (by id)', async function () { - const block = await eos.v1.chain.get_block( - '00816d41e41f1462acb648b810b20f152d944fabd79aaff31c9f50102e4e5db9' - ) - assert.equal(Number(block.block_num), 8482113) - assert.equal( - block.id.hexString, - '00816d41e41f1462acb648b810b20f152d944fabd79aaff31c9f50102e4e5db9' - ) - }) - - test('chain get_block (by id, typed)', async function () { - const block = await eos.v1.chain.get_block( - BlockId.from('00816d41e41f1462acb648b810b20f152d944fabd79aaff31c9f50102e4e5db9') - ) - assert.equal(Number(block.block_num), 8482113) - assert.equal( - block.id.hexString, - '00816d41e41f1462acb648b810b20f152d944fabd79aaff31c9f50102e4e5db9' - ) - }) - - test('chain get_block (by num)', async function () { - const block = await eos.v1.chain.get_block(8482113) - assert.equal(Number(block.block_num), 8482113) - assert.equal( - block.id.hexString, - '00816d41e41f1462acb648b810b20f152d944fabd79aaff31c9f50102e4e5db9' - ) - }) - - test('chain get_block w/ new_producers', async function () { - const block = await eos.v1.chain.get_block(92565371) - assert.equal(Number(block.block_num), 92565371) - }) - - test('chain get_block w/ transactions', async function () { - const block = await eos.v1.chain.get_block(124472078) - assert.equal(Number(block.block_num), 124472078) - assert.equal(block.transactions.length, 8) - block.transactions.forEach((tx) => { - assert.ok(tx instanceof TransactionReceipt) - assert.ok(tx.trx.id instanceof Checksum256) - }) - const tx = block.transactions[5].trx.transaction - assert.equal(String(tx?.id), String(block.transactions[5].id)) - const sigs = block.transactions[5].trx.signatures || [] - assert.equal( - String(sigs[0]), - 'SIG_K1_KeQEThQJEk7fuQC1zLuFyXZBnVmeRJXq9SrmDJGcerq1RZbgCoH5tvt28xpM7xA1bp7tStVPw17gNMG6hFyYXuNHCU4Wpd' - ) - }) - - test('chain get_block_header_state', async function () { - const header = await eos.v1.chain.get_block_header_state(323978187) - assert.equal(Number(header.block_num), 323978187) - }) - - test('chain get_block', async function () { - const block = await eos.v1.chain.get_block(8482113) - assert.equal(Number(block.block_num), 8482113) - assert.equal( - block.id.hexString, - '00816d41e41f1462acb648b810b20f152d944fabd79aaff31c9f50102e4e5db9' - ) - }) - - test('chain get_block w/ new_producers', async function () { - const block = await eos.v1.chain.get_block(92565371) - assert.equal(Number(block.block_num), 92565371) - }) - - test('chain get_block w/ transactions', async function () { - const block = await eos.v1.chain.get_block(124472078) - assert.equal(Number(block.block_num), 124472078) - block.transactions.forEach((tx) => { - assert.equal(tx instanceof TransactionReceipt, true) - }) - }) - - test('chain get_block w/ compression', async function () { - const block = await wax.v1.chain.get_block(258546986) - assert.equal(Number(block.block_num), 258546986) - for (const tx of block.transactions) { - assert.instanceOf(tx.trx.transaction, Transaction) - } - }) - - test('chain get_currency_balance', async function () { - const balances = await jungle.v1.chain.get_currency_balance('eosio.token', 'lioninjungle') - assert.equal(balances.length, 2) - balances.forEach((asset) => { - assert.equal(asset instanceof Asset, true) - }) - assert.deepEqual(balances.map(String), ['539235868.8986 EOS', '100360.0680 JUNGLE']) - }) - - test('chain get_currency_balance w/ symbol', async function () { - const balances = await jungle.v1.chain.get_currency_balance( - 'eosio.token', - 'lioninjungle', - 'JUNGLE' - ) - assert.equal(balances.length, 1) - assert.equal(balances[0].value, 100360.068) - }) - - test('chain get_info', async function () { - const info = await jungle.v1.chain.get_info() - assert.equal( - info.chain_id.hexString, - '73e4385a2708e6d7048834fbc1079f2fabb17b3c125b146af438971e90716c4d' - ) - }) - - test('chain get_info (beos)', async function () { - const info = await beos.v1.chain.get_info() - assert.equal( - info.chain_id.hexString, - 'cbef47b0b26d2b8407ec6a6f91284100ec32d288a39d4b4bbd49655f7c484112' - ) - }) - - test('chain get_producer_schedule', async function () { - const schedule = await jungle.v1.chain.get_producer_schedule() - assert.isTrue(schedule.active.version.equals(72)) - assert.lengthOf(schedule.active.producers, 21) - assert.isTrue(schedule.active.producers[0].producer_name.equals('alohaeostest')) - assert.lengthOf(schedule.active.producers[0].authority, 2) - assert.isTrue(schedule.active.producers[0].authority[1].threshold.equals(1)) - assert.lengthOf(schedule.active.producers[0].authority[1].keys, 1) - assert.isTrue(schedule.active.producers[0].authority[1].keys[0].weight.equals(1)) - assert.isTrue( - schedule.active.producers[0].authority[1].keys[0].key.equals( - 'PUB_K1_8QwUpioje5txP4XwwXjjufqMs7wjrxkuWhUxcVMaxqrr14Sd2v' - ) - ) - }) - - test('chain push_transaction', async function () { - const info = await jungle.v1.chain.get_info() - const header = info.getTransactionHeader() - const action = Action.from({ - authorization: [ - { - actor: 'corecorecore', - permission: 'active', - }, - ], - account: 'eosio.token', - name: 'transfer', - data: Transfer.from({ - from: 'corecorecore', - to: 'teamgreymass', - quantity: '0.0042 EOS', - memo: 'eosio-core is the best <3', - }), - }) - const transaction = Transaction.from({ - ...header, - actions: [action], - }) - const privateKey = PrivateKey.from('5JW71y3njNNVf9fiGaufq8Up5XiGk68jZ5tYhKpy69yyU9cr7n9') - const signature = privateKey.signDigest(transaction.signingDigest(info.chain_id)) - const signedTransaction = SignedTransaction.from({ - ...transaction, - signatures: [signature], - }) - const result = await jungle.v1.chain.push_transaction(signedTransaction) - assert.equal(result.transaction_id, transaction.id.hexString) - }) - - test('chain push_transaction (compression by default)', async function () { - const info = await jungle.v1.chain.get_info() - const header = info.getTransactionHeader() - const action = Action.from({ - authorization: [ - { - actor: 'corecorecore', - permission: 'active', - }, - ], - account: 'eosio.token', - name: 'transfer', - data: Transfer.from({ - from: 'corecorecore', - to: 'teamgreymass', - quantity: '0.0042 EOS', - memo: 'eosio-core is the best <3', - }), - }) - const transaction = Transaction.from({ - ...header, - actions: [action], - }) - const privateKey = PrivateKey.from('5JW71y3njNNVf9fiGaufq8Up5XiGk68jZ5tYhKpy69yyU9cr7n9') - const signature = privateKey.signDigest(transaction.signingDigest(info.chain_id)) - const signedTransaction = SignedTransaction.from({ - ...transaction, - signatures: [signature], - }) - const packed = PackedTransaction.fromSigned(signedTransaction) - assert.equal(packed.compression, CompressionType.zlib) - }) - - test('chain push_transaction (optional uncompressed)', async function () { - const info = await jungle.v1.chain.get_info() - const header = info.getTransactionHeader() - const action = Action.from({ - authorization: [ - { - actor: 'corecorecore', - permission: 'active', - }, - ], - account: 'eosio.token', - name: 'transfer', - data: Transfer.from({ - from: 'corecorecore', - to: 'teamgreymass', - quantity: '0.0042 EOS', - memo: 'eosio-core is the best <3', - }), - }) - const transaction = Transaction.from({ - ...header, - actions: [action], - }) - const privateKey = PrivateKey.from('5JW71y3njNNVf9fiGaufq8Up5XiGk68jZ5tYhKpy69yyU9cr7n9') - const signature = privateKey.signDigest(transaction.signingDigest(info.chain_id)) - const signedTransaction = SignedTransaction.from({ - ...transaction, - signatures: [signature], - }) - const packed = PackedTransaction.fromSigned(signedTransaction, CompressionType.none) - assert.equal(packed.compression, CompressionType.none) - }) - - test('chain push_transaction (untyped)', async function () { - const info = await jungle.v1.chain.get_info() - const header = info.getTransactionHeader() - const untypedAction: AnyAction = { - authorization: [ - { - actor: 'corecorecore', - permission: 'active', - }, - ], - account: 'eosio.token', - name: 'transfer', - data: { - from: 'corecorecore', - to: 'teamgreymass', - quantity: '0.0042 EOS', - memo: 'eosio-core is the best <3', - }, - } - const {abi} = await jungle.v1.chain.get_abi(untypedAction.account) - if (!abi) { - throw new Error(`No ABI for ${untypedAction.account}`) - } - const action = Action.from(untypedAction, abi) - const transaction = Transaction.from({ - ...header, - actions: [action], - }) - const privateKey = PrivateKey.from('5JW71y3njNNVf9fiGaufq8Up5XiGk68jZ5tYhKpy69yyU9cr7n9') - const signature = privateKey.signDigest(transaction.signingDigest(info.chain_id)) - const signedTransaction = SignedTransaction.from({ - ...transaction, - signatures: [signature], - }) - const result = await jungle.v1.chain.push_transaction(signedTransaction) - assert.equal(result.transaction_id, transaction.id.hexString) - }) - - test('chain compute_transaction', async function () { - const info = await jungle4.v1.chain.get_info() - const transaction = await makeMockTransaction(info) - const signedTransaction = await signMockTransaction(transaction, info) - const result = await jungle4.v1.chain.compute_transaction(signedTransaction) - assert.equal(result.transaction_id, transaction.id.hexString) - }) - - test('chain send_transaction', async function () { - const info = await jungle4.v1.chain.get_info() - const transaction = await makeMockTransaction(info) - const signedTransaction = await signMockTransaction(transaction, info) - const result = await jungle4.v1.chain.send_transaction(signedTransaction) - assert.equal(result.transaction_id, transaction.id.hexString) - }) - - test('chain send_transaction2 (default)', async function () { - const info = await jungle4.v1.chain.get_info() - const memo = this.test ? this.test.title : undefined - const transaction = await makeMockTransaction(info, memo) - const signedTransaction = await signMockTransaction(transaction, info) - const result = await jungle4.v1.chain.send_transaction2(signedTransaction) - assert.equal(result.transaction_id, transaction.id.hexString) - }) - - test('chain send_transaction2 (failure traces)', async function () { - const info = await jungle4.v1.chain.get_info() - const memo = this.test ? this.test.title : undefined - const transaction = await makeMockTransaction(info, memo) - const signedTransaction = await signMockTransaction(transaction, info) - const result = await jungle4.v1.chain.send_transaction2(signedTransaction, { - return_failure_trace: true, - }) - assert.equal(result.transaction_id, transaction.id.hexString) - }) - - test('chain send_transaction2 (retry)', async function () { - const info = await jungle4.v1.chain.get_info() - const memo = this.test ? this.test.title : undefined - const transaction = await makeMockTransaction(info, memo) - const signedTransaction = await signMockTransaction(transaction, info) - const result = await jungle4.v1.chain.send_transaction2(signedTransaction, { - retry_trx: true, - retry_trx_num_blocks: 10, - }) - assert.equal(result.transaction_id, transaction.id.hexString) - }) - - test('chain get_table_rows (untyped)', async function () { - const res = await eos.v1.chain.get_table_rows({ - code: 'eosio.token', - table: 'stat', - scope: Asset.Symbol.from('4,EOS').code.value.toString(), - key_type: 'i64', - }) - assert.equal(res.rows.length, 1) - assert.equal(res.rows[0].max_supply, '10000000000.0000 EOS') - }) - - test('chain get_table_rows (typed)', async function () { - @Struct.type('user') - class User extends Struct { - @Struct.field('name') account!: Name - @Struct.field('float64') balance!: Float64 - } - const res1 = await eos.v1.chain.get_table_rows({ - code: 'fuel.gm', - table: 'users', - type: User, - limit: 1, - }) - assert.equal(res1.rows[0].account instanceof Name, true) - assert.equal(res1.more, true) - assert.equal(String(res1.rows[0].account), 'aaaa') - const res2 = await eos.v1.chain.get_table_rows({ - code: 'fuel.gm', - table: 'users', - type: User, - limit: 2, - lower_bound: res1.next_key, - }) - assert.equal(String(res2.rows[0].account), 'atomichub') - assert.equal(String(res2.next_key), 'boidservices') - assert.equal(Number(res2.rows[1].balance).toFixed(6), (0.02566).toFixed(6)) - }) - - test('chain get_table_rows (empty scope)', async function () { - const res = await jungle.v1.chain.get_table_rows({ - code: 'eosio', - table: 'powup.state', - scope: '', - }) - assert.equal(res.rows.length, 1) - }) - - test('chain get_table_rows (ram payer)', async function () { - const res = await eos.v1.chain.get_table_rows({ - code: 'eosio.token', - table: 'stat', - scope: Asset.SymbolCode.from('EOS').value, - show_payer: true, - }) - assert.equal(res.rows.length, 1) - assert.equal(String(res.ram_payers![0]), 'eosio.token') - }) - - test('chain get_table_by_scope', async function () { - const res = await eos.v1.chain.get_table_by_scope({ - code: 'eosio.token', - table: 'accounts', - limit: 1, - }) - assert.equal(res.rows.length, 1) - res.rows.forEach((row) => { - assert.equal(row instanceof API.v1.GetTableByScopeResponseRow, true) - }) - const res2 = await eos.v1.chain.get_table_by_scope({ - code: 'eosio.token', - table: 'accounts', - lower_bound: res.more, - upper_bound: res.more, - limit: 1, - }) - res2.rows.forEach((row) => { - assert.equal(row instanceof API.v1.GetTableByScopeResponseRow, true) - }) - }) - - test('chain send_read_only_transaction', async function () { - const info = await jungle4.v1.chain.get_info() - const header = info.getTransactionHeader(90) - - @Struct.type('returnvalue') - class Returnvalue extends Struct { - @Struct.field(Name) message!: Name - } - - const action = Action.from({ - authorization: [], // No authorizations - account: 'abcabcabc333', - name: 'returnvalue', - data: Returnvalue.from({ - message: 'hello', - }), - }) - - const transaction = Transaction.from({ - ...header, - actions: [action], - }) - - const res = await jungle4.v1.chain.send_read_only_transaction(transaction) - - assert.equal(res.processed.action_traces.length, 1) - assert.equal(res.processed.action_traces[0].return_value_data, 'Validation has passed.') - assert.equal( - res.processed.action_traces[0].return_value_hex_data, - '1656616c69646174696f6e20686173207061737365642e' - ) - - // Test decoding raw hex data as string - const decoded = Serializer.decode({ - type: 'string', - data: Bytes.from(res.processed.action_traces[0].return_value_hex_data), - }) - assert.equal(decoded, 'Validation has passed.') - }) - - test('api errors', async function () { - try { - await jungle.call({path: '/v1/chain/get_account', params: {account_name: 'nani1'}}) - assert.fail() - } catch (error) { - assert.equal(error instanceof APIError, true) - const apiError = error as APIError - assert.equal(apiError.message, 'Account not found at /v1/chain/get_account') - assert.equal(apiError.name, 'exception') - assert.equal(apiError.code, 0) - assert.equal(error.response.headers['access-control-allow-origin'], '*') - assert.equal(error.response.headers.date, 'Fri, 04 Aug 2023 18:50:00 GMT') - assert.deepEqual(apiError.details, [ - { - file: 'http_plugin.cpp', - line_number: 954, - message: - 'unknown key (boost::tuples::tuple): (0 nani1)', - method: 'handle_exception', - }, - ]) - } - }) - - test('history get_actions', async function () { - const res = await eos.v1.history.get_actions('teamgreymass', 1, 1) - assert.equal(res.actions.length, 1) - }) - - test('history get_transaction', async function () { - const res = await eos.v1.history.get_transaction( - '03ef96a276a252b66595d91006ad0ff38ed999816f078bc5d87f88368a9354e7' - ) - assert(Array.isArray(res.traces), 'response should have traces') - assert.equal(res.id, '03ef96a276a252b66595d91006ad0ff38ed999816f078bc5d87f88368a9354e7') - assert.equal(res.block_num, 199068081) - }) - - test('history get_transaction (no traces)', async function () { - const res = await eos.v1.history.get_transaction( - '03ef96a276a252b66595d91006ad0ff38ed999816f078bc5d87f88368a9354e7', - {excludeTraces: true} - ) - assert.equal(res.traces, null, 'response should not have traces') - assert.equal(res.id, '03ef96a276a252b66595d91006ad0ff38ed999816f078bc5d87f88368a9354e7') - assert.equal(res.block_num, 199068081) - }) - - test('history get_key_accounts', async function () { - const res = await eos.v1.history.get_key_accounts( - 'PUB_K1_6gqJ7sdPgjHLFLtks9cRPs5qYHa9U3CwK4P2JasTLWKQBdT2GF' - ) - assert.equal(res.account_names.length, 2) - }) - - test('history get_controlled_accounts', async function () { - const res = await eos.v1.history.get_controlled_accounts('teamgreymass') - assert.equal(res.controlled_accounts.length, 2) - }) - - test('chain get_transaction_status', async function () { - const res = await jungle4.v1.chain.get_transaction_status( - '153207ae7b30621421b968fa3c327db0d89f70975cf2bee7f8118c336094019a' - ) - assert.equal(res.state, 'UNKNOWN') +suite('api', function () { + test('allows interface as generic', async function () { + // Response type + interface GetAbiResponse { + account_name: string + abi?: ABI.Def + } + // Client + class CustomAPI extends BaseAPIClient { + async get_abi(accountName: NameType) { + return this.call({ + path: '/v1/chain/get_abi', + params: {account_name: Name.from(accountName)}, + }) + } + } + const provider = new MockProvider('https://jungle4.greymass.com') + const client = new CustomAPI({provider}) + assert.instanceOf(client, BaseAPIClient) + const result = await client.get_abi('eosio.token') + assert.equal(result.account_name, 'eosio.token') + }) + test('allows defining response type', async function () { + // Response type + @Struct.type('get_raw_abi_response') + class GetRawAbiResponse extends Struct { + @Struct.field('name') declare account_name: Name + @Struct.field('checksum256') declare code_hash: Checksum256 + @Struct.field('checksum256') declare abi_hash: Checksum256 + @Struct.field(Blob) declare abi: Blob + } + // Client + class CustomAPI extends BaseAPIClient { + async get_raw_abi(accountName: NameType) { + return this.call({ + path: '/v1/chain/get_raw_abi', + params: {account_name: Name.from(accountName)}, + responseType: GetRawAbiResponse, + }) + } + } + const provider = new MockProvider('https://jungle4.greymass.com') + const client = new CustomAPI({provider}) + assert.instanceOf(client, BaseAPIClient) + const result = await client.get_raw_abi('eosio.token') + assert.instanceOf(result.account_name, Name) + assert.instanceOf(result.code_hash, Checksum256) + assert.instanceOf(result.abi_hash, Checksum256) + assert.instanceOf(result.abi, Blob) }) }) diff --git a/test/data/11fe3460125bdf6b983cd9e0d2522d449d6152fa.json b/test/data/11fe3460125bdf6b983cd9e0d2522d449d6152fa.json new file mode 100644 index 00000000..fcb5ad5f --- /dev/null +++ b/test/data/11fe3460125bdf6b983cd9e0d2522d449d6152fa.json @@ -0,0 +1,22 @@ +{ + "api": "https://jungle4.greymass.com", + "headers": { + "access-control-allow-headers": "X-Requested-With,Accept,Content-Type,Origin", + "access-control-allow-methods": "GET, POST, OPTIONS", + "access-control-allow-origin": "*", + "connection": "close", + "content-length": "877", + "content-type": "application/json", + "date": "Fri, 18 Aug 2023 17:36:41 GMT", + "host": "jungle4.greymass.com", + "server": "nginx/1.18.0 (Ubuntu)" + }, + "status": 200, + "json": { + "account_name": "eosio.token", + "code_hash": "33109b3dd5d354cab5a425c1d4c404c4db056717215f1a8b7ba036a6692811df", + "abi_hash": "d84356074da34a976528321472d73ac919227b9b01d9de59d8ade6d96440455c", + "abi": "DmVvc2lvOjphYmkvMS4yAAgHYWNjb3VudAABB2JhbGFuY2UFYXNzZXQFY2xvc2UAAgVvd25lcgRuYW1lBnN5bWJvbAZzeW1ib2wGY3JlYXRlAAIGaXNzdWVyBG5hbWUObWF4aW11bV9zdXBwbHkFYXNzZXQOY3VycmVuY3lfc3RhdHMAAwZzdXBwbHkFYXNzZXQKbWF4X3N1cHBseQVhc3NldAZpc3N1ZXIEbmFtZQVpc3N1ZQADAnRvBG5hbWUIcXVhbnRpdHkFYXNzZXQEbWVtbwZzdHJpbmcEb3BlbgADBW93bmVyBG5hbWUGc3ltYm9sBnN5bWJvbAlyYW1fcGF5ZXIEbmFtZQZyZXRpcmUAAghxdWFudGl0eQVhc3NldARtZW1vBnN0cmluZwh0cmFuc2ZlcgAEBGZyb20EbmFtZQJ0bwRuYW1lCHF1YW50aXR5BWFzc2V0BG1lbW8Gc3RyaW5nBgAAAAAAhWlEBWNsb3NlAAAAAACobNRFBmNyZWF0ZQAAAAAAAKUxdgVpc3N1ZQAAAAAAADBVpQRvcGVuAAAAAACo67K6BnJldGlyZQAAAABXLTzNzQh0cmFuc2ZlcgACAAAAOE9NETIDaTY0AAAHYWNjb3VudAAAAAAAkE3GA2k2NAAADmN1cnJlbmN5X3N0YXRzAAAAAA===" + }, + "text": "{\"account_name\":\"eosio.token\",\"code_hash\":\"33109b3dd5d354cab5a425c1d4c404c4db056717215f1a8b7ba036a6692811df\",\"abi_hash\":\"d84356074da34a976528321472d73ac919227b9b01d9de59d8ade6d96440455c\",\"abi\":\"DmVvc2lvOjphYmkvMS4yAAgHYWNjb3VudAABB2JhbGFuY2UFYXNzZXQFY2xvc2UAAgVvd25lcgRuYW1lBnN5bWJvbAZzeW1ib2wGY3JlYXRlAAIGaXNzdWVyBG5hbWUObWF4aW11bV9zdXBwbHkFYXNzZXQOY3VycmVuY3lfc3RhdHMAAwZzdXBwbHkFYXNzZXQKbWF4X3N1cHBseQVhc3NldAZpc3N1ZXIEbmFtZQVpc3N1ZQADAnRvBG5hbWUIcXVhbnRpdHkFYXNzZXQEbWVtbwZzdHJpbmcEb3BlbgADBW93bmVyBG5hbWUGc3ltYm9sBnN5bWJvbAlyYW1fcGF5ZXIEbmFtZQZyZXRpcmUAAghxdWFudGl0eQVhc3NldARtZW1vBnN0cmluZwh0cmFuc2ZlcgAEBGZyb20EbmFtZQJ0bwRuYW1lCHF1YW50aXR5BWFzc2V0BG1lbW8Gc3RyaW5nBgAAAAAAhWlEBWNsb3NlAAAAAACobNRFBmNyZWF0ZQAAAAAAAKUxdgVpc3N1ZQAAAAAAADBVpQRvcGVuAAAAAACo67K6BnJldGlyZQAAAABXLTzNzQh0cmFuc2ZlcgACAAAAOE9NETIDaTY0AAAHYWNjb3VudAAAAAAAkE3GA2k2NAAADmN1cnJlbmN5X3N0YXRzAAAAAA===\"}" +} \ No newline at end of file