From 7d6c7e5b75a1a4e8d735a731becef2296441c852 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 9 Dec 2019 15:54:16 +0300 Subject: [PATCH 01/62] [ECHOJS-245] Serialize `eth_address_type` as dynamic-size buffer instead of 20-bytes buffer --- src/serializers/protocol/ethAddress.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serializers/protocol/ethAddress.js b/src/serializers/protocol/ethAddress.js index 8492d347..13d78711 100644 --- a/src/serializers/protocol/ethAddress.js +++ b/src/serializers/protocol/ethAddress.js @@ -1,4 +1,4 @@ import { bytes } from '../basic'; -const ethAddress = bytes(20); +const ethAddress = bytes(); export default ethAddress; From b44daea722c33bd36f2adac7a8eff04432a6ff1e Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 9 Dec 2019 15:56:26 +0300 Subject: [PATCH 02/62] Add field `btc_block_number:uint32` to `sidechain_btc_aggregate_operation` --- src/serializers/protocol/sidechain/btc.js | 3 ++- types/serializers/protocol/sidechain/btc.d.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/serializers/protocol/sidechain/btc.js b/src/serializers/protocol/sidechain/btc.js index 50a98097..27201811 100644 --- a/src/serializers/protocol/sidechain/btc.js +++ b/src/serializers/protocol/sidechain/btc.js @@ -11,7 +11,7 @@ import { btcTransactionDetailsSerializer } from '../../chain/sidechain/btc'; import { struct, set, map, optional } from '../../collections'; import { string as stringSerializer, integers } from '../../basic'; import btcPublicKey from '../btcPublicKey'; -import { uint8 } from '../../basic/integers'; +import { uint8, uint32 } from '../../basic/integers'; export const sidechainBtcCreateAddressOperationPropsSerializer = struct({ fee: asset, @@ -62,6 +62,7 @@ export const sidechainBtcAggregateOperationPropsSerializer = struct({ sma_address: struct({ address: stringSerializer }), committee_member_ids_in_script: map(accountId, btcPublicKey), aggregation_out_value: integers.uint64, + btc_block_number: uint32, previous_aggregation: optional(btcAggregatingId), cpfp_depth: uint8, signatures: map(integers.uint32, stringSerializer), diff --git a/types/serializers/protocol/sidechain/btc.d.ts b/types/serializers/protocol/sidechain/btc.d.ts index b1682e5f..7e08ee0d 100644 --- a/types/serializers/protocol/sidechain/btc.d.ts +++ b/types/serializers/protocol/sidechain/btc.d.ts @@ -52,6 +52,7 @@ export declare const sidechainBtcAggregateOperationPropsSerializer: StructSerial withdrawals: SetSerializer, transaction_id: typeof sha256, aggregation_out_value: typeof integers.uint64, + btc_block_number: typeof integers.uint32, sma_address: StructSerializer<{ address: StringSerializer }>, committee_member_ids_in_script: MapSerializer, previous_aggregation: typeof btcAggregatingId, From f2e31ddcb144191f9a38e38b8af6f481974433ef Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 9 Dec 2019 16:09:57 +0300 Subject: [PATCH 03/62] [ECHOJS-245] Change `sidechain_config_object` --- docs/API.md | 12 ++++++------ docs/Serializers.md | 11 ++++++----- src/echo/api.js | 12 ++++++------ src/serializers/plugins/sidechain/config.js | 12 ++++++------ types/serializers/plugins/sidechain/config.d.ts | 12 ++++++------ 5 files changed, 30 insertions(+), 29 deletions(-) diff --git a/docs/API.md b/docs/API.md index 828e7577..6fa28d85 100644 --- a/docs/API.md +++ b/docs/API.md @@ -1032,6 +1032,7 @@ try { eth_gen_address_method:{method:String,gas:Number}, eth_withdraw_method:{method:String,gas:Number}, eth_update_addr_method:{method:String,gas:Number}, + eth_update_contract_address:{method:String,gas:Number}, eth_withdraw_token_method:{method:String,gas:Number}, eth_collect_tokens_method:{method:String,gas:Number}, eth_committee_updated_topic:String, @@ -1041,14 +1042,13 @@ try { erc20_deposit_topic:String, erc20_withdraw_topic:String, ETH_asset_id:String, - waiting_eth_blocks:Number, - fines:{generate_eth_address:Number}, - waiting_blocks:Number, BTC_asset_id:String, - waiting_btc_blocks:Number, + fines:{generate_eth_address:Number|String}, + gas_price:Number|String, satoshis_per_byte:Number, - echo_blocks_per_aggregation:Number, - gas_price:String, + coefficient_waiting_blocks:Number, + btc_deposit_withdrawal_min:Number|String, + btc_deposit_withdrawal_fee:Number|String, }, gas_price:{ price:Number|String, diff --git a/docs/Serializers.md b/docs/Serializers.md index 04977373..ae2d9f74 100644 --- a/docs/Serializers.md +++ b/docs/Serializers.md @@ -434,6 +434,7 @@ console.log(s.serialize(input).toString('hex')); |eth_gen_address_method|[`eth method`](#eth-method)| |eth_withdraw_method|[`eth method`](#eth-method)| |eth_update_addr_method|[`eth method`](#eth-method)| +|eth_update_contract_address|[`eth method`](#eth-method)| |eth_withdraw_token_method|[`eth method`](#eth-method)| |eth_collect_tokens_method|[`eth method`](#eth-method)| |eth_committee_updated_topic|[`eth topic`](#eth-topic)| @@ -443,13 +444,13 @@ console.log(s.serialize(input).toString('hex')); |erc20_deposit_topic|[`eth topic`](#eth-topic)| |erc20_withdraw_topic|[`eth topic`](#eth-topic)| |ETH_asset_id|[`assetId`](#protocol-object-id)| -|waiting_eth_blocks|[`uint32`](#integers)| -|fines|[`fines`](#fines)| -|waiting_blocks|[`uint32`](#integers)| |BTC_asset_id|[`assetId`](#protocol-object-id)| -|waiting_btc_blocks|[`uint32`](#integers)| +|fines|[`fines`](#fines)|: typeof sidechainFinesSerializer, +|gas_price|[`uint64`](#integers)| |satoshis_per_byte|[`uint32`](#integers)| -|echo_blocks_per_aggregation|[`uint32`](#integers)| +|coefficient_waiting_blocks|[`uint32`](#integers)| +|btc_deposit_withdrawal_min|[`uint64`](#integers)| +|btc_deposit_withdrawal_fee|[`uint64`](#integers)| #### ERC20 config diff --git a/src/echo/api.js b/src/echo/api.js index 6d31f1ac..f6cab663 100644 --- a/src/echo/api.js +++ b/src/echo/api.js @@ -156,6 +156,7 @@ import { PublicKey } from '../crypto'; * eth_gen_address_method:{method:String,gas:Number}, * eth_withdraw_method:{method:String,gas:Number}, * eth_update_addr_method:{method:String,gas:Number}, +* eth_update_contract_address:{method:String,gas:Number}, * eth_withdraw_token_method:{method:String,gas:Number}, * eth_collect_tokens_method:{method:String,gas:Number}, * eth_committee_updated_topic:String, @@ -165,14 +166,13 @@ import { PublicKey } from '../crypto'; * erc20_deposit_topic:String, * erc20_withdraw_topic:String, * ETH_asset_id:String, -* waiting_eth_blocks:Number, -* fines:{generate_eth_address:Number}, -* waiting_blocks:Number, * BTC_asset_id:String, -* waiting_btc_blocks:Number, +* fines:{generate_eth_address:Number|String}, +* gas_price:Number|String, * satoshis_per_byte:Number, -* echo_blocks_per_aggregation:Number, -* gas_price:String, +* coefficient_waiting_blocks:Number, +* btc_deposit_withdrawal_min:Number|String, +* btc_deposit_withdrawal_fee:Number|String, * }, * gas_price:{ * price:Number|String, diff --git a/src/serializers/plugins/sidechain/config.js b/src/serializers/plugins/sidechain/config.js index 8b1df3d8..e3321134 100644 --- a/src/serializers/plugins/sidechain/config.js +++ b/src/serializers/plugins/sidechain/config.js @@ -19,6 +19,7 @@ export const sidechainConfigSerializer = struct({ eth_gen_address_method: ethMethodSerializer, eth_withdraw_method: ethMethodSerializer, eth_update_addr_method: ethMethodSerializer, + eth_update_contract_address: ethMethodSerializer, eth_withdraw_token_method: ethMethodSerializer, eth_collect_tokens_method: ethMethodSerializer, eth_committee_updated_topic: ethTopicSerializer, @@ -28,14 +29,13 @@ export const sidechainConfigSerializer = struct({ erc20_deposit_topic: ethTopicSerializer, erc20_withdraw_topic: ethTopicSerializer, ETH_asset_id: assetId, - waiting_eth_blocks: uint32, - fines: sidechainFinesSerializer, - waiting_blocks: uint32, BTC_asset_id: assetId, - waiting_btc_blocks: uint32, + fines: sidechainFinesSerializer, + gas_price: uint64, satoshis_per_byte: uint32, - echo_blocks_per_aggregation: uint32, - echo_blocks_per_deposit: uint32, + coefficient_waiting_blocks: uint32, + btc_deposit_withdrawal_min: uint64, + btc_deposit_withdrawal_fee: uint64, }); export const sidechainERC20ConfigSerializer = struct({ diff --git a/types/serializers/plugins/sidechain/config.d.ts b/types/serializers/plugins/sidechain/config.d.ts index 21a15b9c..cdbc6cb7 100644 --- a/types/serializers/plugins/sidechain/config.d.ts +++ b/types/serializers/plugins/sidechain/config.d.ts @@ -19,6 +19,7 @@ export declare const sidechainConfigSerializer: StructSerializer<{ eth_gen_address_method: typeof ethMethodSerializer, eth_withdraw_method: typeof ethMethodSerializer, eth_update_addr_method: typeof ethMethodSerializer, + eth_update_contract_address: typeof ethMethodSerializer, eth_withdraw_token_method: typeof ethMethodSerializer, eth_collect_tokens_method: typeof ethMethodSerializer, eth_committee_updated_topic: typeof ethTopicSerializer, @@ -28,14 +29,13 @@ export declare const sidechainConfigSerializer: StructSerializer<{ erc20_deposit_topic: typeof ethTopicSerializer, erc20_withdraw_topic: typeof ethTopicSerializer, ETH_asset_id: typeof assetId, - waiting_eth_blocks: typeof uint32, - fines: typeof sidechainFinesSerializer, - waiting_blocks: typeof uint32, BTC_asset_id: typeof assetId, - waiting_btc_blocks: typeof uint32, + fines: typeof sidechainFinesSerializer, + gas_price: typeof uint64, satoshis_per_byte: typeof uint32, - echo_blocks_per_aggregation: typeof uint32, - echo_blocks_per_deposit: typeof uint32, + coefficient_waiting_blocks: typeof uint32, + btc_deposit_withdrawal_min: typeof uint64, + btc_deposit_withdrawal_fee: typeof uint64, }>; export declare const sidechainERC20ConfigSerializer: StructSerializer<{ From 3db4919126811baf0bcd9a0c1f1c88973b94a97c Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 9 Dec 2019 16:33:29 +0300 Subject: [PATCH 04/62] [ECHOJS-245] Add `sidechain_eth_send_deposit_operation` --- docs/Serializers.md | 2 +- echo@0.14.0-rc.1-migration.md | 11 ++++++ src/constants/operations-ids.js | 37 ++++++++++--------- src/serializers/chain/id/protocol.js | 2 +- src/serializers/operation.js | 1 + src/serializers/protocol/fee_parameters.js | 1 + src/serializers/protocol/sidechain/eth.js | 9 ++++- src/serializers/protocol/sidechain/index.js | 5 ++- types/interfaces/OperationId.d.ts | 37 ++++++++++--------- types/serializers/chain/id/protocol.d.ts | 4 +- types/serializers/operation.d.ts | 1 + .../serializers/protocol/fee_parameters.d.ts | 1 + types/serializers/protocol/sidechain/eth.d.ts | 9 ++++- .../serializers/protocol/sidechain/index.d.ts | 5 ++- 14 files changed, 79 insertions(+), 46 deletions(-) create mode 100644 echo@0.14.0-rc.1-migration.md diff --git a/docs/Serializers.md b/docs/Serializers.md index ae2d9f74..4efd5be8 100644 --- a/docs/Serializers.md +++ b/docs/Serializers.md @@ -331,7 +331,7 @@ Available protocol object id serializers: * `vestingBalanceId` * `balanceId` * `contractId` -* `depositId` +* `ethDepositId` * `withdrawId` * `erc20TokenId` diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md new file mode 100644 index 00000000..1d15ee6e --- /dev/null +++ b/echo@0.14.0-rc.1-migration.md @@ -0,0 +1,11 @@ +* [x] Add field `btc_block_number` to `sidechain_btc_aggregate_operation` and `btc_aggregating_object` +* [x] Add fields `btc_deposit_withdrawal_min`, `btc_deposit_withdrawal_fee` to `sidechain_config` +* [ ] Update contract subscription + * [ ] Update the contracts logs subscription filter + * [ ] Add method `unsubscribe_contract_logs` in database API +* [ ] Bitcoin key to configure-keys +* [ ] Implement 24 hours delay for deposit and withdrawal processing in Ethereum sidechain + * [ ] sidechain_eth_send_deposit_operation + * [ ] sidechain_eth_send_withdraw_operation + * [ ] sidechain_erc20_send_deposit_operation + * [ ] sidechain_erc20_send_withdraw_operation diff --git a/src/constants/operations-ids.js b/src/constants/operations-ids.js index dcabbe94..a3579a34 100644 --- a/src/constants/operations-ids.js +++ b/src/constants/operations-ids.js @@ -40,21 +40,22 @@ export const CONTRACT_WHITELIST = 38; export const SIDECHAIN_ETH_CREATE_ADDRESS = 39; export const SIDECHAIN_ETH_APPROVE_ADDRESS = 40; export const SIDECHAIN_ETH_DEPOSIT = 41; -export const SIDECHAIN_ETH_WITHDRAW = 42; -export const SIDECHAIN_ETH_APPROVE_WITHDRAW = 43; -export const SIDECHAIN_ISSUE = 44; // VIRTUAL -export const SIDECHAIN_BURN = 45; // VIRTUAL -export const SIDECHAIN_ERC20_REGISTER_TOKEN = 46; -export const SIDECHAIN_ERC20_DEPOSIT_TOKEN = 47; -export const SIDECHAIN_ERC20_WITHDRAW_TOKEN = 48; -export const SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 49; -export const SIDECHAIN_ERC20_ISSUE = 50; // VIRTUAL -export const SIDECHAIN_ERC20_BURN = 51; // VIRTUAL -export const SIDECHAIN_BTC_CREATE_ADDRESS = 52; -export const SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 53; -export const SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 54; -export const SIDECHAIN_BTC_DEPOSIT = 55; -export const SIDECHAIN_BTC_WITHDRAW = 56; -export const SIDECHAIN_BTC_AGGREGATE = 57; -export const SIDECHAIN_BTC_APPROVE_AGGREGATE = 58; -export const BLOCK_REWARD = 59;// VIRTUAL +export const SIDECHAIN_ETH_SEND_DEPOSIT = 42; +export const SIDECHAIN_ETH_WITHDRAW = 43; +export const SIDECHAIN_ETH_APPROVE_WITHDRAW = 44; +export const SIDECHAIN_ISSUE = 45; // VIRTUAL +export const SIDECHAIN_BURN = 46; // VIRTUAL +export const SIDECHAIN_ERC20_REGISTER_TOKEN = 47; +export const SIDECHAIN_ERC20_DEPOSIT_TOKEN = 48; +export const SIDECHAIN_ERC20_WITHDRAW_TOKEN = 49; +export const SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 50; +export const SIDECHAIN_ERC20_ISSUE = 51; // VIRTUAL +export const SIDECHAIN_ERC20_BURN = 52; // VIRTUAL +export const SIDECHAIN_BTC_CREATE_ADDRESS = 53; +export const SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 54; +export const SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 55; +export const SIDECHAIN_BTC_DEPOSIT = 56; +export const SIDECHAIN_BTC_WITHDRAW = 57; +export const SIDECHAIN_BTC_AGGREGATE = 58; +export const SIDECHAIN_BTC_APPROVE_AGGREGATE = 59; +export const BLOCK_REWARD = 60;// VIRTUAL diff --git a/src/serializers/chain/id/protocol.js b/src/serializers/chain/id/protocol.js index 0c94f44a..a6238f1f 100644 --- a/src/serializers/chain/id/protocol.js +++ b/src/serializers/chain/id/protocol.js @@ -19,7 +19,7 @@ export const frozenBalanceId = new ObjectIdSerializer( PROTOCOL_OBJECT_TYPE_ID.FROZEN_BALANCE, ); export const contractId = new ObjectIdSerializer(RESERVED_SPACE_ID.PROTOCOL, PROTOCOL_OBJECT_TYPE_ID.CONTRACT); -export const depositId = new ObjectIdSerializer( +export const ethDepositId = new ObjectIdSerializer( RESERVED_SPACE_ID.PROTOCOL, PROTOCOL_OBJECT_TYPE_ID.SIDECHAIN_ETH_DEPOSIT, ); diff --git a/src/serializers/operation.js b/src/serializers/operation.js index 21334e75..a3016143 100644 --- a/src/serializers/operation.js +++ b/src/serializers/operation.js @@ -44,6 +44,7 @@ const operationProps = { [OPERATIONS_IDS.SIDECHAIN_ETH_CREATE_ADDRESS]: protocol.sidechain.eth.createAddress, [OPERATIONS_IDS.SIDECHAIN_ETH_APPROVE_ADDRESS]: protocol.sidechain.eth.approveAddress, [OPERATIONS_IDS.SIDECHAIN_ETH_DEPOSIT]: protocol.sidechain.eth.deposit, + [OPERATIONS_IDS.SIDECHAIN_ETH_SEND_DEPOSIT]: protocol.sidechain.eth.sendDeposit, [OPERATIONS_IDS.SIDECHAIN_ETH_WITHDRAW]: protocol.sidechain.eth.withdraw, [OPERATIONS_IDS.SIDECHAIN_ETH_APPROVE_WITHDRAW]: protocol.sidechain.eth.approveWithdraw, [OPERATIONS_IDS.CONTRACT_FUND_POOL]: protocol.contract.fundPool, diff --git a/src/serializers/protocol/fee_parameters.js b/src/serializers/protocol/fee_parameters.js index ecf1428d..7c072396 100644 --- a/src/serializers/protocol/fee_parameters.js +++ b/src/serializers/protocol/fee_parameters.js @@ -52,6 +52,7 @@ const feeParametersSerializer = staticVariant({ [OPERATIONS_IDS.SIDECHAIN_ETH_CREATE_ADDRESS]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ETH_APPROVE_ADDRESS]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ETH_DEPOSIT]: defaultFeeParametersSerializer, + [OPERATIONS_IDS.SIDECHAIN_ETH_SEND_DEPOSIT]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ETH_WITHDRAW]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ETH_APPROVE_WITHDRAW]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ISSUE]: defaultFeeParametersSerializer, diff --git a/src/serializers/protocol/sidechain/eth.js b/src/serializers/protocol/sidechain/eth.js index fa70c8c9..cdec1f09 100644 --- a/src/serializers/protocol/sidechain/eth.js +++ b/src/serializers/protocol/sidechain/eth.js @@ -1,7 +1,7 @@ import ethAddress from '../ethAddress'; import { uint64 } from '../../basic/integers'; import { asset, extensions } from '../../chain'; -import { accountId } from '../../chain/id/protocol'; +import { accountId, ethDepositId } from '../../chain/id/protocol'; import { struct, vector } from '../../collections'; export const sidechainEthCreateAddressOperationPropsSerializer = struct({ @@ -28,6 +28,13 @@ export const sidechainEthDepositOperationPropsSerializer = struct({ extensions, }); +export const sidechainEthSendDepositOperationPropsSerializer = struct({ + fee: asset, + committee_member_id: accountId, + deposit_id: ethDepositId, + extensions, +}); + export const sidechainEthWithdrawOperationPropsSerializer = struct({ fee: asset, account: accountId, diff --git a/src/serializers/protocol/sidechain/index.js b/src/serializers/protocol/sidechain/index.js index 442988c0..b2cec45b 100644 --- a/src/serializers/protocol/sidechain/index.js +++ b/src/serializers/protocol/sidechain/index.js @@ -3,13 +3,13 @@ import * as _eth from './eth'; import * as _btc from './btc'; import { struct } from '../../collections'; import { asset, extensions } from '../../chain'; -import { accountId, depositId, withdrawId } from '../../chain/id/protocol'; +import { accountId, ethDepositId, withdrawId } from '../../chain/id/protocol'; export const sidechainIssueOperationPropsSerializer = struct({ fee: asset, value: asset, account: accountId, - deposit_id: depositId, + deposit_id: ethDepositId, extensions, }); @@ -35,6 +35,7 @@ export const eth = { createAddress: _eth.sidechainEthCreateAddressOperationPropsSerializer, approveAddress: _eth.sidechainEthApproveAddressOperationPropsSerializer, deposit: _eth.sidechainEthDepositOperationPropsSerializer, + sendDeposit: _eth.sidechainEthSendDepositOperationPropsSerializer, withdraw: _eth.sidechainEthWithdrawOperationPropsSerializer, approveWithdraw: _eth.sidechainEthApproveWithdrawOperationPropsSerializer, }; diff --git a/types/interfaces/OperationId.d.ts b/types/interfaces/OperationId.d.ts index a5d62ae5..ab93a2e1 100644 --- a/types/interfaces/OperationId.d.ts +++ b/types/interfaces/OperationId.d.ts @@ -42,24 +42,25 @@ declare enum OperationId { SIDECHAIN_ETH_CREATE_ADDRESS = 39, SIDECHAIN_ETH_APPROVE_ADDRESS = 40, SIDECHAIN_ETH_DEPOSIT = 41, - SIDECHAIN_ETH_WITHDRAW = 42, - SIDECHAIN_ETH_APPROVE_WITHDRAW = 43, - SIDECHAIN_ISSUE = 44, // VIRTUAL - SIDECHAIN_BURN = 45, // VIRTUAL - SIDECHAIN_ERC20_REGISTER_TOKEN = 46, - SIDECHAIN_ERC20_DEPOSIT_TOKEN = 47, - SIDECHAIN_ERC20_WITHDRAW_TOKEN = 48, - SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 49, - SIDECHAIN_ERC20_ISSUE = 50, // VIRTUAL - SIDECHAIN_ERC20_BURN = 51, // VIRTUAL - SIDECHAIN_BTC_CREATE_ADDRESS = 52, - SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 53, - SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 54, - SIDECHAIN_BTC_DEPOSIT = 55, - SIDECHAIN_BTC_WITHDRAW = 56, - SIDECHAIN_BTC_AGGREGATE = 57, - SIDECHAIN_BTC_APPROVE_AGGREGATE = 58, - BLOCK_REWARD = 59,// VIRTUAL + SIDECHAIN_ETH_SEND_DEPOSIT = 42, + SIDECHAIN_ETH_WITHDRAW = 43, + SIDECHAIN_ETH_APPROVE_WITHDRAW = 44, + SIDECHAIN_ISSUE = 45, // VIRTUAL + SIDECHAIN_BURN = 46, // VIRTUAL + SIDECHAIN_ERC20_REGISTER_TOKEN = 47, + SIDECHAIN_ERC20_DEPOSIT_TOKEN = 48, + SIDECHAIN_ERC20_WITHDRAW_TOKEN = 49, + SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 50, + SIDECHAIN_ERC20_ISSUE = 51, // VIRTUAL + SIDECHAIN_ERC20_BURN = 52, // VIRTUAL + SIDECHAIN_BTC_CREATE_ADDRESS = 53, + SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 54, + SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 55, + SIDECHAIN_BTC_DEPOSIT = 56, + SIDECHAIN_BTC_WITHDRAW = 57, + SIDECHAIN_BTC_AGGREGATE = 58, + SIDECHAIN_BTC_APPROVE_AGGREGATE = 59, + BLOCK_REWARD = 60,// VIRTUAL } diff --git a/types/serializers/chain/id/protocol.d.ts b/types/serializers/chain/id/protocol.d.ts index 59dc464e..62a69f3e 100644 --- a/types/serializers/chain/id/protocol.d.ts +++ b/types/serializers/chain/id/protocol.d.ts @@ -8,7 +8,7 @@ export declare const proposalId: ObjectIdSerializer; export declare const vestingBalanceId: ObjectIdSerializer; export declare const balanceId: ObjectIdSerializer; export declare const contractId: ObjectIdSerializer; -export declare const depositId: ObjectIdSerializer; +export declare const ethDepositId: ObjectIdSerializer; export declare const withdrawId: ObjectIdSerializer; export declare const erc20TokenId: ObjectIdSerializer; export declare const depositErc20TokenId: ObjectIdSerializer; @@ -17,4 +17,4 @@ export declare const btcAddressId: ObjectIdSerializer; export declare const btcDepositId: ObjectIdSerializer; export declare const btcWithdrawId: ObjectIdSerializer; -export const btcAggregatingId: ObjectIdSerializer; \ No newline at end of file +export const btcAggregatingId: ObjectIdSerializer; diff --git a/types/serializers/operation.d.ts b/types/serializers/operation.d.ts index d7e1773f..29d57354 100644 --- a/types/serializers/operation.d.ts +++ b/types/serializers/operation.d.ts @@ -44,6 +44,7 @@ export type OperationPropsSerializer = { [OperationId.SIDECHAIN_ETH_CREATE_ADDRESS]: typeof protocol.sidechain.eth.createAddress, [OperationId.SIDECHAIN_ETH_APPROVE_ADDRESS]: typeof protocol.sidechain.eth.approveAddress, [OperationId.SIDECHAIN_ETH_DEPOSIT]: typeof protocol.sidechain.eth.deposit, + [OperationId.SIDECHAIN_ETH_SEND_DEPOSIT]: typeof protocol.sidechain.eth.sendDeposit, [OperationId.SIDECHAIN_ETH_WITHDRAW]: typeof protocol.sidechain.eth.withdraw, [OperationId.SIDECHAIN_ETH_APPROVE_WITHDRAW]: typeof protocol.sidechain.eth.approveWithdraw, [OperationId.CONTRACT_FUND_POOL]: typeof protocol.contract.fundPool, diff --git a/types/serializers/protocol/fee_parameters.d.ts b/types/serializers/protocol/fee_parameters.d.ts index 83db79e0..3edfb14c 100644 --- a/types/serializers/protocol/fee_parameters.d.ts +++ b/types/serializers/protocol/fee_parameters.d.ts @@ -62,6 +62,7 @@ export type FeeParametersSerializer = { [OperationId.SIDECHAIN_ETH_CREATE_ADDRESS]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ETH_APPROVE_ADDRESS]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ETH_DEPOSIT]: typeof defaultFeeParametersSerializer, + [OperationId.SIDECHAIN_ETH_SEND_DEPOSIT]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ETH_WITHDRAW]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ETH_APPROVE_WITHDRAW]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ISSUE]: typeof defaultFeeParametersSerializer, diff --git a/types/serializers/protocol/sidechain/eth.d.ts b/types/serializers/protocol/sidechain/eth.d.ts index 4a174e1a..501d7cf6 100644 --- a/types/serializers/protocol/sidechain/eth.d.ts +++ b/types/serializers/protocol/sidechain/eth.d.ts @@ -1,7 +1,7 @@ import ethAddress from "../ethAddress"; import { uint64 } from "../../basic/integers"; import { asset, extensions } from "../../chain"; -import { accountId } from "../../chain/id/protocol"; +import { accountId, ethDepositId } from "../../chain/id/protocol"; import { VectorSerializer, StructSerializer } from "../../collections"; export declare const sidechainEthCreateAddressOperationPropsSerializer: StructSerializer<{ @@ -28,6 +28,13 @@ export declare const sidechainEthDepositOperationPropsSerializer: StructSerializ extensions: typeof extensions, }>; +export const sidechainEthSendDepositOperationPropsSerializer: StructSerializer<{ + fee: typeof asset, + committee_member_id: typeof accountId, + deposit_id: typeof ethDepositId, + extensions: typeof extensions, +}>; + export declare const sidechainEthWithdrawOperationPropsSerializer: StructSerializer<{ fee: typeof asset, account: typeof accountId, diff --git a/types/serializers/protocol/sidechain/index.d.ts b/types/serializers/protocol/sidechain/index.d.ts index 678c3103..369e472b 100644 --- a/types/serializers/protocol/sidechain/index.d.ts +++ b/types/serializers/protocol/sidechain/index.d.ts @@ -2,14 +2,14 @@ import * as _erc20 from './erc20'; import * as _eth from './eth'; import * as _btc from './btc'; import { asset, extensions } from '../../chain'; -import { accountId, depositId, withdrawId } from '../../chain/id/protocol'; +import { accountId, ethDepositId, withdrawId } from '../../chain/id/protocol'; import { StructSerializer } from '../../collections'; export declare const sidechainIssueOperationPropsSerializer: StructSerializer<{ fee: typeof asset, value: typeof asset, account: typeof accountId, - deposit_id: typeof depositId, + deposit_id: typeof ethDepositId, extensions: typeof extensions, }>; @@ -34,6 +34,7 @@ export declare const eth: { createAddress: typeof _eth.sidechainEthCreateAddressOperationPropsSerializer, approveAddress: typeof _eth.sidechainEthApproveAddressOperationPropsSerializer, deposit: typeof _eth.sidechainEthDepositOperationPropsSerializer, + sendDeposit: typeof _eth.sidechainEthSendDepositOperationPropsSerializer, withdraw: typeof _eth.sidechainEthWithdrawOperationPropsSerializer, approveWithdraw: typeof _eth.sidechainEthApproveWithdrawOperationPropsSerializer, }; From 08882aa0ca5406e877cd04a385b86ab20bfbfdd4 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 9 Dec 2019 16:52:40 +0300 Subject: [PATCH 05/62] [ECHOJS-245] Add `sidechain_eth_send_withdraw_operation` --- docs/Serializers.md | 2 +- echo@0.14.0-rc.1-migration.md | 8 ++--- src/constants/operations-ids.js | 35 ++++++++++--------- src/serializers/chain/id/protocol.js | 2 +- src/serializers/operation.js | 1 + src/serializers/protocol/fee_parameters.js | 1 + src/serializers/protocol/sidechain/eth.js | 9 ++++- src/serializers/protocol/sidechain/index.js | 5 +-- types/interfaces/OperationId.d.ts | 35 ++++++++++--------- types/serializers/chain/id/protocol.d.ts | 2 +- types/serializers/operation.d.ts | 1 + .../serializers/protocol/fee_parameters.d.ts | 1 + types/serializers/protocol/sidechain/eth.d.ts | 9 ++++- .../serializers/protocol/sidechain/index.d.ts | 5 +-- 14 files changed, 69 insertions(+), 47 deletions(-) diff --git a/docs/Serializers.md b/docs/Serializers.md index 4efd5be8..a7220a16 100644 --- a/docs/Serializers.md +++ b/docs/Serializers.md @@ -332,7 +332,7 @@ Available protocol object id serializers: * `balanceId` * `contractId` * `ethDepositId` -* `withdrawId` +* `ethWithdrawId` * `erc20TokenId` Example: diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index 1d15ee6e..dec3d147 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -5,7 +5,7 @@ * [ ] Add method `unsubscribe_contract_logs` in database API * [ ] Bitcoin key to configure-keys * [ ] Implement 24 hours delay for deposit and withdrawal processing in Ethereum sidechain - * [ ] sidechain_eth_send_deposit_operation - * [ ] sidechain_eth_send_withdraw_operation - * [ ] sidechain_erc20_send_deposit_operation - * [ ] sidechain_erc20_send_withdraw_operation + * [x] `sidechain_eth_send_deposit_operation` + * [x] `sidechain_eth_send_withdraw_operation` + * [ ] `sidechain_erc20_send_deposit_operation` + * [ ] `sidechain_erc20_send_withdraw_operation` diff --git a/src/constants/operations-ids.js b/src/constants/operations-ids.js index a3579a34..29c0ddc6 100644 --- a/src/constants/operations-ids.js +++ b/src/constants/operations-ids.js @@ -42,20 +42,21 @@ export const SIDECHAIN_ETH_APPROVE_ADDRESS = 40; export const SIDECHAIN_ETH_DEPOSIT = 41; export const SIDECHAIN_ETH_SEND_DEPOSIT = 42; export const SIDECHAIN_ETH_WITHDRAW = 43; -export const SIDECHAIN_ETH_APPROVE_WITHDRAW = 44; -export const SIDECHAIN_ISSUE = 45; // VIRTUAL -export const SIDECHAIN_BURN = 46; // VIRTUAL -export const SIDECHAIN_ERC20_REGISTER_TOKEN = 47; -export const SIDECHAIN_ERC20_DEPOSIT_TOKEN = 48; -export const SIDECHAIN_ERC20_WITHDRAW_TOKEN = 49; -export const SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 50; -export const SIDECHAIN_ERC20_ISSUE = 51; // VIRTUAL -export const SIDECHAIN_ERC20_BURN = 52; // VIRTUAL -export const SIDECHAIN_BTC_CREATE_ADDRESS = 53; -export const SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 54; -export const SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 55; -export const SIDECHAIN_BTC_DEPOSIT = 56; -export const SIDECHAIN_BTC_WITHDRAW = 57; -export const SIDECHAIN_BTC_AGGREGATE = 58; -export const SIDECHAIN_BTC_APPROVE_AGGREGATE = 59; -export const BLOCK_REWARD = 60;// VIRTUAL +export const SIDECHAIN_ETH_SEND_WITHDRAW = 44; +export const SIDECHAIN_ETH_APPROVE_WITHDRAW = 45; +export const SIDECHAIN_ISSUE = 46; // VIRTUAL +export const SIDECHAIN_BURN = 47; // VIRTUAL +export const SIDECHAIN_ERC20_REGISTER_TOKEN = 48; +export const SIDECHAIN_ERC20_DEPOSIT_TOKEN = 49; +export const SIDECHAIN_ERC20_WITHDRAW_TOKEN = 50; +export const SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 51; +export const SIDECHAIN_ERC20_ISSUE = 52; // VIRTUAL +export const SIDECHAIN_ERC20_BURN = 53; // VIRTUAL +export const SIDECHAIN_BTC_CREATE_ADDRESS = 54; +export const SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 55; +export const SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 56; +export const SIDECHAIN_BTC_DEPOSIT = 57; +export const SIDECHAIN_BTC_WITHDRAW = 58; +export const SIDECHAIN_BTC_AGGREGATE = 59; +export const SIDECHAIN_BTC_APPROVE_AGGREGATE = 60; +export const BLOCK_REWARD = 61;// VIRTUAL diff --git a/src/serializers/chain/id/protocol.js b/src/serializers/chain/id/protocol.js index a6238f1f..69fe9d49 100644 --- a/src/serializers/chain/id/protocol.js +++ b/src/serializers/chain/id/protocol.js @@ -23,7 +23,7 @@ export const ethDepositId = new ObjectIdSerializer( RESERVED_SPACE_ID.PROTOCOL, PROTOCOL_OBJECT_TYPE_ID.SIDECHAIN_ETH_DEPOSIT, ); -export const withdrawId = new ObjectIdSerializer( +export const ethWithdrawId = new ObjectIdSerializer( RESERVED_SPACE_ID.PROTOCOL, PROTOCOL_OBJECT_TYPE_ID.SIDECHAIN_ETH_WITHDRAW, ); diff --git a/src/serializers/operation.js b/src/serializers/operation.js index a3016143..6691209e 100644 --- a/src/serializers/operation.js +++ b/src/serializers/operation.js @@ -46,6 +46,7 @@ const operationProps = { [OPERATIONS_IDS.SIDECHAIN_ETH_DEPOSIT]: protocol.sidechain.eth.deposit, [OPERATIONS_IDS.SIDECHAIN_ETH_SEND_DEPOSIT]: protocol.sidechain.eth.sendDeposit, [OPERATIONS_IDS.SIDECHAIN_ETH_WITHDRAW]: protocol.sidechain.eth.withdraw, + [OPERATIONS_IDS.SIDECHAIN_ETH_SEND_WITHDRAW]: protocol.sidechain.eth.sendWithdraw, [OPERATIONS_IDS.SIDECHAIN_ETH_APPROVE_WITHDRAW]: protocol.sidechain.eth.approveWithdraw, [OPERATIONS_IDS.CONTRACT_FUND_POOL]: protocol.contract.fundPool, [OPERATIONS_IDS.CONTRACT_WHITELIST]: protocol.contract.whitelist, diff --git a/src/serializers/protocol/fee_parameters.js b/src/serializers/protocol/fee_parameters.js index 7c072396..5c80a6cf 100644 --- a/src/serializers/protocol/fee_parameters.js +++ b/src/serializers/protocol/fee_parameters.js @@ -54,6 +54,7 @@ const feeParametersSerializer = staticVariant({ [OPERATIONS_IDS.SIDECHAIN_ETH_DEPOSIT]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ETH_SEND_DEPOSIT]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ETH_WITHDRAW]: defaultFeeParametersSerializer, + [OPERATIONS_IDS.SIDECHAIN_ETH_SEND_WITHDRAW]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ETH_APPROVE_WITHDRAW]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ISSUE]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_BURN]: defaultFeeParametersSerializer, diff --git a/src/serializers/protocol/sidechain/eth.js b/src/serializers/protocol/sidechain/eth.js index cdec1f09..eec754cc 100644 --- a/src/serializers/protocol/sidechain/eth.js +++ b/src/serializers/protocol/sidechain/eth.js @@ -1,7 +1,7 @@ import ethAddress from '../ethAddress'; import { uint64 } from '../../basic/integers'; import { asset, extensions } from '../../chain'; -import { accountId, ethDepositId } from '../../chain/id/protocol'; +import { accountId, ethDepositId, ethWithdrawId } from '../../chain/id/protocol'; import { struct, vector } from '../../collections'; export const sidechainEthCreateAddressOperationPropsSerializer = struct({ @@ -43,6 +43,13 @@ export const sidechainEthWithdrawOperationPropsSerializer = struct({ extensions, }); +export const sidechainEthSendWithdrawOperationPropsSerializer = struct({ + fee: asset, + committee_member_id: accountId, + withdraw_id: ethWithdrawId, + extensions, +}); + export const sidechainEthApproveWithdrawOperationPropsSerializer = struct({ fee: asset, committee_member_id: accountId, diff --git a/src/serializers/protocol/sidechain/index.js b/src/serializers/protocol/sidechain/index.js index b2cec45b..92fcfe9b 100644 --- a/src/serializers/protocol/sidechain/index.js +++ b/src/serializers/protocol/sidechain/index.js @@ -3,7 +3,7 @@ import * as _eth from './eth'; import * as _btc from './btc'; import { struct } from '../../collections'; import { asset, extensions } from '../../chain'; -import { accountId, ethDepositId, withdrawId } from '../../chain/id/protocol'; +import { accountId, ethDepositId, ethWithdrawId } from '../../chain/id/protocol'; export const sidechainIssueOperationPropsSerializer = struct({ fee: asset, @@ -18,7 +18,7 @@ export const sidechainBurnOperationPropsSerializer = struct({ fee: asset, value: asset, account: accountId, - withdraw_id: withdrawId, + withdraw_id: ethWithdrawId, extensions, }); @@ -37,6 +37,7 @@ export const eth = { deposit: _eth.sidechainEthDepositOperationPropsSerializer, sendDeposit: _eth.sidechainEthSendDepositOperationPropsSerializer, withdraw: _eth.sidechainEthWithdrawOperationPropsSerializer, + sendWithdraw: _eth.sidechainEthSendWithdrawOperationPropsSerializer, approveWithdraw: _eth.sidechainEthApproveWithdrawOperationPropsSerializer, }; diff --git a/types/interfaces/OperationId.d.ts b/types/interfaces/OperationId.d.ts index ab93a2e1..649ea631 100644 --- a/types/interfaces/OperationId.d.ts +++ b/types/interfaces/OperationId.d.ts @@ -44,23 +44,24 @@ declare enum OperationId { SIDECHAIN_ETH_DEPOSIT = 41, SIDECHAIN_ETH_SEND_DEPOSIT = 42, SIDECHAIN_ETH_WITHDRAW = 43, - SIDECHAIN_ETH_APPROVE_WITHDRAW = 44, - SIDECHAIN_ISSUE = 45, // VIRTUAL - SIDECHAIN_BURN = 46, // VIRTUAL - SIDECHAIN_ERC20_REGISTER_TOKEN = 47, - SIDECHAIN_ERC20_DEPOSIT_TOKEN = 48, - SIDECHAIN_ERC20_WITHDRAW_TOKEN = 49, - SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 50, - SIDECHAIN_ERC20_ISSUE = 51, // VIRTUAL - SIDECHAIN_ERC20_BURN = 52, // VIRTUAL - SIDECHAIN_BTC_CREATE_ADDRESS = 53, - SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 54, - SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 55, - SIDECHAIN_BTC_DEPOSIT = 56, - SIDECHAIN_BTC_WITHDRAW = 57, - SIDECHAIN_BTC_AGGREGATE = 58, - SIDECHAIN_BTC_APPROVE_AGGREGATE = 59, - BLOCK_REWARD = 60,// VIRTUAL + SIDECHAIN_ETH_SEND_WITHDRAW = 44, + SIDECHAIN_ETH_APPROVE_WITHDRAW = 45, + SIDECHAIN_ISSUE = 46, // VIRTUAL + SIDECHAIN_BURN = 47, // VIRTUAL + SIDECHAIN_ERC20_REGISTER_TOKEN = 48, + SIDECHAIN_ERC20_DEPOSIT_TOKEN = 49, + SIDECHAIN_ERC20_WITHDRAW_TOKEN = 50, + SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 51, + SIDECHAIN_ERC20_ISSUE = 52, // VIRTUAL + SIDECHAIN_ERC20_BURN = 53, // VIRTUAL + SIDECHAIN_BTC_CREATE_ADDRESS = 54, + SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 55, + SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 56, + SIDECHAIN_BTC_DEPOSIT = 57, + SIDECHAIN_BTC_WITHDRAW = 58, + SIDECHAIN_BTC_AGGREGATE = 59, + SIDECHAIN_BTC_APPROVE_AGGREGATE = 60, + BLOCK_REWARD = 61, // VIRTUAL } diff --git a/types/serializers/chain/id/protocol.d.ts b/types/serializers/chain/id/protocol.d.ts index 62a69f3e..ac5cb690 100644 --- a/types/serializers/chain/id/protocol.d.ts +++ b/types/serializers/chain/id/protocol.d.ts @@ -9,7 +9,7 @@ export declare const vestingBalanceId: ObjectIdSerializer; export declare const contractId: ObjectIdSerializer; export declare const ethDepositId: ObjectIdSerializer; -export declare const withdrawId: ObjectIdSerializer; +export declare const ethWithdrawId: ObjectIdSerializer; export declare const erc20TokenId: ObjectIdSerializer; export declare const depositErc20TokenId: ObjectIdSerializer; export declare const withdrawErc20TokenId: ObjectIdSerializer; diff --git a/types/serializers/operation.d.ts b/types/serializers/operation.d.ts index 29d57354..0b371178 100644 --- a/types/serializers/operation.d.ts +++ b/types/serializers/operation.d.ts @@ -46,6 +46,7 @@ export type OperationPropsSerializer = { [OperationId.SIDECHAIN_ETH_DEPOSIT]: typeof protocol.sidechain.eth.deposit, [OperationId.SIDECHAIN_ETH_SEND_DEPOSIT]: typeof protocol.sidechain.eth.sendDeposit, [OperationId.SIDECHAIN_ETH_WITHDRAW]: typeof protocol.sidechain.eth.withdraw, + [OperationId.SIDECHAIN_ETH_SEND_WITHDRAW]: typeof protocol.sidechain.eth.sendWithdraw, [OperationId.SIDECHAIN_ETH_APPROVE_WITHDRAW]: typeof protocol.sidechain.eth.approveWithdraw, [OperationId.CONTRACT_FUND_POOL]: typeof protocol.contract.fundPool, [OperationId.CONTRACT_WHITELIST]: typeof protocol.contract.whitelist, diff --git a/types/serializers/protocol/fee_parameters.d.ts b/types/serializers/protocol/fee_parameters.d.ts index 3edfb14c..9843378b 100644 --- a/types/serializers/protocol/fee_parameters.d.ts +++ b/types/serializers/protocol/fee_parameters.d.ts @@ -64,6 +64,7 @@ export type FeeParametersSerializer = { [OperationId.SIDECHAIN_ETH_DEPOSIT]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ETH_SEND_DEPOSIT]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ETH_WITHDRAW]: typeof defaultFeeParametersSerializer, + [OperationId.SIDECHAIN_ETH_SEND_WITHDRAW]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ETH_APPROVE_WITHDRAW]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ISSUE]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_BURN]: typeof defaultFeeParametersSerializer, diff --git a/types/serializers/protocol/sidechain/eth.d.ts b/types/serializers/protocol/sidechain/eth.d.ts index 501d7cf6..dbf0492e 100644 --- a/types/serializers/protocol/sidechain/eth.d.ts +++ b/types/serializers/protocol/sidechain/eth.d.ts @@ -1,7 +1,7 @@ import ethAddress from "../ethAddress"; import { uint64 } from "../../basic/integers"; import { asset, extensions } from "../../chain"; -import { accountId, ethDepositId } from "../../chain/id/protocol"; +import { accountId, ethDepositId, ethWithdrawId } from "../../chain/id/protocol"; import { VectorSerializer, StructSerializer } from "../../collections"; export declare const sidechainEthCreateAddressOperationPropsSerializer: StructSerializer<{ @@ -43,6 +43,13 @@ export declare const sidechainEthWithdrawOperationPropsSerializer: StructSeriali extensions: typeof extensions, }>; +export const sidechainEthSendWithdrawOperationPropsSerializer: StructSerializer<{ + fee: typeof asset, + committee_member_id: typeof accountId, + withdraw_id: typeof ethWithdrawId, + extensions: typeof extensions, +}>; + export declare const sidechainEthApproveWithdrawOperationPropsSerializer: StructSerializer<{ fee: typeof asset, committee_member_id: typeof accountId, diff --git a/types/serializers/protocol/sidechain/index.d.ts b/types/serializers/protocol/sidechain/index.d.ts index 369e472b..cd83fe25 100644 --- a/types/serializers/protocol/sidechain/index.d.ts +++ b/types/serializers/protocol/sidechain/index.d.ts @@ -2,7 +2,7 @@ import * as _erc20 from './erc20'; import * as _eth from './eth'; import * as _btc from './btc'; import { asset, extensions } from '../../chain'; -import { accountId, ethDepositId, withdrawId } from '../../chain/id/protocol'; +import { accountId, ethDepositId, ethWithdrawId } from '../../chain/id/protocol'; import { StructSerializer } from '../../collections'; export declare const sidechainIssueOperationPropsSerializer: StructSerializer<{ @@ -17,7 +17,7 @@ export declare const sidechainBurnOperationPropsSerializer: StructSerializer<{ fee: typeof asset, value: typeof asset, account: typeof accountId, - withdraw_id: typeof withdrawId, + withdraw_id: typeof ethWithdrawId, extensions: typeof extensions, }>; @@ -36,6 +36,7 @@ export declare const eth: { deposit: typeof _eth.sidechainEthDepositOperationPropsSerializer, sendDeposit: typeof _eth.sidechainEthSendDepositOperationPropsSerializer, withdraw: typeof _eth.sidechainEthWithdrawOperationPropsSerializer, + sendWithdraw: typeof _eth.sidechainEthSendWithdrawOperationPropsSerializer, approveWithdraw: typeof _eth.sidechainEthApproveWithdrawOperationPropsSerializer, }; From 67b13c8557670003e7ff69f35e7058b8ac35132d Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 9 Dec 2019 17:01:25 +0300 Subject: [PATCH 06/62] [ECHOJS-245] Add `sidechain_erc20_send_deposit_operation` --- echo@0.14.0-rc.1-migration.md | 2 +- src/constants/operations-ids.js | 25 ++++++++--------- src/serializers/operation.js | 1 + src/serializers/protocol/fee_parameters.js | 1 + src/serializers/protocol/sidechain/erc20.js | 7 +++++ src/serializers/protocol/sidechain/index.js | 1 + types/interfaces/OperationId.d.ts | 27 +++++++++---------- types/serializers/operation.d.ts | 1 + .../serializers/protocol/fee_parameters.d.ts | 1 + .../serializers/protocol/sidechain/erc20.d.ts | 7 +++++ .../serializers/protocol/sidechain/index.d.ts | 1 + 11 files changed, 47 insertions(+), 27 deletions(-) diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index dec3d147..d8b983fb 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -7,5 +7,5 @@ * [ ] Implement 24 hours delay for deposit and withdrawal processing in Ethereum sidechain * [x] `sidechain_eth_send_deposit_operation` * [x] `sidechain_eth_send_withdraw_operation` - * [ ] `sidechain_erc20_send_deposit_operation` + * [x] `sidechain_erc20_send_deposit_operation` * [ ] `sidechain_erc20_send_withdraw_operation` diff --git a/src/constants/operations-ids.js b/src/constants/operations-ids.js index 29c0ddc6..7e646c34 100644 --- a/src/constants/operations-ids.js +++ b/src/constants/operations-ids.js @@ -48,15 +48,16 @@ export const SIDECHAIN_ISSUE = 46; // VIRTUAL export const SIDECHAIN_BURN = 47; // VIRTUAL export const SIDECHAIN_ERC20_REGISTER_TOKEN = 48; export const SIDECHAIN_ERC20_DEPOSIT_TOKEN = 49; -export const SIDECHAIN_ERC20_WITHDRAW_TOKEN = 50; -export const SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 51; -export const SIDECHAIN_ERC20_ISSUE = 52; // VIRTUAL -export const SIDECHAIN_ERC20_BURN = 53; // VIRTUAL -export const SIDECHAIN_BTC_CREATE_ADDRESS = 54; -export const SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 55; -export const SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 56; -export const SIDECHAIN_BTC_DEPOSIT = 57; -export const SIDECHAIN_BTC_WITHDRAW = 58; -export const SIDECHAIN_BTC_AGGREGATE = 59; -export const SIDECHAIN_BTC_APPROVE_AGGREGATE = 60; -export const BLOCK_REWARD = 61;// VIRTUAL +export const SIDECHAIN_ERC20_SEND_DEPOSIT = 50; +export const SIDECHAIN_ERC20_WITHDRAW_TOKEN = 51; +export const SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 52; +export const SIDECHAIN_ERC20_ISSUE = 53; // VIRTUAL +export const SIDECHAIN_ERC20_BURN = 54; // VIRTUAL +export const SIDECHAIN_BTC_CREATE_ADDRESS = 55; +export const SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 56; +export const SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 57; +export const SIDECHAIN_BTC_DEPOSIT = 58; +export const SIDECHAIN_BTC_WITHDRAW = 59; +export const SIDECHAIN_BTC_AGGREGATE = 60; +export const SIDECHAIN_BTC_APPROVE_AGGREGATE = 61; +export const BLOCK_REWARD = 62; // VIRTUAL diff --git a/src/serializers/operation.js b/src/serializers/operation.js index 6691209e..1eeb4e36 100644 --- a/src/serializers/operation.js +++ b/src/serializers/operation.js @@ -54,6 +54,7 @@ const operationProps = { [OPERATIONS_IDS.SIDECHAIN_BURN]: protocol.sidechain.burn, [OPERATIONS_IDS.SIDECHAIN_ERC20_REGISTER_TOKEN]: protocol.sidechain.erc20.registerToken, [OPERATIONS_IDS.SIDECHAIN_ERC20_DEPOSIT_TOKEN]: protocol.sidechain.erc20.depositToken, + [OPERATIONS_IDS.SIDECHAIN_ERC20_SEND_DEPOSIT]: protocol.sidechain.erc20.sendDeposit, [OPERATIONS_IDS.SIDECHAIN_ERC20_WITHDRAW_TOKEN]: protocol.sidechain.erc20.withdrawToken, [OPERATIONS_IDS.SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW]: protocol.sidechain.erc20.approveTokenWithdraw, [OPERATIONS_IDS.SIDECHAIN_ERC20_ISSUE]: protocol.sidechain.erc20.issue, diff --git a/src/serializers/protocol/fee_parameters.js b/src/serializers/protocol/fee_parameters.js index 5c80a6cf..9113ad3c 100644 --- a/src/serializers/protocol/fee_parameters.js +++ b/src/serializers/protocol/fee_parameters.js @@ -60,6 +60,7 @@ const feeParametersSerializer = staticVariant({ [OPERATIONS_IDS.SIDECHAIN_BURN]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ERC20_REGISTER_TOKEN]: struct({ fee: uint64, pool_fee: uint64 }), [OPERATIONS_IDS.SIDECHAIN_ERC20_DEPOSIT_TOKEN]: defaultFeeParametersSerializer, + [OPERATIONS_IDS.SIDECHAIN_ERC20_SEND_DEPOSIT]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ERC20_WITHDRAW_TOKEN]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ERC20_ISSUE]: defaultFeeParametersSerializer, diff --git a/src/serializers/protocol/sidechain/erc20.js b/src/serializers/protocol/sidechain/erc20.js index 7d87d395..38f09183 100644 --- a/src/serializers/protocol/sidechain/erc20.js +++ b/src/serializers/protocol/sidechain/erc20.js @@ -26,6 +26,13 @@ export const sidechainERC20DepositTokenOperationPropsSerializer = struct({ extensions, }); +export const sidechainERC20SendDepositOperationPropsSerializer = struct({ + fee: asset, + committee_member_id: accountId, + deposit_id: depositErc20TokenId, + extensions, +}); + export const sidechainERC20WithdrawTokenOperationPropsSerializer = struct({ fee: asset, account: accountId, diff --git a/src/serializers/protocol/sidechain/index.js b/src/serializers/protocol/sidechain/index.js index 92fcfe9b..7a9a0fae 100644 --- a/src/serializers/protocol/sidechain/index.js +++ b/src/serializers/protocol/sidechain/index.js @@ -25,6 +25,7 @@ export const sidechainBurnOperationPropsSerializer = struct({ export const erc20 = { registerToken: _erc20.sidechainERC20RegisterTokenOperationPropsSerializer, depositToken: _erc20.sidechainERC20DepositTokenOperationPropsSerializer, + sendDeposit: _erc20.sidechainERC20SendDepositOperationPropsSerializer, withdrawToken: _erc20.sidechainERC20WithdrawTokenOperationPropsSerializer, approveTokenWithdraw: _erc20.sidechainERC20ApproveTokenWithdrawOperationPropsSerializer, issue: _erc20.sidechainERC20IssueOperationPropsSerializer, diff --git a/types/interfaces/OperationId.d.ts b/types/interfaces/OperationId.d.ts index 649ea631..8992039d 100644 --- a/types/interfaces/OperationId.d.ts +++ b/types/interfaces/OperationId.d.ts @@ -50,18 +50,17 @@ declare enum OperationId { SIDECHAIN_BURN = 47, // VIRTUAL SIDECHAIN_ERC20_REGISTER_TOKEN = 48, SIDECHAIN_ERC20_DEPOSIT_TOKEN = 49, - SIDECHAIN_ERC20_WITHDRAW_TOKEN = 50, - SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 51, - SIDECHAIN_ERC20_ISSUE = 52, // VIRTUAL - SIDECHAIN_ERC20_BURN = 53, // VIRTUAL - SIDECHAIN_BTC_CREATE_ADDRESS = 54, - SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 55, - SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 56, - SIDECHAIN_BTC_DEPOSIT = 57, - SIDECHAIN_BTC_WITHDRAW = 58, - SIDECHAIN_BTC_AGGREGATE = 59, - SIDECHAIN_BTC_APPROVE_AGGREGATE = 60, - BLOCK_REWARD = 61, // VIRTUAL + SIDECHAIN_ERC20_SEND_DEPOSIT = 50, + SIDECHAIN_ERC20_WITHDRAW_TOKEN = 51, + SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 52, + SIDECHAIN_ERC20_ISSUE = 53, // VIRTUAL + SIDECHAIN_ERC20_BURN = 54, // VIRTUAL + SIDECHAIN_BTC_CREATE_ADDRESS = 55, + SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 56, + SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 57, + SIDECHAIN_BTC_DEPOSIT = 58, + SIDECHAIN_BTC_WITHDRAW = 59, + SIDECHAIN_BTC_AGGREGATE = 60, + SIDECHAIN_BTC_APPROVE_AGGREGATE = 61, + BLOCK_REWARD = 62, // VIRTUAL } - - diff --git a/types/serializers/operation.d.ts b/types/serializers/operation.d.ts index 0b371178..3fa215f6 100644 --- a/types/serializers/operation.d.ts +++ b/types/serializers/operation.d.ts @@ -54,6 +54,7 @@ export type OperationPropsSerializer = { [OperationId.SIDECHAIN_BURN]: typeof protocol.sidechain.burn, [OperationId.SIDECHAIN_ERC20_REGISTER_TOKEN]: typeof protocol.sidechain.erc20.registerToken, [OperationId.SIDECHAIN_ERC20_DEPOSIT_TOKEN]: typeof protocol.sidechain.erc20.depositToken, + [OperationId.SIDECHAIN_ERC20_SEND_DEPOSIT]: typeof protocol.sidechain.erc20.sendDeposit, [OperationId.SIDECHAIN_ERC20_WITHDRAW_TOKEN]: typeof protocol.sidechain.erc20.withdrawToken, [OperationId.SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW]: typeof protocol.sidechain.erc20.approveTokenWithdraw, [OperationId.SIDECHAIN_ERC20_ISSUE]: typeof protocol.sidechain.erc20.issue, diff --git a/types/serializers/protocol/fee_parameters.d.ts b/types/serializers/protocol/fee_parameters.d.ts index 9843378b..a68b6a25 100644 --- a/types/serializers/protocol/fee_parameters.d.ts +++ b/types/serializers/protocol/fee_parameters.d.ts @@ -70,6 +70,7 @@ export type FeeParametersSerializer = { [OperationId.SIDECHAIN_BURN]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ERC20_REGISTER_TOKEN]: StructSerializer<{ fee: typeof uint64, pool_fee: typeof uint64 }>, [OperationId.SIDECHAIN_ERC20_DEPOSIT_TOKEN]: typeof defaultFeeParametersSerializer, + [OperationId.SIDECHAIN_ERC20_SEND_DEPOSIT]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ERC20_WITHDRAW_TOKEN]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ERC20_ISSUE]: typeof defaultFeeParametersSerializer, diff --git a/types/serializers/protocol/sidechain/erc20.d.ts b/types/serializers/protocol/sidechain/erc20.d.ts index cf1585a9..b0791e8b 100644 --- a/types/serializers/protocol/sidechain/erc20.d.ts +++ b/types/serializers/protocol/sidechain/erc20.d.ts @@ -26,6 +26,13 @@ export declare const sidechainERC20DepositTokenOperationPropsSerializer: StructS extensions: typeof extensions, }>; +export const sidechainERC20SendDepositOperationPropsSerializer: StructSerializer<{ + fee: typeof asset, + committee_member_id: typeof accountId, + deposit_id: typeof depositErc20TokenId, + extensions: typeof extensions, +}>; + export declare const sidechainERC20WithdrawTokenOperationPropsSerializer: StructSerializer<{ fee: typeof asset, account: typeof accountId, diff --git a/types/serializers/protocol/sidechain/index.d.ts b/types/serializers/protocol/sidechain/index.d.ts index cd83fe25..23719e37 100644 --- a/types/serializers/protocol/sidechain/index.d.ts +++ b/types/serializers/protocol/sidechain/index.d.ts @@ -24,6 +24,7 @@ export declare const sidechainBurnOperationPropsSerializer: StructSerializer<{ export declare const erc20: { registerToken: typeof _erc20.sidechainERC20RegisterTokenOperationPropsSerializer, depositToken: typeof _erc20.sidechainERC20DepositTokenOperationPropsSerializer, + sendDeposit: typeof _erc20.sidechainERC20SendDepositOperationPropsSerializer, withdrawToken: typeof _erc20.sidechainERC20WithdrawTokenOperationPropsSerializer, approveTokenWithdraw: typeof _erc20.sidechainERC20ApproveTokenWithdrawOperationPropsSerializer, issue: typeof _erc20.sidechainERC20IssueOperationPropsSerializer, From 9e4073346632eb3ac9bc4a87fc8b07766963e83c Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 9 Dec 2019 17:10:12 +0300 Subject: [PATCH 07/62] [ECHOJS-245] Add `sidechain_erc20_send_withdraw_operation` --- echo@0.14.0-rc.1-migration.md | 6 +++-- src/constants/operations-ids.js | 23 ++++++++++--------- src/serializers/operation.js | 1 + src/serializers/protocol/fee_parameters.js | 1 + src/serializers/protocol/sidechain/erc20.js | 7 ++++++ src/serializers/protocol/sidechain/index.js | 1 + types/interfaces/OperationId.d.ts | 23 ++++++++++--------- types/serializers/operation.d.ts | 1 + .../serializers/protocol/fee_parameters.d.ts | 1 + .../serializers/protocol/sidechain/erc20.d.ts | 7 ++++++ .../serializers/protocol/sidechain/index.d.ts | 1 + 11 files changed, 48 insertions(+), 24 deletions(-) diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index d8b983fb..ad0a7cc3 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -4,8 +4,10 @@ * [ ] Update the contracts logs subscription filter * [ ] Add method `unsubscribe_contract_logs` in database API * [ ] Bitcoin key to configure-keys -* [ ] Implement 24 hours delay for deposit and withdrawal processing in Ethereum sidechain +* [x] Implement 24 hours delay for deposit and withdrawal processing in Ethereum sidechain * [x] `sidechain_eth_send_deposit_operation` * [x] `sidechain_eth_send_withdraw_operation` * [x] `sidechain_erc20_send_deposit_operation` - * [ ] `sidechain_erc20_send_withdraw_operation` + * [x] `sidechain_erc20_send_withdraw_operation` + +* [ ] Update operations' id's in docs diff --git a/src/constants/operations-ids.js b/src/constants/operations-ids.js index 7e646c34..3acfa890 100644 --- a/src/constants/operations-ids.js +++ b/src/constants/operations-ids.js @@ -50,14 +50,15 @@ export const SIDECHAIN_ERC20_REGISTER_TOKEN = 48; export const SIDECHAIN_ERC20_DEPOSIT_TOKEN = 49; export const SIDECHAIN_ERC20_SEND_DEPOSIT = 50; export const SIDECHAIN_ERC20_WITHDRAW_TOKEN = 51; -export const SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 52; -export const SIDECHAIN_ERC20_ISSUE = 53; // VIRTUAL -export const SIDECHAIN_ERC20_BURN = 54; // VIRTUAL -export const SIDECHAIN_BTC_CREATE_ADDRESS = 55; -export const SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 56; -export const SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 57; -export const SIDECHAIN_BTC_DEPOSIT = 58; -export const SIDECHAIN_BTC_WITHDRAW = 59; -export const SIDECHAIN_BTC_AGGREGATE = 60; -export const SIDECHAIN_BTC_APPROVE_AGGREGATE = 61; -export const BLOCK_REWARD = 62; // VIRTUAL +export const SIDECHAIN_ERC20_SEND_WITHDRAW = 52; +export const SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 53; +export const SIDECHAIN_ERC20_ISSUE = 54; // VIRTUAL +export const SIDECHAIN_ERC20_BURN = 55; // VIRTUAL +export const SIDECHAIN_BTC_CREATE_ADDRESS = 56; +export const SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 57; +export const SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 58; +export const SIDECHAIN_BTC_DEPOSIT = 59; +export const SIDECHAIN_BTC_WITHDRAW = 60; +export const SIDECHAIN_BTC_AGGREGATE = 61; +export const SIDECHAIN_BTC_APPROVE_AGGREGATE = 62; +export const BLOCK_REWARD = 63; // VIRTUAL diff --git a/src/serializers/operation.js b/src/serializers/operation.js index 1eeb4e36..400b88ff 100644 --- a/src/serializers/operation.js +++ b/src/serializers/operation.js @@ -56,6 +56,7 @@ const operationProps = { [OPERATIONS_IDS.SIDECHAIN_ERC20_DEPOSIT_TOKEN]: protocol.sidechain.erc20.depositToken, [OPERATIONS_IDS.SIDECHAIN_ERC20_SEND_DEPOSIT]: protocol.sidechain.erc20.sendDeposit, [OPERATIONS_IDS.SIDECHAIN_ERC20_WITHDRAW_TOKEN]: protocol.sidechain.erc20.withdrawToken, + [OPERATIONS_IDS.SIDECHAIN_ERC20_SEND_WITHDRAW]: protocol.sidechain.erc20.sendWithdraw, [OPERATIONS_IDS.SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW]: protocol.sidechain.erc20.approveTokenWithdraw, [OPERATIONS_IDS.SIDECHAIN_ERC20_ISSUE]: protocol.sidechain.erc20.issue, [OPERATIONS_IDS.SIDECHAIN_ERC20_BURN]: protocol.sidechain.erc20.burn, diff --git a/src/serializers/protocol/fee_parameters.js b/src/serializers/protocol/fee_parameters.js index 9113ad3c..ccde308d 100644 --- a/src/serializers/protocol/fee_parameters.js +++ b/src/serializers/protocol/fee_parameters.js @@ -62,6 +62,7 @@ const feeParametersSerializer = staticVariant({ [OPERATIONS_IDS.SIDECHAIN_ERC20_DEPOSIT_TOKEN]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ERC20_SEND_DEPOSIT]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ERC20_WITHDRAW_TOKEN]: defaultFeeParametersSerializer, + [OPERATIONS_IDS.SIDECHAIN_ERC20_SEND_WITHDRAW]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ERC20_ISSUE]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ERC20_BURN]: defaultFeeParametersSerializer, diff --git a/src/serializers/protocol/sidechain/erc20.js b/src/serializers/protocol/sidechain/erc20.js index 38f09183..fe744e45 100644 --- a/src/serializers/protocol/sidechain/erc20.js +++ b/src/serializers/protocol/sidechain/erc20.js @@ -42,6 +42,13 @@ export const sidechainERC20WithdrawTokenOperationPropsSerializer = struct({ extensions, }); +export const sidechainERC20SendWithdrawOperationPropsSerializer = struct({ + fee: asset, + committee_member_id: accountId, + withdraw_id: withdrawErc20TokenId, + extensions, +}); + export const sidechainERC20ApproveTokenWithdrawOperationPropsSerializer = struct({ fee: asset, committee_member_id: accountId, diff --git a/src/serializers/protocol/sidechain/index.js b/src/serializers/protocol/sidechain/index.js index 7a9a0fae..45e2a20d 100644 --- a/src/serializers/protocol/sidechain/index.js +++ b/src/serializers/protocol/sidechain/index.js @@ -27,6 +27,7 @@ export const erc20 = { depositToken: _erc20.sidechainERC20DepositTokenOperationPropsSerializer, sendDeposit: _erc20.sidechainERC20SendDepositOperationPropsSerializer, withdrawToken: _erc20.sidechainERC20WithdrawTokenOperationPropsSerializer, + sendWithdraw: _erc20.sidechainERC20SendWithdrawOperationPropsSerializer, approveTokenWithdraw: _erc20.sidechainERC20ApproveTokenWithdrawOperationPropsSerializer, issue: _erc20.sidechainERC20IssueOperationPropsSerializer, burn: _erc20.sidechainERC20BurnOperationPropsSerializer, diff --git a/types/interfaces/OperationId.d.ts b/types/interfaces/OperationId.d.ts index 8992039d..14d41c51 100644 --- a/types/interfaces/OperationId.d.ts +++ b/types/interfaces/OperationId.d.ts @@ -52,15 +52,16 @@ declare enum OperationId { SIDECHAIN_ERC20_DEPOSIT_TOKEN = 49, SIDECHAIN_ERC20_SEND_DEPOSIT = 50, SIDECHAIN_ERC20_WITHDRAW_TOKEN = 51, - SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 52, - SIDECHAIN_ERC20_ISSUE = 53, // VIRTUAL - SIDECHAIN_ERC20_BURN = 54, // VIRTUAL - SIDECHAIN_BTC_CREATE_ADDRESS = 55, - SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 56, - SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 57, - SIDECHAIN_BTC_DEPOSIT = 58, - SIDECHAIN_BTC_WITHDRAW = 59, - SIDECHAIN_BTC_AGGREGATE = 60, - SIDECHAIN_BTC_APPROVE_AGGREGATE = 61, - BLOCK_REWARD = 62, // VIRTUAL + SIDECHAIN_ERC20_SEND_WITHDRAW = 52, + SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 53, + SIDECHAIN_ERC20_ISSUE = 54, // VIRTUAL + SIDECHAIN_ERC20_BURN = 55, // VIRTUAL + SIDECHAIN_BTC_CREATE_ADDRESS = 56, + SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 57, + SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 58, + SIDECHAIN_BTC_DEPOSIT = 59, + SIDECHAIN_BTC_WITHDRAW = 60, + SIDECHAIN_BTC_AGGREGATE = 61, + SIDECHAIN_BTC_APPROVE_AGGREGATE = 62, + BLOCK_REWARD = 63, // VIRTUAL } diff --git a/types/serializers/operation.d.ts b/types/serializers/operation.d.ts index 3fa215f6..924dc94a 100644 --- a/types/serializers/operation.d.ts +++ b/types/serializers/operation.d.ts @@ -56,6 +56,7 @@ export type OperationPropsSerializer = { [OperationId.SIDECHAIN_ERC20_DEPOSIT_TOKEN]: typeof protocol.sidechain.erc20.depositToken, [OperationId.SIDECHAIN_ERC20_SEND_DEPOSIT]: typeof protocol.sidechain.erc20.sendDeposit, [OperationId.SIDECHAIN_ERC20_WITHDRAW_TOKEN]: typeof protocol.sidechain.erc20.withdrawToken, + [OperationId.SIDECHAIN_ERC20_SEND_WITHDRAW]: typeof protocol.sidechain.erc20.sendWithdraw, [OperationId.SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW]: typeof protocol.sidechain.erc20.approveTokenWithdraw, [OperationId.SIDECHAIN_ERC20_ISSUE]: typeof protocol.sidechain.erc20.issue, [OperationId.SIDECHAIN_ERC20_BURN]: typeof protocol.sidechain.erc20.burn, diff --git a/types/serializers/protocol/fee_parameters.d.ts b/types/serializers/protocol/fee_parameters.d.ts index a68b6a25..6142db1a 100644 --- a/types/serializers/protocol/fee_parameters.d.ts +++ b/types/serializers/protocol/fee_parameters.d.ts @@ -72,6 +72,7 @@ export type FeeParametersSerializer = { [OperationId.SIDECHAIN_ERC20_DEPOSIT_TOKEN]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ERC20_SEND_DEPOSIT]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ERC20_WITHDRAW_TOKEN]: typeof defaultFeeParametersSerializer, + [OperationId.SIDECHAIN_ERC20_SEND_WITHDRAW]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ERC20_ISSUE]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ERC20_BURN]: typeof defaultFeeParametersSerializer, diff --git a/types/serializers/protocol/sidechain/erc20.d.ts b/types/serializers/protocol/sidechain/erc20.d.ts index b0791e8b..47e34bf6 100644 --- a/types/serializers/protocol/sidechain/erc20.d.ts +++ b/types/serializers/protocol/sidechain/erc20.d.ts @@ -42,6 +42,13 @@ export declare const sidechainERC20WithdrawTokenOperationPropsSerializer: Struct extensions: typeof extensions, }>; +export const sidechainERC20SendWithdrawOperationPropsSerializer: StructSerializer<{ + fee: typeof asset, + committee_member_id: typeof accountId, + withdraw_id: typeof withdrawErc20TokenId, + extensions: typeof extensions, +}>; + export declare const sidechainERC20ApproveTokenWithdrawOperationPropsSerializer: StructSerializer<{ fee: typeof asset, committee_member_id: typeof accountId, diff --git a/types/serializers/protocol/sidechain/index.d.ts b/types/serializers/protocol/sidechain/index.d.ts index 23719e37..57af4fc7 100644 --- a/types/serializers/protocol/sidechain/index.d.ts +++ b/types/serializers/protocol/sidechain/index.d.ts @@ -26,6 +26,7 @@ export declare const erc20: { depositToken: typeof _erc20.sidechainERC20DepositTokenOperationPropsSerializer, sendDeposit: typeof _erc20.sidechainERC20SendDepositOperationPropsSerializer, withdrawToken: typeof _erc20.sidechainERC20WithdrawTokenOperationPropsSerializer, + sendWithdraw: typeof _erc20.sidechainERC20SendWithdrawOperationPropsSerializer, approveTokenWithdraw: typeof _erc20.sidechainERC20ApproveTokenWithdrawOperationPropsSerializer, issue: typeof _erc20.sidechainERC20IssueOperationPropsSerializer, burn: typeof _erc20.sidechainERC20BurnOperationPropsSerializer, From c3e1b125566fb14aa5f4b6e6e3279d1a7d3b4d43 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 9 Dec 2019 17:33:25 +0300 Subject: [PATCH 08/62] [ECHOJS-245] Add `sidechain_eth_update_contract_address_operation` --- echo@0.14.0-rc.1-migration.md | 3 ++ src/constants/operations-ids.js | 37 ++++++++++--------- src/serializers/operation.js | 1 + src/serializers/protocol/fee_parameters.js | 1 + src/serializers/protocol/sidechain/eth.js | 6 +++ src/serializers/protocol/sidechain/index.js | 1 + types/interfaces/OperationId.d.ts | 37 ++++++++++--------- types/serializers/operation.d.ts | 1 + .../serializers/protocol/fee_parameters.d.ts | 1 + types/serializers/protocol/sidechain/eth.d.ts | 6 +++ .../serializers/protocol/sidechain/index.d.ts | 1 + 11 files changed, 59 insertions(+), 36 deletions(-) diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index ad0a7cc3..ada71a4e 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -9,5 +9,8 @@ * [x] `sidechain_eth_send_withdraw_operation` * [x] `sidechain_erc20_send_deposit_operation` * [x] `sidechain_erc20_send_withdraw_operation` +* [x] Add functionality to update ETH contract address + * [x] Add `sidechain_eth_update_contract_address_operation` + * [x] Add field `eth_update_contract_address` to `sidechain_config` * [ ] Update operations' id's in docs diff --git a/src/constants/operations-ids.js b/src/constants/operations-ids.js index 3acfa890..22c4f6b6 100644 --- a/src/constants/operations-ids.js +++ b/src/constants/operations-ids.js @@ -44,21 +44,22 @@ export const SIDECHAIN_ETH_SEND_DEPOSIT = 42; export const SIDECHAIN_ETH_WITHDRAW = 43; export const SIDECHAIN_ETH_SEND_WITHDRAW = 44; export const SIDECHAIN_ETH_APPROVE_WITHDRAW = 45; -export const SIDECHAIN_ISSUE = 46; // VIRTUAL -export const SIDECHAIN_BURN = 47; // VIRTUAL -export const SIDECHAIN_ERC20_REGISTER_TOKEN = 48; -export const SIDECHAIN_ERC20_DEPOSIT_TOKEN = 49; -export const SIDECHAIN_ERC20_SEND_DEPOSIT = 50; -export const SIDECHAIN_ERC20_WITHDRAW_TOKEN = 51; -export const SIDECHAIN_ERC20_SEND_WITHDRAW = 52; -export const SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 53; -export const SIDECHAIN_ERC20_ISSUE = 54; // VIRTUAL -export const SIDECHAIN_ERC20_BURN = 55; // VIRTUAL -export const SIDECHAIN_BTC_CREATE_ADDRESS = 56; -export const SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 57; -export const SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 58; -export const SIDECHAIN_BTC_DEPOSIT = 59; -export const SIDECHAIN_BTC_WITHDRAW = 60; -export const SIDECHAIN_BTC_AGGREGATE = 61; -export const SIDECHAIN_BTC_APPROVE_AGGREGATE = 62; -export const BLOCK_REWARD = 63; // VIRTUAL +export const SIDECHAIN_ETH_UPDATE_CONTRACT_ADDRESS = 46; +export const SIDECHAIN_ISSUE = 47; // VIRTUAL +export const SIDECHAIN_BURN = 48; // VIRTUAL +export const SIDECHAIN_ERC20_REGISTER_TOKEN = 49; +export const SIDECHAIN_ERC20_DEPOSIT_TOKEN = 50; +export const SIDECHAIN_ERC20_SEND_DEPOSIT = 51; +export const SIDECHAIN_ERC20_WITHDRAW_TOKEN = 52; +export const SIDECHAIN_ERC20_SEND_WITHDRAW = 53; +export const SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 54; +export const SIDECHAIN_ERC20_ISSUE = 55; // VIRTUAL +export const SIDECHAIN_ERC20_BURN = 56; // VIRTUAL +export const SIDECHAIN_BTC_CREATE_ADDRESS = 57; +export const SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 58; +export const SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 59; +export const SIDECHAIN_BTC_DEPOSIT = 60; +export const SIDECHAIN_BTC_WITHDRAW = 61; +export const SIDECHAIN_BTC_AGGREGATE = 62; +export const SIDECHAIN_BTC_APPROVE_AGGREGATE = 63; +export const BLOCK_REWARD = 64; // VIRTUAL diff --git a/src/serializers/operation.js b/src/serializers/operation.js index 400b88ff..4411e5f4 100644 --- a/src/serializers/operation.js +++ b/src/serializers/operation.js @@ -48,6 +48,7 @@ const operationProps = { [OPERATIONS_IDS.SIDECHAIN_ETH_WITHDRAW]: protocol.sidechain.eth.withdraw, [OPERATIONS_IDS.SIDECHAIN_ETH_SEND_WITHDRAW]: protocol.sidechain.eth.sendWithdraw, [OPERATIONS_IDS.SIDECHAIN_ETH_APPROVE_WITHDRAW]: protocol.sidechain.eth.approveWithdraw, + [OPERATIONS_IDS.SIDECHAIN_ETH_UPDATE_CONTRACT_ADDRESS]: protocol.sidechain.eth.updateContractAddress, [OPERATIONS_IDS.CONTRACT_FUND_POOL]: protocol.contract.fundPool, [OPERATIONS_IDS.CONTRACT_WHITELIST]: protocol.contract.whitelist, [OPERATIONS_IDS.SIDECHAIN_ISSUE]: protocol.sidechain.issue, diff --git a/src/serializers/protocol/fee_parameters.js b/src/serializers/protocol/fee_parameters.js index ccde308d..18972f12 100644 --- a/src/serializers/protocol/fee_parameters.js +++ b/src/serializers/protocol/fee_parameters.js @@ -56,6 +56,7 @@ const feeParametersSerializer = staticVariant({ [OPERATIONS_IDS.SIDECHAIN_ETH_WITHDRAW]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ETH_SEND_WITHDRAW]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ETH_APPROVE_WITHDRAW]: defaultFeeParametersSerializer, + [OPERATIONS_IDS.SIDECHAIN_ETH_UPDATE_CONTRACT_ADDRESS]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ISSUE]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_BURN]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ERC20_REGISTER_TOKEN]: struct({ fee: uint64, pool_fee: uint64 }), diff --git a/src/serializers/protocol/sidechain/eth.js b/src/serializers/protocol/sidechain/eth.js index eec754cc..54ba80c8 100644 --- a/src/serializers/protocol/sidechain/eth.js +++ b/src/serializers/protocol/sidechain/eth.js @@ -56,3 +56,9 @@ export const sidechainEthApproveWithdrawOperationPropsSerializer = struct({ withdraw_id: uint64, extensions, }); + +export const sidechainEthUpdateContractAddressOperationPropsSerializer = struct({ + fee: asset, + new_addr: ethAddress, + extensions, +}); diff --git a/src/serializers/protocol/sidechain/index.js b/src/serializers/protocol/sidechain/index.js index 45e2a20d..30a1d422 100644 --- a/src/serializers/protocol/sidechain/index.js +++ b/src/serializers/protocol/sidechain/index.js @@ -41,6 +41,7 @@ export const eth = { withdraw: _eth.sidechainEthWithdrawOperationPropsSerializer, sendWithdraw: _eth.sidechainEthSendWithdrawOperationPropsSerializer, approveWithdraw: _eth.sidechainEthApproveWithdrawOperationPropsSerializer, + updateContractAddress: _eth.sidechainEthUpdateContractAddressOperationPropsSerializer, }; export const btc = { diff --git a/types/interfaces/OperationId.d.ts b/types/interfaces/OperationId.d.ts index 14d41c51..e9b842fc 100644 --- a/types/interfaces/OperationId.d.ts +++ b/types/interfaces/OperationId.d.ts @@ -46,22 +46,23 @@ declare enum OperationId { SIDECHAIN_ETH_WITHDRAW = 43, SIDECHAIN_ETH_SEND_WITHDRAW = 44, SIDECHAIN_ETH_APPROVE_WITHDRAW = 45, - SIDECHAIN_ISSUE = 46, // VIRTUAL - SIDECHAIN_BURN = 47, // VIRTUAL - SIDECHAIN_ERC20_REGISTER_TOKEN = 48, - SIDECHAIN_ERC20_DEPOSIT_TOKEN = 49, - SIDECHAIN_ERC20_SEND_DEPOSIT = 50, - SIDECHAIN_ERC20_WITHDRAW_TOKEN = 51, - SIDECHAIN_ERC20_SEND_WITHDRAW = 52, - SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 53, - SIDECHAIN_ERC20_ISSUE = 54, // VIRTUAL - SIDECHAIN_ERC20_BURN = 55, // VIRTUAL - SIDECHAIN_BTC_CREATE_ADDRESS = 56, - SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 57, - SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 58, - SIDECHAIN_BTC_DEPOSIT = 59, - SIDECHAIN_BTC_WITHDRAW = 60, - SIDECHAIN_BTC_AGGREGATE = 61, - SIDECHAIN_BTC_APPROVE_AGGREGATE = 62, - BLOCK_REWARD = 63, // VIRTUAL + SIDECHAIN_ETH_UPDATE_CONTRACT_ADDRESS = 46, + SIDECHAIN_ISSUE = 47, // VIRTUAL + SIDECHAIN_BURN = 48, // VIRTUAL + SIDECHAIN_ERC20_REGISTER_TOKEN = 49, + SIDECHAIN_ERC20_DEPOSIT_TOKEN = 50, + SIDECHAIN_ERC20_SEND_DEPOSIT = 51, + SIDECHAIN_ERC20_WITHDRAW_TOKEN = 52, + SIDECHAIN_ERC20_SEND_WITHDRAW = 53, + SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 54, + SIDECHAIN_ERC20_ISSUE = 55, // VIRTUAL + SIDECHAIN_ERC20_BURN = 56, // VIRTUAL + SIDECHAIN_BTC_CREATE_ADDRESS = 57, + SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 58, + SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 59, + SIDECHAIN_BTC_DEPOSIT = 60, + SIDECHAIN_BTC_WITHDRAW = 61, + SIDECHAIN_BTC_AGGREGATE = 62, + SIDECHAIN_BTC_APPROVE_AGGREGATE = 63, + BLOCK_REWARD = 64, // VIRTUAL } diff --git a/types/serializers/operation.d.ts b/types/serializers/operation.d.ts index 924dc94a..3b97ab74 100644 --- a/types/serializers/operation.d.ts +++ b/types/serializers/operation.d.ts @@ -48,6 +48,7 @@ export type OperationPropsSerializer = { [OperationId.SIDECHAIN_ETH_WITHDRAW]: typeof protocol.sidechain.eth.withdraw, [OperationId.SIDECHAIN_ETH_SEND_WITHDRAW]: typeof protocol.sidechain.eth.sendWithdraw, [OperationId.SIDECHAIN_ETH_APPROVE_WITHDRAW]: typeof protocol.sidechain.eth.approveWithdraw, + [OperationId.SIDECHAIN_ETH_UPDATE_CONTRACT_ADDRESS]: typeof protocol.sidechain.eth.updateContractAddress, [OperationId.CONTRACT_FUND_POOL]: typeof protocol.contract.fundPool, [OperationId.CONTRACT_WHITELIST]: typeof protocol.contract.whitelist, [OperationId.SIDECHAIN_ISSUE]: typeof protocol.sidechain.issue, diff --git a/types/serializers/protocol/fee_parameters.d.ts b/types/serializers/protocol/fee_parameters.d.ts index 6142db1a..c1fd2b9c 100644 --- a/types/serializers/protocol/fee_parameters.d.ts +++ b/types/serializers/protocol/fee_parameters.d.ts @@ -66,6 +66,7 @@ export type FeeParametersSerializer = { [OperationId.SIDECHAIN_ETH_WITHDRAW]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ETH_SEND_WITHDRAW]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ETH_APPROVE_WITHDRAW]: typeof defaultFeeParametersSerializer, + [OperationId.SIDECHAIN_ETH_UPDATE_CONTRACT_ADDRESS]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ISSUE]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_BURN]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ERC20_REGISTER_TOKEN]: StructSerializer<{ fee: typeof uint64, pool_fee: typeof uint64 }>, diff --git a/types/serializers/protocol/sidechain/eth.d.ts b/types/serializers/protocol/sidechain/eth.d.ts index dbf0492e..ebc61867 100644 --- a/types/serializers/protocol/sidechain/eth.d.ts +++ b/types/serializers/protocol/sidechain/eth.d.ts @@ -56,3 +56,9 @@ export declare const sidechainEthApproveWithdrawOperationPropsSerializer: Struct withdraw_id: typeof uint64, extensions: typeof extensions, }>; + +export const sidechainEthUpdateContractAddressOperationPropsSerializer: StructSerializer<{ + fee: typeof asset, + new_addr: typeof ethAddress, + extensions: typeof extensions, +}>; diff --git a/types/serializers/protocol/sidechain/index.d.ts b/types/serializers/protocol/sidechain/index.d.ts index 57af4fc7..5162817c 100644 --- a/types/serializers/protocol/sidechain/index.d.ts +++ b/types/serializers/protocol/sidechain/index.d.ts @@ -40,6 +40,7 @@ export declare const eth: { withdraw: typeof _eth.sidechainEthWithdrawOperationPropsSerializer, sendWithdraw: typeof _eth.sidechainEthSendWithdrawOperationPropsSerializer, approveWithdraw: typeof _eth.sidechainEthApproveWithdrawOperationPropsSerializer, + updateContractAddress: typeof _eth.sidechainEthUpdateContractAddressOperationPropsSerializer, }; export declare const btc: { From 971dc97cff9cb157c80e5b35a9c44c181813360f Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 9 Dec 2019 17:57:55 +0300 Subject: [PATCH 09/62] [ECHOJS-245] Add `get_contract_history` method to wallet-api && Fix JSDoc of ObjectId --- echo@0.14.0-rc.1-migration.md | 3 +++ src/echo/ws-api/wallet-api.js | 12 ++++++++++++ src/serializers/chain/id/ObjectId.js | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index ada71a4e..93d41e7f 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -12,5 +12,8 @@ * [x] Add functionality to update ETH contract address * [x] Add `sidechain_eth_update_contract_address_operation` * [x] Add field `eth_update_contract_address` to `sidechain_config` +* [ ] Add methods to wallet-api + * [x] `get_contract_history` + * [ ] `get_relative_contract_history` * [ ] Update operations' id's in docs diff --git a/src/echo/ws-api/wallet-api.js b/src/echo/ws-api/wallet-api.js index fbdb34a3..8dd47c20 100644 --- a/src/echo/ws-api/wallet-api.js +++ b/src/echo/ws-api/wallet-api.js @@ -552,6 +552,18 @@ class WalletAPI { return this.wsRpc.call([0, 'get_contract_result', [string.toRaw(contractResultId)]]); } + /** + * Returns the most recent operations on the contract id. + * + * This returns a list of operation history objects, which describe activity on the contract. + * @param {typeof contractId["__TInput__"]} _contractId the ID of the contract + * @param {typeof uint32["__TInput__"]} limit the number of entries to return (starting from the most recent) + * @returns {Promise} a list of accounts mapping account names to account ids + */ + async getContractHistory(_contractId, limit) { + return this.wsRpc.call([0, 'get_contract_history', [contractId.toRaw(_contractId), uint32.toRaw(limit)]]); + } + /** * Transfer an amount from one account to another. * @param {string} fromAccountNameOrId the name or id of the account sending the funds diff --git a/src/serializers/chain/id/ObjectId.js b/src/serializers/chain/id/ObjectId.js index b4fea888..21b6895c 100644 --- a/src/serializers/chain/id/ObjectId.js +++ b/src/serializers/chain/id/ObjectId.js @@ -32,7 +32,7 @@ const _objectTypeIds = { /** * @template {ReservedSpaceId} T - * @augments {ISerializer} + * @augments {ISerializer} */ export default class ObjectIdSerializer extends ISerializer { From c2a99508c458804941f7fdcfb31bd5b1487b260e Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 9 Dec 2019 18:07:30 +0300 Subject: [PATCH 10/62] [ECHOJS-245] Add `get_relative_contract_history` method to wallet-api --- echo@0.14.0-rc.1-migration.md | 2 +- src/echo/ws-api/wallet-api.js | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index 93d41e7f..ed5658b2 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -14,6 +14,6 @@ * [x] Add field `eth_update_contract_address` to `sidechain_config` * [ ] Add methods to wallet-api * [x] `get_contract_history` - * [ ] `get_relative_contract_history` + * [x] `get_relative_contract_history` * [ ] Update operations' id's in docs diff --git a/src/echo/ws-api/wallet-api.js b/src/echo/ws-api/wallet-api.js index 8dd47c20..12b91223 100644 --- a/src/echo/ws-api/wallet-api.js +++ b/src/echo/ws-api/wallet-api.js @@ -564,6 +564,23 @@ class WalletAPI { return this.wsRpc.call([0, 'get_contract_history', [contractId.toRaw(_contractId), uint32.toRaw(limit)]]); } + /** + * Returns the relative operations on the id contract from start number + * @param {typeof contractId["__TInput__"]} _contractId the ID of the contract + * @param {typeof uint32["__TInput__"]} stop Sequence number of earliest operation + * @param {typeof uint32["__TInput__"]} limit the number of entries to return + * @param {typeof uint32["__TInput__"]} start the sequence number where to start looping back throw the history + * @returns {Promise} a list of operation history objects + */ + async getRelativeContractHistory(_contractId, stop, limit, start) { + return this.wsRpc.call([0, 'get_relative_contract_history', [ + contractId.toRaw(_contractId), + uint32.toRaw(stop), + uint32.toRaw(limit), + uint32.toRaw(start), + ]]); + } + /** * Transfer an amount from one account to another. * @param {string} fromAccountNameOrId the name or id of the account sending the funds From 08bd5612eac02ef33d09f7e6a605e7700fe9df5f Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Tue, 10 Dec 2019 12:41:14 +0300 Subject: [PATCH 11/62] [ECHOJS-245] Add `get_relative_contract_history` method to history-api --- src/echo/api.js | 18 +++++- src/echo/ws-api/history-api.js | 15 +++++ src/serializers/basic/integers/UInt64.js | 2 +- types/echo/api.d.ts | 77 +++++++++++++++++++++--- types/interfaces/chain.d.ts | 17 ++++++ 5 files changed, 118 insertions(+), 11 deletions(-) create mode 100644 types/interfaces/chain.d.ts diff --git a/src/echo/api.js b/src/echo/api.js index f6cab663..ff7adf3f 100644 --- a/src/echo/api.js +++ b/src/echo/api.js @@ -38,7 +38,7 @@ import { solveRegistrationTask, validateRegistrationOptions } from '../utils/pow /** @typedef {import('./ws-api').default} WSAPI */ import { ECHO_ASSET_ID, DYNAMIC_GLOBAL_OBJECT_ID, API_CONFIG, CACHE_MAPS } from '../constants'; -import { transaction, signedTransaction, operation, basic } from '../serializers'; +import { transaction, signedTransaction, operation, basic, chain } from '../serializers'; import { PublicKey } from '../crypto'; /** @typedef {import("./ws-api/database-api").SidechainType} SidechainType */ @@ -2290,6 +2290,22 @@ class API { ); } + /** + * @param {typeof chain.ids["protocol"]["contractId"]["__TInput__"]} contract + * @param {Object} [options] + * @param {typeof basic.integers["uint64"]["__TInput__"]} [options.stop] + * @param {typeof basic.integers["uint32"]["__TInput__"]} [options.limit] + * @param {typeof basic.integers["uint64"]["__TInput__"]} [options.start] + */ + async getRelativeContractHistory(contract, options = {}) { + contract = chain.ids.protocol.contractId.toRaw(contract); + const stop = options.stop === undefined ? 0 : basic.integers.uint64.toRaw(options.stop); + const limit = options.limit === undefined ? 100 : basic.integers.uint32.toRaw(options.limit); + const start = options.stop === undefined ? 0 : basic.integers.uint64.toRaw(options.start); + if (limit > 100) throw new Error('Limit is greater than 100'); + return this.wsApi.history.getRelativeContractHistory(contract, stop, limit, start); + } + /** * @method getFullContract * Get contract info. diff --git a/src/echo/ws-api/history-api.js b/src/echo/ws-api/history-api.js index 865d1821..39571d30 100644 --- a/src/echo/ws-api/history-api.js +++ b/src/echo/ws-api/history-api.js @@ -1,5 +1,9 @@ import { START_OPERATION_ID } from '../../constants'; +/** @typedef {import("../../../types/interfaces/chain").OperationHistoryObject} OperationHistoryObject */ +/** @typedef {import("../../serializers/basic/integers")} Integer_t */ +/** @typedef {import("../../serializers/chain/id/protocol")["contractId"]["__TOutput__"]} ContractId */ + class HistoryAPI { /** @@ -78,6 +82,17 @@ class HistoryAPI { return this.db.exec('get_contract_history', [contractId, stop, limit, start]); } + /** + * @param {ContractId} contract + * @param {Integer_t["uint64"]["__TOutput__"]} stop + * @param {Integer_t["uint32"]["__TOutput__"]} limit + * @param {Integer_t["uint64"]["__TOutput__"]} start + * @returns {Promise} + */ + getRelativeContractHistory(contract, stop, limit, start) { + return this.db.exec('get_relative_contract_history', [contract, stop, limit, start]); + } + } export default HistoryAPI; diff --git a/src/serializers/basic/integers/UInt64.js b/src/serializers/basic/integers/UInt64.js index 39b81ca3..de570e18 100644 --- a/src/serializers/basic/integers/UInt64.js +++ b/src/serializers/basic/integers/UInt64.js @@ -9,7 +9,7 @@ import IUIntSerializer from './IUIntSerializer'; * @typedef {import("../../ISerializer").SerializerInput} SerializerInput */ -/** @augments {IUIntSerializer} */ +/** @augments {IUIntSerializer} */ export default class UInt64Serializer extends IUIntSerializer { constructor() { super(64); } diff --git a/types/echo/api.d.ts b/types/echo/api.d.ts index a27177e9..6d182c0b 100644 --- a/types/echo/api.d.ts +++ b/types/echo/api.d.ts @@ -22,14 +22,15 @@ import ContractHistory from '../interfaces/ContractHistory'; import ContractResult from '../interfaces/ContractResult'; import FrozenBalance from '../interfaces/FrozenBalance'; import BtcAddress from '../interfaces/BtcAddress'; +import { OperationHistoryObject } from '../interfaces/chain'; import { PotentialPeerRecord } from '../interfaces/net/peer-database'; import RegistrationTask from '../interfaces/RegistrationTask'; import PeerDetails from '../interfaces/PeerDetails'; import { asset } from '../serializers/chain'; import { VectorSerializer } from '../serializers/collections'; import { signedTransaction } from '../serializers'; -import { committeeMemberId } from '../serializers/chain/id/protocol'; -import { uint32 } from '../serializers/basic/integers'; +import { uint32, uint64 } from '../serializers/basic/integers'; +import { committeeMemberId, contractId } from '../serializers/chain/id/protocol'; type SidechainType = "" | "eth" | "btc"; @@ -51,11 +52,25 @@ export default class Api { getAccountCount(): Promise; getAccountDeposits(account: string, type: SidechainType): Promise; getAccountHistory(accountId: string, stop: string, limit: number, start: string): Promise>; - getAccountHistoryOperations(accountId: string, operationId: string, start: number, stop: number, limit: number): Promise>; + + getAccountHistoryOperations( + accountId: string, + operationId: string, + start: number, + stop: number, + limit: number, + ): Promise; + getAccountReferences(accountId: string, force?: boolean): Promise; getAccountWithdrawals(account: string, type: SidechainType): Promise; getAllAssetHolders(): Promise>; - getAssetHolders(assetId: string, start: number, limit: number): Promise>; + + getAssetHolders(assetId: string, start: number, limit: number): Promise>; + getAssetHoldersCount(assetId: string): Promise; getAssets(assetIds: Array, force?: boolean): Promise>; getBalanceObjects(keys: Object): any; @@ -77,21 +92,57 @@ export default class Api { getContract(contractId: string): Promise>; getContractBalances(contractId: string, force?: boolean): Promise; getContractPoolWhitelist(contractId: string): Promise; - getContractHistory(operationId: string, stop: number, limit: number, start: number): Promise>; - getContracts(contractIds: Array, force?: boolean): Promise>; + + getContractHistory( + operationId: string, + stop: number, + limit: number, + start: number, + ): Promise; + + /** + * Get operations relevant to the specified contract referenced by an event numbering specific to the contract. + * The current number of operations for the contract can be found in the contract statistics (or use 0 for start). + * @param contract the contract whose history should be queried + * @param options.stop + * Sequence number of earliest operation. 0 is default and will query `limit` number of operations. + * @param options.limit Maximum number of operations to retrive (must not exceed 100) + * @param options.start Sequence number of the most recent operation to retrive. + * 0 is default, which will start querying from the most recent operation. + * @returns A list of operations performed by contract, ordered from most recent to oldest + */ + getRelativeContractHistory(contract: typeof contractId["__TInput__"], options?: { + stop?: typeof uint64["__TInput__"], + limit?: typeof uint64["__TInput__"], + start?: typeof uint64["__TInput__"], + }): Promise; + + getContracts(contractIds: Array, force?: boolean): Promise>; + getContractLogs(opts: { contracts?: string[], topics?: Array>, fromBlock?: number | BigNumber, toBlock?: number | BigNumber, }): Promise; + getContractPoolBalance(resultContractId: string, force?: boolean): Promise<{asset_id: string, amount: number}>; getContractResult(resultContractId: string, force?: boolean): Promise; getDynamicAssetData(dynamicAssetDataId: string, force?: boolean): Promise; getDynamicGlobalProperties(force?: boolean): Promise; getFeePool(assetId: string): Promise; getFrozenBalances(accountId: string): Promise>; - getFullAccounts(accountNamesOrIds: Array, subscribe?: boolean, force?: boolean): Promise>; + + getFullAccounts( + accountNamesOrIds: string[], + subscribe?: boolean, + force?: boolean, + ): Promise; + getFullContract(contractId: string, force?: boolean): Promise; getGlobalProperties(force?: boolean): Promise; getKeyReferences(keys: Array, force?: boolean): Promise; @@ -102,11 +153,19 @@ export default class Api { getPotentialSignatures(tr: Object): Promise; getProposedTransactions(accountNameOrId: string): Promise; getRecentTransactionById(transactionId: string): Promise; - getRelativeAccountHistory(accountId: string, stop: number, limit: number, start: number): Promise>; + getRelativeAccountHistory(accountId: string, stop: number, limit: number, start: number): Promise; getRequiredFees(operations: Array, assetId: string): Promise>; getRequiredSignatures(tr: Object, availableKey: Array): Promise; getTicker(baseAssetName: string, quoteAssetName: string): Promise; - getTradeHistory(baseAssetName: string, quoteAssetName: number, start: number, stop: number, limit: number): Promise; + + getTradeHistory( + baseAssetName: string, + quoteAssetName: number, + start: number, + stop: number, + limit: number, + ): Promise; + getTransaction(blockNum: number, transactionIndex: number): Promise; getTransactionHex(tr: Object): Promise; getVestedBalances(balanceIds: Array): Promise; diff --git a/types/interfaces/chain.d.ts b/types/interfaces/chain.d.ts new file mode 100644 index 00000000..c98c70fa --- /dev/null +++ b/types/interfaces/chain.d.ts @@ -0,0 +1,17 @@ +import { RESERVED_SPACE_ID } from "../constants/chain-types"; +import { OperationSerializer, operationResult, chain } from "../serializers"; +import { uint32, uint16 } from "../serializers/basic/integers"; +import { extensions } from "../serializers/chain"; +import { ObjectIdSerializer } from "../serializers/chain/id"; +import { StructSerializer } from "../serializers/collections"; + +export type OperationHistoryObject = StructSerializer<{ + id: ObjectIdSerializer; + op: OperationSerializer; + result: typeof operationResult; + block_num: typeof uint32; + trx_in_block: typeof uint16; + op_in_trx: typeof uint16; + virtual_op: typeof uint16; + extensions: typeof extensions; +}>["__TOutput__"]; From bfd7f0f5aea39663ad2437dea3dddbb08e13ebdc Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Tue, 10 Dec 2019 14:14:54 +0300 Subject: [PATCH 12/62] [ECHOJS-245] Change arguments of `get_contract_logs` method and make it async --- echo@0.14.0-rc.1-migration.md | 6 +- src/echo/api.js | 78 +++++++++------------ src/echo/ws-api/database-api.js | 13 ++-- src/echo/ws/reconnection-websocket.js | 3 +- src/serializers/basic/integers/Int32.js | 28 ++++++++ src/serializers/basic/integers/Int64.js | 2 +- src/serializers/basic/integers/index.js | 3 + types/echo/api.d.ts | 22 +++++- types/interfaces/vm/index.d.ts | 3 + types/interfaces/vm/types.d.ts | 15 ++++ types/serializers/basic/integers/Int32.d.ts | 7 ++ types/serializers/basic/integers/index.d.ts | 3 + types/serializers/collections/Set.d.ts | 2 +- types/serializers/collections/Vector.d.ts | 9 ++- 14 files changed, 131 insertions(+), 63 deletions(-) create mode 100644 src/serializers/basic/integers/Int32.js create mode 100644 types/interfaces/vm/index.d.ts create mode 100644 types/interfaces/vm/types.d.ts create mode 100644 types/serializers/basic/integers/Int32.d.ts diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index ed5658b2..8e1f95ee 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -12,8 +12,12 @@ * [x] Add functionality to update ETH contract address * [x] Add `sidechain_eth_update_contract_address_operation` * [x] Add field `eth_update_contract_address` to `sidechain_config` -* [ ] Add methods to wallet-api +* [x] Add methods to wallet-api * [x] `get_contract_history` * [x] `get_relative_contract_history` +* [x] Change arguments of `get_contract_logs` method and make it async * [ ] Update operations' id's in docs +* [ ] Tests + * [ ] `get_contract_history` + * [ ] `get_relative_contract_history` diff --git a/src/echo/api.js b/src/echo/api.js index ff7adf3f..07e0ba40 100644 --- a/src/echo/api.js +++ b/src/echo/api.js @@ -1,6 +1,4 @@ /* eslint-disable no-continue,no-await-in-loop,camelcase,no-restricted-syntax */ -import { ok } from 'assert'; -import BigNumber from 'bignumber.js'; import { Map, List, fromJS } from 'immutable'; import { @@ -27,7 +25,6 @@ import { isOperationId, isDynamicGlobalObjectId, isBtcAddressId, - isUInt32, isObject, isInt64, validateSidechainType, @@ -38,11 +35,20 @@ import { solveRegistrationTask, validateRegistrationOptions } from '../utils/pow /** @typedef {import('./ws-api').default} WSAPI */ import { ECHO_ASSET_ID, DYNAMIC_GLOBAL_OBJECT_ID, API_CONFIG, CACHE_MAPS } from '../constants'; -import { transaction, signedTransaction, operation, basic, chain } from '../serializers'; +import { transaction, signedTransaction, operation, basic, chain, collections } from '../serializers'; import { PublicKey } from '../crypto'; +/** @typedef {import("bignumber.js").default} BigNumber */ +/** @typedef {import("../../types/interfaces/vm/types").Log} Log */ /** @typedef {import("./ws-api/database-api").SidechainType} SidechainType */ +/** @typedef {string | number | BigNumber} ObjectId_t */ +/** @typedef {number | BigNumber | string} Integer_t */ +/** + * @template T + * @typedef {Set | T[] | undefined} Set_t + */ + /** @typedef { * { * previous:String, @@ -1930,48 +1936,28 @@ class API { } /** - * @param {Object} [opts] - * @param {string[]} [opts.contracts] - * @param {(null | string | Buffer | (string | Buffer)[])[]} [opts.topics] - * @param {number | BigNumber} [opts.fromBlock] - * @param {number | BigNumber} [opts.toBlock] - * @returns {Promise} - */ - async getContractLogs(opts = {}) { - if (opts.contracts !== undefined) { - ok(Array.isArray(opts.contracts), '"contracts" option is not an array'); - for (const contractId of opts.contracts) ok(isContractId(contractId)); - } - /** @type {typeof opts["topics"]} */ - let topics; - if (opts.topics !== undefined) { - ok(Array.isArray(opts.topics), '"topics" option is not an array'); - topics = new Array(opts.topics.length).fill(null); - for (let topicIndex = 0; topicIndex < opts.topics.length; topicIndex += 1) { - let topicVariants = opts.topics[topicIndex]; - if (topicVariants === null) topicVariants = []; - else if (typeof topicVariants === 'string') topicVariants = [topicVariants]; - topics[topicIndex] = new Array(topicVariants.length).fill(null); - for (let variantIndex = 0; variantIndex < topicVariants.length; variantIndex += 1) { - let variant = topicVariants[variantIndex]; - if (Buffer.isBuffer(variant)) variant = variant.toString('hex'); - ok(typeof variant === 'string', 'invalid "topic" option type'); - if (variant.startsWith('0x')) variant = variant.slice(2); - ok(/^([\da-fA-F]{2})+$/.test(variant), '"topic" is not a hex'); - ok(variant.length === 64, 'invalid "topic" length'); - topics[topicIndex][variantIndex] = variant; - } - } - } - for (const field of ['fromBlock', 'toBlock']) { - ok(opts[field] === undefined || isUInt32(opts[field]), `"${field}" option is not uint32`); - } - return this.wsApi.database.getContractLogs({ - contracts: opts.contracts, - topics, - from_block: BigNumber.isBigNumber(opts.fromBlock) ? opts.fromBlock.toNumber() : opts.fromBlock, - to_block: BigNumber.isBigNumber(opts.toBlock) ? opts.toBlock.toNumber() : opts.toBlock, - }); + * @param {Set_t} contracts + * @param {Array>} topics + * @param {Object} [blocks] + * @param {Integer_t} [blocks.from] + * @param {Integer_t} [blocks.to] + * @returns {Promise} + */ + async getContractLogs(contracts, topics, blocks = {}) { + /** @type {string[]} */ + const contractsList = collections.set(chain.ids.protocol.contractId).toRaw(contracts); + /** @type {Array} */ + const topicsList = collections.vector(collections.set(basic.string)).toRaw(topics); + const from = blocks.from === undefined ? undefined : basic.integers.int32.toRaw(blocks.from); + const to = blocks.to === undefined ? undefined : basic.integers.int32.toRaw(blocks.to); + if (from !== undefined && from < 0) throw new Error('`blocks.from` must be greater than or equal to zero'); + if (to !== undefined && to <= 0) throw new Error('`blocks.to` must be greater than zero'); + return new Promise((resolve) => this.wsApi.database.getContractLogs((res) => resolve(res), { + contracts: contractsList, + topics: topicsList, + from_block: from, + to_block: to, + })); } /** diff --git a/src/echo/ws-api/database-api.js b/src/echo/ws-api/database-api.js index 57f9e455..b7487301 100644 --- a/src/echo/ws-api/database-api.js +++ b/src/echo/ws-api/database-api.js @@ -1,3 +1,5 @@ +/** @typedef {import("../../../types/interfaces/vm/types").Log} Log */ + /** @typedef {"" | "eth" | "btc"} SidechainType */ class DatabaseAPI { @@ -496,17 +498,14 @@ class DatabaseAPI { } /** - * @method getContractLogs + * @param {(result: Log[]) => any} cb * @param {Object} opts - * @param {string[]} [opts.contracts] - * @param {(string | string[])[]} [opts.topics] + * @param {string[]} opts.contracts + * @param {Array} opts.topics * @param {number} [opts.from_block] * @param {number} [opts.to_block] - * @returns {Promise} */ - getContractLogs(opts) { - return this.db.exec('get_contract_logs', [opts]); - } + getContractLogs(cb, opts) { return this.db.exec('get_contract_logs', [cb, opts]); } /** * @method subscribeContractLogs diff --git a/src/echo/ws/reconnection-websocket.js b/src/echo/ws/reconnection-websocket.js index f9bb5436..b9dbbfb6 100644 --- a/src/echo/ws/reconnection-websocket.js +++ b/src/echo/ws/reconnection-websocket.js @@ -211,7 +211,8 @@ class ReconnectionWebSocket { if (method === 'set_subscribe_callback' || method === 'broadcast_transaction_with_callback' || method === 'set_pending_transaction_callback' || method === 'set_block_applied_callback' || method === 'set_consensus_message_callback' || - method === 'subscribe_contract_logs' || method === 'submit_registration_solution' + method === 'subscribe_contract_logs' || method === 'submit_registration_solution' || + method === 'get_contract_logs' ) { // Store callback in subs map this._subs[this._cbId] = { diff --git a/src/serializers/basic/integers/Int32.js b/src/serializers/basic/integers/Int32.js new file mode 100644 index 00000000..1ca0ddcb --- /dev/null +++ b/src/serializers/basic/integers/Int32.js @@ -0,0 +1,28 @@ +import IIntSerializer from './IIntSerializer'; + +/** @typedef {import("bytebuffer")} ByteBuffer */ + +/** @typedef {import("../../ISerializer").default} ISerializer */ + +/** + * @template {ISerializer} T + * @typedef {import("../../ISerializer").SerializerInput} SerializerInput + */ + +/** @augments {IIntSerializer} */ +export default class Int32Serializer extends IIntSerializer { + + constructor() { + super(32); + } + + /** + * @param {SerializerInput} value + * @param {ByteBuffer} bytebuffer + */ + appendToByteBuffer(value, bytebuffer) { + const raw = this.toRaw(value); + bytebuffer.writeInt32(raw); + } + +} diff --git a/src/serializers/basic/integers/Int64.js b/src/serializers/basic/integers/Int64.js index e50adfa1..225412af 100644 --- a/src/serializers/basic/integers/Int64.js +++ b/src/serializers/basic/integers/Int64.js @@ -9,7 +9,7 @@ import IIntSerializer from './IIntSerializer'; * @typedef {import("../../ISerializer").SerializerInput} SerializerInput */ -/** @augments {IIntSerializer} */ +/** @augments {IIntSerializer} */ export default class Int64Serializer extends IIntSerializer { constructor() { diff --git a/src/serializers/basic/integers/index.js b/src/serializers/basic/integers/index.js index e9a48444..40f12d90 100644 --- a/src/serializers/basic/integers/index.js +++ b/src/serializers/basic/integers/index.js @@ -1,4 +1,5 @@ import IIntSerializer from './IIntSerializer'; +import Int32Serializer from './Int32'; import Int64Serializer from './Int64'; import IUIntSerializer from './IUIntSerializer'; import UInt8Serializer from './UInt8'; @@ -8,6 +9,7 @@ import UInt64Serializer from './UInt64'; import UInt256Serializer from './UInt256'; import VarInt32Serializer from './VarInt32'; +export const int32 = new Int32Serializer(); export const int64 = new Int64Serializer(); export const uint8 = new UInt8Serializer(); export const uint16 = new UInt16Serializer(); @@ -18,6 +20,7 @@ export const varint32 = new VarInt32Serializer(); export { IIntSerializer, + Int32Serializer, Int64Serializer, IUIntSerializer, UInt8Serializer, diff --git a/types/echo/api.d.ts b/types/echo/api.d.ts index 6d182c0b..52689a12 100644 --- a/types/echo/api.d.ts +++ b/types/echo/api.d.ts @@ -26,11 +26,13 @@ import { OperationHistoryObject } from '../interfaces/chain'; import { PotentialPeerRecord } from '../interfaces/net/peer-database'; import RegistrationTask from '../interfaces/RegistrationTask'; import PeerDetails from '../interfaces/PeerDetails'; +import { Log } from '../interfaces/vm/types'; import { asset } from '../serializers/chain'; -import { VectorSerializer } from '../serializers/collections'; import { signedTransaction } from '../serializers'; -import { uint32, uint64 } from '../serializers/basic/integers'; +import { StringSerializer } from '../serializers/basic'; +import { uint32, uint64, int32 } from '../serializers/basic/integers'; import { committeeMemberId, contractId } from '../serializers/chain/id/protocol'; +import { VectorSerializer, SetSerializer } from '../serializers/collections'; type SidechainType = "" | "eth" | "btc"; @@ -123,7 +125,21 @@ export default class Api { suicided: boolean, }>>; - getContractLogs(opts: { + /** + * Get logs of specified contract logs filter options + * @param contracts IDs of the contract + * @param topics Filters by certain events if any provided + * @param blocks.from Number of block to start retrive from + * @param blocks.to Number of block to end to retrive + * @returns The contracts logs from specified blocks interval + */ + getContractLogs( + contracts: SetSerializer["__TInput__"], + topics: VectorSerializer>["__TInput__"], + blocks?: { from?: typeof int32["__TInput__"], to?: typeof int32["__TInput__"] }, + ): Promise; + + getContractLogs1(opts: { contracts?: string[], topics?: Array>, fromBlock?: number | BigNumber, diff --git a/types/interfaces/vm/index.d.ts b/types/interfaces/vm/index.d.ts new file mode 100644 index 00000000..83d0ba55 --- /dev/null +++ b/types/interfaces/vm/index.d.ts @@ -0,0 +1,3 @@ +import * as types from "./types"; + +export { types }; diff --git a/types/interfaces/vm/types.d.ts b/types/interfaces/vm/types.d.ts new file mode 100644 index 00000000..b2358adc --- /dev/null +++ b/types/interfaces/vm/types.d.ts @@ -0,0 +1,15 @@ +export enum LogType { + EVM = 0, + X86_X64 = 1, +} + +export interface LogEntry { + address: string; + log: string[]; + data: string; + block_num: number; + trx_num: number; + op_num: number; +} + +export type Log = [LogType, LogEntry]; diff --git a/types/serializers/basic/integers/Int32.d.ts b/types/serializers/basic/integers/Int32.d.ts new file mode 100644 index 00000000..3bf73cc0 --- /dev/null +++ b/types/serializers/basic/integers/Int32.d.ts @@ -0,0 +1,7 @@ +import * as ByteBuffer from "bytebuffer"; +import IIntSerializer from "./IIntSerializer"; +import { SerializerInput, SerializerOutput } from "../../ISerializer"; + +export default class Int32Serializer extends IIntSerializer { + appendToByteBuffer(value: SerializerInput, bytebuffer: ByteBuffer): void; +} diff --git a/types/serializers/basic/integers/index.d.ts b/types/serializers/basic/integers/index.d.ts index 510c59be..b411a737 100644 --- a/types/serializers/basic/integers/index.d.ts +++ b/types/serializers/basic/integers/index.d.ts @@ -1,4 +1,5 @@ import IIntSerializer from './IIntSerializer'; +import Int32Serializer from './Int32'; import Int64Serializer from './Int64'; import IUIntSerializer from './IUIntSerializer'; import UInt8Serializer from './UInt8'; @@ -8,6 +9,7 @@ import UInt64Serializer from './UInt64'; import UInt256Serializer from './UInt256'; import VarInt32Serializer from './VarInt32'; +export declare const int32: Int32Serializer; export declare const int64: Int64Serializer; export declare const uint8: UInt8Serializer; export declare const uint16: UInt16Serializer; @@ -18,6 +20,7 @@ export declare const varint32: VarInt32Serializer; export { IIntSerializer, + Int32Serializer, Int64Serializer, IUIntSerializer, UInt8Serializer, diff --git a/types/serializers/collections/Set.d.ts b/types/serializers/collections/Set.d.ts index 69b97c6e..836e7fec 100644 --- a/types/serializers/collections/Set.d.ts +++ b/types/serializers/collections/Set.d.ts @@ -5,7 +5,7 @@ import VectorSerializer from "./Vector"; type TInput = SerializerInput>[] | Set>> | undefined; -export default class SetSerializer extends VectorSerializer { +export default class SetSerializer extends VectorSerializer> { constructor(serializer: T); validate(value: TInput): void; serialize(value: TInput): Buffer; diff --git a/types/serializers/collections/Vector.d.ts b/types/serializers/collections/Vector.d.ts index f4e47cad..e7d605c2 100644 --- a/types/serializers/collections/Vector.d.ts +++ b/types/serializers/collections/Vector.d.ts @@ -4,10 +4,13 @@ import ISerializer, { SerializerInput, SerializerOutput } from "../ISerializer"; type TInput = SerializerInput[]; type TOutput = SerializerOutput[]; -export default class VectorSerializer extends ISerializer, TOutput> { +export default class VectorSerializer< + T extends ISerializer, + K extends any = TInput + > extends ISerializer> { readonly serializer: T; constructor(serializer: T); - toRaw(value: TInput): TOutput; - appendToByteBuffer(value: TInput, bytebuffer: ByteBuffer): void; + toRaw(value: K): TOutput; + appendToByteBuffer(value: K, bytebuffer: ByteBuffer): void; readFromBuffer(buffer: Buffer, offset?: number): { res: TOutput, newOffset: number }; } From bef7f7d36ae4369fabbeaa4b81ab003eff602173 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Tue, 10 Dec 2019 14:17:54 +0300 Subject: [PATCH 13/62] [ECHOJS-245] Fix TSDoc for `get_contract_logs` method --- echo@0.14.0-rc.1-migration.md | 1 + types/echo/api.d.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index 8e1f95ee..f611516f 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -21,3 +21,4 @@ * [ ] Tests * [ ] `get_contract_history` * [ ] `get_relative_contract_history` + * [ ] `get_contract_logs` diff --git a/types/echo/api.d.ts b/types/echo/api.d.ts index 52689a12..a742383d 100644 --- a/types/echo/api.d.ts +++ b/types/echo/api.d.ts @@ -129,6 +129,7 @@ export default class Api { * Get logs of specified contract logs filter options * @param contracts IDs of the contract * @param topics Filters by certain events if any provided + * @param blocks Contract logs filter options * @param blocks.from Number of block to start retrive from * @param blocks.to Number of block to end to retrive * @returns The contracts logs from specified blocks interval From fae4de9b5a52704862d0105bb64ce7229bba57cb Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Tue, 10 Dec 2019 14:26:27 +0300 Subject: [PATCH 14/62] [ECHOJS-245] Change type of argument in method `get_btc_address` from `account_id` to `string` --- echo@0.14.0-rc.1-migration.md | 1 + src/echo/ws-api/wallet-api.js | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index f611516f..d2f3b8ec 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -16,6 +16,7 @@ * [x] `get_contract_history` * [x] `get_relative_contract_history` * [x] Change arguments of `get_contract_logs` method and make it async +* [x] Change type of argument in method `get_btc_address` from `account_id` to `string` (may be account's id or name) * [ ] Update operations' id's in docs * [ ] Tests diff --git a/src/echo/ws-api/wallet-api.js b/src/echo/ws-api/wallet-api.js index 12b91223..17abc2be 100644 --- a/src/echo/ws-api/wallet-api.js +++ b/src/echo/ws-api/wallet-api.js @@ -1684,13 +1684,13 @@ class WalletAPI { /** * @method getBtcAddress - * @param {String} accountId - * @returns {Promise} + * @param {string} account + * @returns {Promise} */ - getBtcAddress(accountIdValue) { - if (!isAccountId(accountIdValue)) throw new Error('account should be valid'); + getBtcAddress(account) { + if (!isAccountId(account) || !isAccountName(account)) throw new Error('account should be valid'); - return this.wsRpc.call([0, 'get_btc_address', [accountIdValue]]); + return this.wsRpc.call([0, 'get_btc_address', [account]]); } /** From e2d2560716c9be900feaa7de025aa5913f7bdb32 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Tue, 10 Dec 2019 14:29:43 +0300 Subject: [PATCH 15/62] [ECHOJS-245] Rename wallet-api method `generate_eth_address` to `create_eth_address` --- echo@0.14.0-rc.1-migration.md | 3 ++- src/echo/ws-api/wallet-api.js | 4 ++-- test/wallet-api.test.js | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index d2f3b8ec..e7ae1137 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -16,7 +16,8 @@ * [x] `get_contract_history` * [x] `get_relative_contract_history` * [x] Change arguments of `get_contract_logs` method and make it async -* [x] Change type of argument in method `get_btc_address` from `account_id` to `string` (may be account's id or name) +* [x] Change type of argument in wallet-api method `get_btc_address` from `account_id` to `string` +* [x] Rename wallet-api method `generate_eth_address` to `create_eth_address` * [ ] Update operations' id's in docs * [ ] Tests diff --git a/src/echo/ws-api/wallet-api.js b/src/echo/ws-api/wallet-api.js index 17abc2be..2f5d5708 100644 --- a/src/echo/ws-api/wallet-api.js +++ b/src/echo/ws-api/wallet-api.js @@ -1052,11 +1052,11 @@ class WalletAPI { * @param {boolean} shouldDoBroadcastToNetwork true if you wish to broadcast the transaction * @returns {Promise} the signed version of the transaction */ - generateEthAddress(accountIdOrName, shouldDoBroadcastToNetwork) { + createEthAddress(accountIdOrName, shouldDoBroadcastToNetwork) { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'generate_eth_address', [ + return this.wsRpc.call([0, 'create_eth_address', [ string.toRaw(accountIdOrName), bool.toRaw(shouldDoBroadcastToNetwork), ]]); diff --git a/test/wallet-api.test.js b/test/wallet-api.test.js index 5a9f1b19..be4a9dbe 100644 --- a/test/wallet-api.test.js +++ b/test/wallet-api.test.js @@ -1009,9 +1009,9 @@ describe('WALLET API', () => { }).timeout(5000); }); - describe('#generateEthAddress()', () => { + describe('#createEthAddress()', () => { it('Should generate eth address', async () => { - const result = await echo.walletApi.generateEthAddress(accountId, shouldDoBroadcastToNetwork); + const result = await echo.walletApi.createEthAddress(accountId, shouldDoBroadcastToNetwork); expect(result) .to .be From 29b22fe68c9672bee59505d7872e2a2907743a27 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 23 Dec 2019 13:24:47 +0300 Subject: [PATCH 16/62] Rename `deposit_erc20_token_object` to `erc20_deposit_token_object` --- echo@0.14.0-rc.1-migration.md | 2 ++ src/constants/object-types.js | 4 ++-- types/interfaces/ProtocolObjectTypeId.d.ts | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index e7ae1137..39468fd8 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -18,7 +18,9 @@ * [x] Change arguments of `get_contract_logs` method and make it async * [x] Change type of argument in wallet-api method `get_btc_address` from `account_id` to `string` * [x] Rename wallet-api method `generate_eth_address` to `create_eth_address` +* [x] Rename `deposit_erc20_token_object` to `erc20_deposit_token_object` +* [ ] Update contract's logs' filter * [ ] Update operations' id's in docs * [ ] Tests * [ ] `get_contract_history` diff --git a/src/constants/object-types.js b/src/constants/object-types.js index 14c11bc1..78b15492 100644 --- a/src/constants/object-types.js +++ b/src/constants/object-types.js @@ -15,8 +15,8 @@ export const ETH_ADDRESS = 13; export const SIDECHAIN_ETH_DEPOSIT = 14; export const SIDECHAIN_ETH_WITHDRAW = 15; export const ERC20_TOKEN = 16; -export const SIDECHAIN_ERC20_DEPOSIT_TOKEN = 17; -export const SIDECHAIN_ERC20_WITHDRAW_TOKEN = 18; +export const ERC20_DEPOSIT_TOKEN = 17; +export const ERC20_WITHDRAW_TOKEN = 18; export const BTC_ADDRESS = 19; export const BTC_INTERMEDIATE_DEPOSIT = 20; export const BTC_DEPOSIT = 21; diff --git a/types/interfaces/ProtocolObjectTypeId.d.ts b/types/interfaces/ProtocolObjectTypeId.d.ts index 640ffe2f..b7fad93d 100644 --- a/types/interfaces/ProtocolObjectTypeId.d.ts +++ b/types/interfaces/ProtocolObjectTypeId.d.ts @@ -16,8 +16,8 @@ declare enum PROTOCOL_OBJECT_TYPE_ID { SIDECHAIN_ETH_DEPOSIT = 14, SIDECHAIN_ETH_WITHDRAW = 15, ERC20_TOKEN = 16, - SIDECHAIN_ERC20_DEPOSIT_TOKEN = 17, - SIDECHAIN_ERC20_WITHDRAW_TOKEN = 18, + ERC20_DEPOSIT_TOKEN = 17, + ERC20_WITHDRAW_TOKEN = 18, BTC_ADDRESS = 19, BTC_INTERMEDIATE_DEPOSIT = 20, BTC_DEPOSIT = 21, From 706d265cb8929005dfde6c38cf3f12006ac36e9a Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 23 Dec 2019 14:08:10 +0300 Subject: [PATCH 17/62] wallet-api's `create_contract` method receives `amount` argument as `number|string|BigNumber` instead of `uint64` --- echo@0.14.0-rc.1-migration.md | 2 ++ src/constants/chain/config.js | 2 ++ src/constants/chain/index.js | 4 ++++ src/constants/index.js | 2 ++ src/echo/ws-api/wallet-api.js | 15 ++++++++------- src/utils/validators.js | 17 ++++++++++++++++- types/constants/chain/config.d.ts | 1 + types/constants/chain/index.d.ts | 3 +++ types/constants/index.d.ts | 13 ++++++++++++- types/utils/validators.d.ts | 4 ++++ 10 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 src/constants/chain/config.js create mode 100644 src/constants/chain/index.js create mode 100644 types/constants/chain/config.d.ts create mode 100644 types/constants/chain/index.d.ts diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index 39468fd8..1913ba9d 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -19,6 +19,8 @@ * [x] Change type of argument in wallet-api method `get_btc_address` from `account_id` to `string` * [x] Rename wallet-api method `generate_eth_address` to `create_eth_address` * [x] Rename `deposit_erc20_token_object` to `erc20_deposit_token_object` +* [x] Rename `withdraw_erc20_token_object` to `erc20_withdraw_token_object` +* [x] wallet-api's `create_contract` method receives `amount` argument as `number|string|BigNumber` instead of `uint64` * [ ] Update contract's logs' filter * [ ] Update operations' id's in docs diff --git a/src/constants/chain/config.js b/src/constants/chain/config.js new file mode 100644 index 00000000..69283acd --- /dev/null +++ b/src/constants/chain/config.js @@ -0,0 +1,2 @@ +// eslint-disable-next-line import/prefer-default-export +export const ECHO_MAX_SHARE_SUPPLY = 1000000000000000; diff --git a/src/constants/chain/index.js b/src/constants/chain/index.js new file mode 100644 index 00000000..90b987eb --- /dev/null +++ b/src/constants/chain/index.js @@ -0,0 +1,4 @@ +import * as config from './config'; + +// eslint-disable-next-line import/prefer-default-export +export { config }; diff --git a/src/constants/index.js b/src/constants/index.js index ae76747d..5f1e30b7 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -2,6 +2,7 @@ import BigNumber from 'bignumber.js'; import * as API_CONFIG from './api-config'; import * as CACHE_MAPS from './cache-maps'; +import * as chain from './chain'; import * as CHAIN_CONFIG from './chain-config'; import * as CHAIN_TYPES from './chain-types'; import * as PROTOCOL_OBJECT_TYPE_ID from './object-types'; @@ -35,6 +36,7 @@ export const DEFAULT_MIN_CACHE_CLEANING_TIME = 500; /** @typedef {typeof OPERATIONS_IDS[keyof typeof OPERATIONS_IDS]} OperationId */ export { + chain, OPERATIONS_IDS, CACHE_MAPS, CHAIN_TYPES, diff --git a/src/echo/ws-api/wallet-api.js b/src/echo/ws-api/wallet-api.js index 2f5d5708..4351e4d2 100644 --- a/src/echo/ws-api/wallet-api.js +++ b/src/echo/ws-api/wallet-api.js @@ -20,6 +20,7 @@ import { isPublicKey, isUInt64, isCommitteeMemberId, + validateAmount, } from '../../utils/validators'; const { ethAddress, accountListing } = serializers.protocol; @@ -66,6 +67,7 @@ const { committeeMemberId, } = serializers.chain.ids.protocol; +/** @typedef {import("bignumber.js").BigNumber} BigNumber */ /** * @typedef {typeof import("../../serializers/transaction")['signedTransactionSerializer']} SignedTransactionSerializer */ @@ -455,7 +457,7 @@ class WalletAPI { * Upload/Create a contract. * @param {string} accountNameOrId name of the account creating the contract * @param {string} contractCode code of the contract - * @param {number} amount the amount of asset transferred to the contract + * @param {number|string|BigNumber} amount the amount of asset transferred to the contract * @param {string} assetType the type of the asset transferred to the contract * @param {string} supportedAssetId the asset that can be used to create/call the contract * (see https://echo-dev.io/developers/smart-contracts/solidity/introduction/#flag-of-supported-asset) @@ -464,7 +466,7 @@ class WalletAPI { * @param {boolean} shouldSaveToWallet whether to save the contract to the wallet * @returns {Promise} the signed transaction creating the contract */ - createContract( + async createContract( accountNameOrId, contractCode, amount, @@ -473,14 +475,13 @@ class WalletAPI { useEthereumAssetAccuracy, shouldSaveToWallet, ) { - if (!isAccountIdOrName(accountNameOrId)) { - return Promise.reject(new Error('Accounts id or name should be string and valid')); - } - if (!isContractCode(contractCode)) return Promise.reject(new Error('Byte code should be string and valid')); + if (!isAccountIdOrName(accountNameOrId)) throw new Error('Accounts id or name should be string and valid'); + if (!isContractCode(contractCode)) throw new Error('Byte code should be string and valid'); + amount = validateAmount(amount); return this.wsRpc.call([0, 'create_contract', [ string.toRaw(accountNameOrId), string.toRaw(contractCode), - uint64.toRaw(amount), + string.toRaw(amount), assetId.toRaw(assetType), assetId.toRaw(supportedAssetId), bool.toRaw(useEthereumAssetAccuracy), diff --git a/src/utils/validators.js b/src/utils/validators.js index 7b363a10..2100ea48 100644 --- a/src/utils/validators.js +++ b/src/utils/validators.js @@ -4,7 +4,7 @@ import bs58 from 'bs58'; import { ADDRESS_PREFIX, LENGTH_DECODE_PUBLIC_KEY, LENGTH_DECODE_PRIVATE_KEY } from '../config/chain-config'; import { CHAIN_APIS } from '../constants/ws-constants'; -import { PROTOCOL_OBJECT_TYPE_ID, CHAIN_TYPES, AMOUNT_MAX_NUMBER, ECHO_MAX_SHARE_SUPPLY } from '../constants'; +import { PROTOCOL_OBJECT_TYPE_ID, CHAIN_TYPES, AMOUNT_MAX_NUMBER, ECHO_MAX_SHARE_SUPPLY, chain } from '../constants'; import { walletAPIMethodsArray, operationPrototypeArray } from './methods-operations-data'; export function validateSafeInteger(value, fieldName) { @@ -360,3 +360,18 @@ export function validateSidechainType(v) { if (typeof v !== 'string') throw new Error('Type is not a string'); if (!['', 'eth', 'btc'].includes(v)) throw new Error(`Unsupported withdrawal type "${v}"`); } + +/** + * @param {number|BN|string} v + * @returns {string} + */ +export function validateAmount(v) { + if (typeof v === 'number' || typeof v === 'string') v = new BN(v); + if (!(v instanceof BN)) throw new Error('amount: invalid type'); + if (v.isNaN()) throw new Error('amount: not a number'); + const dp = v.dp(); + if (dp > 12) throw new Error('amont: invalid precision'); + const minSatoshis = v.times(`1e${dp.toString(10)}`).abs(); + if (minSatoshis > chain.config.ECHO_MAX_SHARE_SUPPLY) throw new Error('amount: overflow'); + return v.toString(10); +} diff --git a/types/constants/chain/config.d.ts b/types/constants/chain/config.d.ts new file mode 100644 index 00000000..157acc89 --- /dev/null +++ b/types/constants/chain/config.d.ts @@ -0,0 +1 @@ +export const ECHO_MAX_SHARE_SUPPLY = 1000000000000000; diff --git a/types/constants/chain/index.d.ts b/types/constants/chain/index.d.ts new file mode 100644 index 00000000..b95f0087 --- /dev/null +++ b/types/constants/chain/index.d.ts @@ -0,0 +1,3 @@ +import * as config from './config'; + +export { config }; diff --git a/types/constants/index.d.ts b/types/constants/index.d.ts index 30ce6d7e..953abc11 100644 --- a/types/constants/index.d.ts +++ b/types/constants/index.d.ts @@ -1,5 +1,6 @@ import * as API_CONFIG from './api-config'; import * as CACHE_MAPS from './cache-maps'; +import * as chain from './chain'; import * as CHAIN_CONFIG from './chain-config'; import * as CHAIN_TYPES from './chain-types'; import PROTOCOL_OBJECT_TYPE_ID = require('./object-types'); @@ -21,4 +22,14 @@ export const BITASSET_UPDATE: string; export const ECHO_ASSET_ID: string; export const DYNAMIC_GLOBAL_OBJECT_ID: string; -export { API_CONFIG, CACHE_MAPS, CHAIN_CONFIG, CHAIN_TYPES, PROTOCOL_OBJECT_TYPE_ID, WS_CONSTANTS, protocol, NET } +export { + chain, + API_CONFIG, + CACHE_MAPS, + CHAIN_CONFIG, + CHAIN_TYPES, + PROTOCOL_OBJECT_TYPE_ID, + WS_CONSTANTS, + protocol, + NET, +} diff --git a/types/utils/validators.d.ts b/types/utils/validators.d.ts index 4458ce11..edf438cc 100644 --- a/types/utils/validators.d.ts +++ b/types/utils/validators.d.ts @@ -1,3 +1,5 @@ +import BigNumber from "bignumber.js"; + export declare function validateUrl(value?: any): boolean; export declare function isString(value?: any): boolean; export declare function isEmpty(value?: any): boolean; @@ -58,3 +60,5 @@ export declare function checkAccountName(value?: any): boolean; export declare function checkCheapName(value?: any): boolean; export declare function validateOptionsError(value?: any): boolean; export declare function isTimePointSec(value?: any): boolean; + +export declare function validateAmount(value: number|BigNumber|string): string; From 9084cb7ef0c2cf1b6df828fb56d449fe536d9ef1 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 23 Dec 2019 14:11:15 +0300 Subject: [PATCH 18/62] wallet-api's `call_contract` method receives `amount` argument as `number|string|BigNumber` instead of `uint64` --- echo@0.14.0-rc.1-migration.md | 1 + src/echo/ws-api/wallet-api.js | 13 ++++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index 1913ba9d..ac0888b5 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -21,6 +21,7 @@ * [x] Rename `deposit_erc20_token_object` to `erc20_deposit_token_object` * [x] Rename `withdraw_erc20_token_object` to `erc20_withdraw_token_object` * [x] wallet-api's `create_contract` method receives `amount` argument as `number|string|BigNumber` instead of `uint64` +* [x] wallet-api's `call_contract` method receives `amount` argument as `number|string|BigNumber` instead of `uint64` * [ ] Update contract's logs' filter * [ ] Update operations' id's in docs diff --git a/src/echo/ws-api/wallet-api.js b/src/echo/ws-api/wallet-api.js index 4351e4d2..bb281034 100644 --- a/src/echo/ws-api/wallet-api.js +++ b/src/echo/ws-api/wallet-api.js @@ -494,12 +494,12 @@ class WalletAPI { * @param {string} accountNameOrId name of the account calling the contract * @param {string} idOfContract the id of the contract to call * @param {string} contractCode the hash of the method to call - * @param {number} amount the amount of asset transferred to the contract + * @param {number|BigNumber|string} amount the amount of asset transferred to the contract * @param {string} assetType the type of the asset transferred to the contract * @param {boolean} shouldSaveToWallet whether to save the contract call to the wallet * @returns {Promise} the signed transaction calling the contract */ - callContract( + async callContract( accountNameOrId, idOfContract, contractCode, @@ -507,15 +507,14 @@ class WalletAPI { assetType, shouldSaveToWallet, ) { - if (!isAccountIdOrName(accountNameOrId)) { - return Promise.reject(new Error('Accounts id or name should be string and valid')); - } - if (!isContractCode(contractCode)) return Promise.reject(new Error('Byte code should be string and valid')); + if (!isAccountIdOrName(accountNameOrId)) throw new Error('Accounts id or name should be string and valid'); + if (!isContractCode(contractCode)) throw new Error('Byte code should be string and valid'); + amount = validateAmount(amount); return this.wsRpc.call([0, 'call_contract', [ string.toRaw(accountNameOrId), contractId.toRaw(idOfContract), string.toRaw(contractCode), - uint64.toRaw(amount), + string.toRaw(amount), assetId.toRaw(assetType), bool.toRaw(shouldSaveToWallet), ]]); From 2e41b12b08a1921fc5474b75e8a418035d0b859d Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 23 Dec 2019 14:46:32 +0300 Subject: [PATCH 19/62] Remove field from --- echo@0.14.0-rc.1-migration.md | 1 + types/serializers/protocol/chain_parameters.d.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index ac0888b5..9f8a0547 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -22,6 +22,7 @@ * [x] Rename `withdraw_erc20_token_object` to `erc20_withdraw_token_object` * [x] wallet-api's `create_contract` method receives `amount` argument as `number|string|BigNumber` instead of `uint64` * [x] wallet-api's `call_contract` method receives `amount` argument as `number|string|BigNumber` instead of `uint64` +* [x] Remove field `min_btc_deposit_withdrawal` from `sidechain_config` * [ ] Update contract's logs' filter * [ ] Update operations' id's in docs diff --git a/types/serializers/protocol/chain_parameters.d.ts b/types/serializers/protocol/chain_parameters.d.ts index ca530c4b..39624c77 100644 --- a/types/serializers/protocol/chain_parameters.d.ts +++ b/types/serializers/protocol/chain_parameters.d.ts @@ -29,7 +29,7 @@ declare const chainParametersSerializer: StructSerializer<{ block_producer_reward_ratio: typeof uint16, committee_frozen_balance_to_activate: typeof uint64, committee_maintenance_intervals_to_deposit: typeof uint64, - committee_freeze_duration_seconds: typeof uint32, + committee_balance_unfreeze_duration_seconds: typeof uint32, x86_64_maximum_contract_size: typeof uint64, extensions: typeof extensions, }>; From bd6bf3f68f94666fa44d5f8533a2a84c5719a38f Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 23 Dec 2019 14:47:14 +0300 Subject: [PATCH 20/62] Remove field `immutable_parameters` from `chain_property_object` --- echo@0.14.0-rc.1-migration.md | 1 + types/interfaces/ChainProperties.d.ts | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index 9f8a0547..cc7f0ee9 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -23,6 +23,7 @@ * [x] wallet-api's `create_contract` method receives `amount` argument as `number|string|BigNumber` instead of `uint64` * [x] wallet-api's `call_contract` method receives `amount` argument as `number|string|BigNumber` instead of `uint64` * [x] Remove field `min_btc_deposit_withdrawal` from `sidechain_config` +* [ ] Remove field `immutable_parameters` from `chain_property_object` * [ ] Update contract's logs' filter * [ ] Update operations' id's in docs diff --git a/types/interfaces/ChainProperties.d.ts b/types/interfaces/ChainProperties.d.ts index 51d70a24..86b6ee21 100644 --- a/types/interfaces/ChainProperties.d.ts +++ b/types/interfaces/ChainProperties.d.ts @@ -1,7 +1,4 @@ export default interface ChainProperties { id: string, chain_id: string, - immutable_parameters:{ - min_committee_member_count: number - } } From 8b09b477a261e95ecab3deef3f231e4b531e4ebf Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 23 Dec 2019 14:49:06 +0300 Subject: [PATCH 21/62] Remove method `get_block_rewards` from `database-api` --- docs/API.md | 3 --- echo@0.14.0-rc.1-migration.md | 3 ++- src/echo/api.js | 12 ------------ src/echo/ws-api/database-api.js | 9 --------- types/echo/api.d.ts | 1 - 5 files changed, 2 insertions(+), 26 deletions(-) diff --git a/docs/API.md b/docs/API.md index 6fa28d85..d9109eaa 100644 --- a/docs/API.md +++ b/docs/API.md @@ -981,9 +981,6 @@ try { { id:String, chain_id:String, - immutable_parameters:{ - min_committee_member_count:Number - } } ``` diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index cc7f0ee9..91805aaf 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -23,7 +23,8 @@ * [x] wallet-api's `create_contract` method receives `amount` argument as `number|string|BigNumber` instead of `uint64` * [x] wallet-api's `call_contract` method receives `amount` argument as `number|string|BigNumber` instead of `uint64` * [x] Remove field `min_btc_deposit_withdrawal` from `sidechain_config` -* [ ] Remove field `immutable_parameters` from `chain_property_object` +* [x] Remove field `immutable_parameters` from `chain_property_object` +* [x] Remove method `get_block_rewards` from `database-api` * [ ] Update contract's logs' filter * [ ] Update operations' id's in docs diff --git a/src/echo/api.js b/src/echo/api.js index 07e0ba40..580b1962 100644 --- a/src/echo/api.js +++ b/src/echo/api.js @@ -114,9 +114,6 @@ import { PublicKey } from '../crypto'; * { * id:String, * chain_id:String, -* immutable_parameters:{ -* min_committee_member_count:Number -* } * } * } ChainProperties */ @@ -2457,15 +2454,6 @@ class API { return this.wsApi.database.getBalanceObjects(keys); } - /** - * @method getBlockRewards - * @param {typeof uint32["__TInput__"]} blockNum - * @returns {Promise} - */ - getBlockRewards(blockNum) { - return this.wsApi.database.getBlockRewards(basic.integers.uint32.toRaw(blockNum)); - } - /** * * @param {Number} blockNum diff --git a/src/echo/ws-api/database-api.js b/src/echo/ws-api/database-api.js index b7487301..7920bd13 100644 --- a/src/echo/ws-api/database-api.js +++ b/src/echo/ws-api/database-api.js @@ -630,15 +630,6 @@ class DatabaseAPI { return this.db.exec('get_balance_objects', [keys]); } - /** - * @method getBlockRewards - * @param {number} blockNum - * @returns {Promise} - */ - getBlockRewards(blockNum) { - return this.db.exec('get_block_rewards', [blockNum]); - } - /** * @method getBlockVirtualOperations * diff --git a/types/echo/api.d.ts b/types/echo/api.d.ts index a742383d..3415e28b 100644 --- a/types/echo/api.d.ts +++ b/types/echo/api.d.ts @@ -79,7 +79,6 @@ export default class Api { getBitAssetData(bitAssetId: string, force?: boolean): Promise; getBlock(blockNum: number): Promise; getBlockHeader(blockNum: number): Promise; - getBlockRewards(blockNum: typeof uint32["__TInput__"]): Promise; getBlockVirtualOperations(blockNum: number): any; getBtcAddress(accountId: string): Promise>; getAccountAddresses(accountId: string, from: number, limit: number): Promise>; From ace3c3638d2d29b86a3eabf3e2fc1211e23ce3c8 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 23 Dec 2019 15:12:06 +0300 Subject: [PATCH 22/62] Fix tests --- .test/docker-compose.yml | 6 +++--- .test/genesis.json | 3 +-- src/serializers/chain/id/protocol.js | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.test/docker-compose.yml b/.test/docker-compose.yml index 8dd69e8d..67a9d1b5 100644 --- a/.test/docker-compose.yml +++ b/.test/docker-compose.yml @@ -2,7 +2,7 @@ version: "2" services: echo: - image: echoprotocol/echo:0.13.1-rc.1 + image: echoprotocol/echo:0.14.0-rc.0 command: --start-echorand --account-info="[\"1.2.6\", \"5KkYp8qdQBaRmLqLz8WVrGjzkt7E13qVcr7cpdLowgJ1mjRyDx2\"]" @@ -24,11 +24,11 @@ services: container_name: echo echo-wallet: - image: echoprotocol/echo-wallet:0.13.1-rc.1 + image: echoprotocol/echo-wallet:0.14.0-rc.0 container_name: echo-wallet command: -s ws://echo:6311 - --chain-id="07ca945b10c3fa918529cff3e7baaefa87d28877f9d9bb6aad5b54d6ade35a98" + --chain-id="1bfd3ec560c0b31ec0dc7da6d4d012ea7f58565cd9121241ac71e1c7499dccc1" --wallet-file="/echo/walletdata/wallet.json" --history-file="/echo/walletdata/history" -r 0.0.0.0:6312 diff --git a/.test/genesis.json b/.test/genesis.json index 2efd3338..1ffa2c1b 100644 --- a/.test/genesis.json +++ b/.test/genesis.json @@ -217,6 +217,5 @@ "eth_address": "298915A83Bd8a0D536aDBe300F12cA1e4388C3BA", "btc_public_key": "02c16e97132e72738c9c0163656348cd1be03521de17efeb07e496e742ac84512e" }], - "initial_chain_id": "aa34045518f1469a28fa4578240d5f039afa9959c0b95ce3b39674efa691fb21", - "immutable_parameters": { "min_committee_member_count": 5 } + "initial_chain_id": "aa34045518f1469a28fa4578240d5f039afa9959c0b95ce3b39674efa691fb21" } diff --git a/src/serializers/chain/id/protocol.js b/src/serializers/chain/id/protocol.js index 69fe9d49..113a1102 100644 --- a/src/serializers/chain/id/protocol.js +++ b/src/serializers/chain/id/protocol.js @@ -30,11 +30,11 @@ export const ethWithdrawId = new ObjectIdSerializer( export const erc20TokenId = new ObjectIdSerializer(RESERVED_SPACE_ID.PROTOCOL, PROTOCOL_OBJECT_TYPE_ID.ERC20_TOKEN); export const depositErc20TokenId = new ObjectIdSerializer( RESERVED_SPACE_ID.PROTOCOL, - PROTOCOL_OBJECT_TYPE_ID.SIDECHAIN_ERC20_DEPOSIT_TOKEN, + PROTOCOL_OBJECT_TYPE_ID.ERC20_DEPOSIT_TOKEN, ); export const withdrawErc20TokenId = new ObjectIdSerializer( RESERVED_SPACE_ID.PROTOCOL, - PROTOCOL_OBJECT_TYPE_ID.SIDECHAIN_ERC20_WITHDRAW_TOKEN, + PROTOCOL_OBJECT_TYPE_ID.ERC20_WITHDRAW_TOKEN, ); export const btcAddressId = new ObjectIdSerializer(RESERVED_SPACE_ID.PROTOCOL, PROTOCOL_OBJECT_TYPE_ID.BTC_ADDRESS); export const btcIntermediateDepositId = new ObjectIdSerializer( From f089566897c97d6085bffad01755bb15c60ac3e6 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 23 Dec 2019 18:17:58 +0300 Subject: [PATCH 23/62] Fix `get_contract_logs` filter object && Add test for `get_contract_logs` method --- src/echo/api.js | 33 +-- src/serializers/collections/Set.js | 8 +- src/serializers/collections/Vector.js | 6 +- test/_test-utils.js | 5 + test/api/database/get-contract-logs2.test.js | 234 ++++++++++++++++--- types/echo/api.d.ts | 23 +- 6 files changed, 251 insertions(+), 58 deletions(-) diff --git a/src/echo/api.js b/src/echo/api.js index 580b1962..f8d699c2 100644 --- a/src/echo/api.js +++ b/src/echo/api.js @@ -1,4 +1,5 @@ /* eslint-disable no-continue,no-await-in-loop,camelcase,no-restricted-syntax */ +import * as assert from 'assert'; import { Map, List, fromJS } from 'immutable'; import { @@ -1933,28 +1934,34 @@ class API { } /** - * @param {Set_t} contracts - * @param {Array>} topics - * @param {Object} [blocks] - * @param {Integer_t} [blocks.from] - * @param {Integer_t} [blocks.to] + * @param {Object} [opts] + * @param {Set_t} [opts.contracts] + * @param {Array>} [opts.topics] + * @param {Integer_t} [opts.fromBlock] + * @param {Integer_t} [opts.toBlock] * @returns {Promise} */ - async getContractLogs(contracts, topics, blocks = {}) { + async getContractLogs(opts = {}) { /** @type {string[]} */ - const contractsList = collections.set(chain.ids.protocol.contractId).toRaw(contracts); + const contractsList = opts.contracts === undefined ? undefined : + collections.set(chain.ids.protocol.contractId).toRaw(opts.contracts, 'contracts'); /** @type {Array} */ - const topicsList = collections.vector(collections.set(basic.string)).toRaw(topics); - const from = blocks.from === undefined ? undefined : basic.integers.int32.toRaw(blocks.from); - const to = blocks.to === undefined ? undefined : basic.integers.int32.toRaw(blocks.to); - if (from !== undefined && from < 0) throw new Error('`blocks.from` must be greater than or equal to zero'); - if (to !== undefined && to <= 0) throw new Error('`blocks.to` must be greater than zero'); + const topicsList = opts.topics === undefined ? undefined : + collections.vector(collections.set(basic.string)).toRaw(opts.topics, '`topics`'); + const from = opts.fromBlock === undefined ? undefined : basic.integers.int32.toRaw(opts.fromBlock, 'fromBlock'); + const to = opts.toBlock === undefined ? undefined : basic.integers.int32.toRaw(opts.toBlock, 'toBlock'); + if (from !== undefined && from < 0) throw new Error('`fromBlock` must be greater than or equal to zero'); + if (to !== undefined && to <= 0) throw new Error('`toBlock` must be greater than zero'); return new Promise((resolve) => this.wsApi.database.getContractLogs((res) => resolve(res), { contracts: contractsList, topics: topicsList, from_block: from, to_block: to, - })); + })).then((res) => { + assert.ok(Array.isArray(res)); + assert.strictEqual(res.length, 1); + return res[0]; + }); } /** diff --git a/src/serializers/collections/Set.js b/src/serializers/collections/Set.js index 3273b973..ab61a905 100644 --- a/src/serializers/collections/Set.js +++ b/src/serializers/collections/Set.js @@ -1,3 +1,4 @@ +import { ok } from 'assert'; import VectorSerializer from './Vector'; /** @typedef {import("bytebuffer")} ByteBuffer */ @@ -27,7 +28,8 @@ export default class SetSerializer extends VectorSerializer { * @param {TInput} value * @returns {SerializerOutput>} */ - toRaw(value) { + toRaw(value, errorField = 'set') { + ok(typeof errorField === 'string'); if (value === undefined) value = []; if (value instanceof Set) value = [...value]; /** @type {ReturnType['toRaw']>} */ @@ -35,7 +37,7 @@ export default class SetSerializer extends VectorSerializer { try { raw = super.toRaw(value); } catch (error) { - throw new Error(`set: ${error.message}`); + throw new Error(`${errorField}: ${error.message}`); } /** @type {string[]} */ const serializedElements = new Array(raw.length); @@ -43,7 +45,7 @@ export default class SetSerializer extends VectorSerializer { serializedElements[i] = this.serializer.serialize(raw[i]).toString('hex'); for (let j = 0; j < i; j += 1) { if (serializedElements[i] === serializedElements[j]) { - throw new Error(`set element with index ${i} is equals to the other one with index ${j}`); + throw new Error(`${errorField} element with index ${i} is equals to the other one with index ${j}`); } } } diff --git a/src/serializers/collections/Vector.js b/src/serializers/collections/Vector.js index b4177fc6..ae53ace3 100644 --- a/src/serializers/collections/Vector.js +++ b/src/serializers/collections/Vector.js @@ -45,15 +45,15 @@ export default class VectorSerializer extends ISerializer { * @param {TInput} value * @returns {TOutput} */ - toRaw(value) { - if (!Array.isArray(value)) throw new Error('value is not an array'); + toRaw(value, errorField = 'vector') { + if (!Array.isArray(value)) throw new Error(`${errorField} is not an array`); const raw = new Array(value.length); for (let i = 0; i < value.length; i += 1) { try { const element = value[i]; raw[i] = this.serializer.toRaw(element); } catch (error) { - throw new Error(`vector element with index ${i}: ${error.message}`); + throw new Error(`${errorField} element with index ${i}: ${error.message}`); } } return raw; diff --git a/test/_test-utils.js b/test/_test-utils.js index 8c92bf29..f03dca9f 100644 --- a/test/_test-utils.js +++ b/test/_test-utils.js @@ -43,3 +43,8 @@ export function getRandomAssetSymbol() { const result = String.fromCharCode(...charCodes); return result; } + +/** + * @template T + * @typedef {T extends Promise ? U : T} UnPromisify + */ diff --git a/test/api/database/get-contract-logs2.test.js b/test/api/database/get-contract-logs2.test.js index c09d09ee..b01e5a52 100644 --- a/test/api/database/get-contract-logs2.test.js +++ b/test/api/database/get-contract-logs2.test.js @@ -1,30 +1,45 @@ -import { Echo, OPERATIONS_IDS } from "../../.."; +import * as assert from "assert"; +import { Echo, OPERATIONS_IDS, BigNumber } from "../../.."; import { url, accountId, privateKey } from "../../_test-data"; -import { inspect } from "util"; -import { ok, deepStrictEqual } from "assert"; +import { shouldReject } from "../../_test-utils"; + +/** + * @template T + * @typedef {import("../../_test-utils").UnPromisify} UnPromisify + */ /* - * pragma solidity ^0.4.24; - * contract Qwe { - * event Test(uint256 indexed indexedField, uint256 nonIndexedField); - * function test(uint256 indexedField, uint256 nonIndexedField) public { emit Test(indexedField, nonIndexedField); } + * pragma solidity ^0.4.23; + * + * contract Emitter { + * event Event1(uint256 indexed indexedField, uint256 nonIndexedField); + * event Event2(uint256 indexed indexedField, uint256 nonIndexedField); + * function emit1(uint256 indexedField, uint256 nonIndexedField) public { + * emit Event1(indexedField, nonIndexedField); + * } + * function emit2(uint256 indexedField, uint256 nonIndexedField) public { + * emit Event2(indexedField, nonIndexedField); + * } * } */ const bytecode = [ - "608060405234801561001057600080fd5b5060e08061001f6000396000f300608060405260043610603f576000357c010000000000000000", - "0000000000000000000000000000000000000000900463ffffffff168063eb8ac921146044575b600080fd5b348015604f57600080fd5b50", - "607660048036038101908080359060200190929190803590602001909291905050506078565b005b817f91916a5e2c96453ddf6b58549726", - "2675140eb9f7a774095fb003d93e6dc69216826040518082815260200191505060405180910390a250505600a165627a7a7230582085d4cd", - "c749b60050d7df224ded452a41549e1880caf023c417b9e1aca69645670029", + "608060405234801561001057600080fd5b50610163806100206000396000f30060806040526004361061004c576000357c010000000000000", + "0000000000000000000000000000000000000000000900463ffffffff168063156d44ef146100515780631baea0ab14610088575b600080fd", + "5b34801561005d57600080fd5b5061008660048036038101908080359060200190929190803590602001909291905050506100bf565b005b3", + "4801561009457600080fd5b506100bd60048036038101908080359060200190929190803590602001909291905050506100fb565b005b817f", + "d3610b1c54575b7f4f0dc03d210b8ac55624ae007679b7a928a4f25a709331a8826040518082815260200191505060405180910390a250505", + "65b817f6a822560072e19c1981d3d3bb11e5954a77efa0caf306eb08d053f37de0040ba826040518082815260200191505060405180910390", + "a250505600a165627a7a72305820fddab02616eb79d169bffcec273868d1795db6ede88d13a007343987fa332a370029", ].join(""); +const emit1 = "156d44ef"; +const emit2 = "1baea0ab"; + describe("getContractLogs", () => { const echo = new Echo(); - /** @type {string} */ - let contractId; - before(async function () { - this.timeout(12e3); - await echo.connect(url); + + /** @returns {Promise} */ + async function deploy() { const txRes = await echo.createTransaction().addOperation(OPERATIONS_IDS.CONTRACT_CREATE, { registrar: accountId, value: { amount: 0, asset_id: "1.3.0" }, @@ -35,19 +50,180 @@ describe("getContractLogs", () => { /** @type {string} */ const opResId = txRes[0].trx.operation_results[0][1]; const opRes = await echo.api.getObject(opResId); - contractId = opRes.contracts_id[0]; - ok(contractId !== undefined); - }); - describe("when options are not provided", () => { - /** @type {[]} */ - let result; - it("should not rejects", async () => { - result = await echo.api.getContractLogs(); - ok(result !== undefined); + const contractId = opRes.contracts_id[0]; + assert.ok(contractId !== undefined); + return contractId; + } + + /** + * @param {string} contractId + * @param {string} methodSignature + * @param {number} indexed + * @param {number} notIndexed + */ + async function emit(contractId, methodSignature, indexed, notIndexed) { + assert.ok(indexed >= 0); + assert.ok(notIndexed >= 0); + assert.ok(Number.isSafeInteger(indexed)); + assert.ok(Number.isSafeInteger(notIndexed)); + await echo.createTransaction().addOperation(OPERATIONS_IDS.CONTRACT_CALL, { + registrar: accountId, + value: { amount: 0, asset_id: '1.3.0' }, + code: [ + methodSignature, + indexed.toString(16).padStart(64, '0'), + notIndexed.toString(16).padStart(64, '0'), + ].join(''), + callee: contractId, + extensions: [], + }).addSigner(privateKey).broadcast(); + } + + before(async () => await echo.connect(url)); + after(async () => await echo.disconnect()); + + describe('when `contracts` is not an `set_t`', () => { + shouldReject(async () => { + await echo.api.getContractLogs({ contracts: 'not an array' }); + }, 'contracts: vector is not an array'); + }); + + describe('when `contracts` has duplicates', () => { + shouldReject( + async () => await echo.api.getContractLogs({ contracts: ['1.11.1', '1.11.1'] }), + 'contracts element with index 1 is equals to the other one with index 0', + 'with indexes of duplicated elements', + ); + }); + + describe('when `contracts` first element is not a contract id', () => { + shouldReject(async () => { + await echo.api.getContractLogs({ contracts: ['1.10.1'] }); + }, 'contracts: vector element with index 0: invalid object type id'); + }); + + describe('when `topics` is not an `set_t`', () => { + shouldReject(async () => { + await echo.api.getContractLogs({ topics: 'not an array' }); + }, '`topics` is not an array'); + }); + + describe('when `fromBlock` is negative', () => { + shouldReject(async () => { + await echo.api.getContractLogs({ fromBlock: -1 }); + }, '`fromBlock` must be greater than or equal to zero'); + }); + + describe('when `toBlock` is negative', () => { + shouldReject(async () => { + await echo.api.getContractLogs({ toBlock: -1 }); + }, '`toBlock` must be greater than zero'); + }); + + describe('when `toBlock` is equals to zero', () => { + shouldReject(async () => { + await echo.api.getContractLogs({ toBlock: 0 }); + }, '`toBlock` must be greater than zero'); + }); + + describe('when different events are emitted in different blocks', () => { + /** @type {string} */ + let contractId; + /** @type {string} */ + let contractAddress; + before(async function () { + this.timeout(25e3); + contractId = await deploy(); + contractAddress = `01${new BigNumber(contractId.split('.')[2]).toString(16).padStart(38, '0')}`; + await emit(contractId, emit1, 123, 234); + await emit(contractId, emit2, 345, 456); + }); + describe('when no filter provided', () => { + /** @type {UnPromisify>} */ + let res; + it('should succeed', async () => { + res = await echo.api.getContractLogs(); + assert.ok(res !== undefined); + }); + it('should return array', function () { + if (res === undefined) this.skip(); + assert.ok(Array.isArray(res)); + }); + /** @type {typeof res} */ + let events; + it('with length greater than or equals to 2', function () { + if (res === undefined || !Array.isArray(res)) this.skip(); + assert.ok(res.length >= 2); + events = res.slice(res.length - 2); + }); + it('with all logs of contract', function () { + if (events === undefined) this.skip(); + assert.ok(events.every(([_, { address }]) => address === contractAddress)); + }); + it('with different blocks', function () { + if (events === undefined) this.skip(); + assert.ok(events[0][1].block_num !== events[1][1].block_num); + }); }); - it("should return empty array", function () { - if (result === undefined) this.skip(); - else deepStrictEqual(result, []); + describe('when there are another contract with the same logs', () => { + /** @type {string} */ + let anotherContractId; + /** @type {string} */ + let anotherContractAddress; + before(async function () { + this.timeout(30e3); + anotherContractId = await deploy(); + const anotherContractInstanceIndex = new BigNumber(anotherContractId.split('.')[2]); + anotherContractAddress = `01${anotherContractInstanceIndex.toString(16).padStart(38, '0')}`; + await emit(anotherContractId, emit1, 123, 234); + await emit(anotherContractId, emit2, 345, 456); + }); + describe('when first contract provided in `contracts` filter', () => { + /** @type {UnPromisify>} */ + let res; + it('should succeed', async () => { + res = await echo.api.getContractLogs({ contracts: [contractId] }); + assert.ok(res !== undefined); + }); + it('should return array', function () { + if (res === undefined) this.skip(); + assert.ok(Array.isArray(res)); + }); + it('with length equals to 2', function () { + if (res === undefined || !Array.isArray(res)) this.skip(); + assert.strictEqual(res.length, 2); + }); + it('with all logs of contract', function () { + if (res === undefined || !Array.isArray(res) || res.length < 2) this.skip(); + assert.ok(res.every(([_, { address }]) => address === contractAddress)); + }); + it('with different blocks', function () { + if (res === undefined || !Array.isArray(res) || res.length < 2) this.skip(); + assert.ok(res[0][1].block_num !== res[1][1].block_num); + }); + }); + describe('when both contracts are provided in `contracts` filter', () => { + /** @type {UnPromisify>} */ + let res; + it('should succeed', async () => { + res = await echo.api.getContractLogs({ contracts: [contractId, anotherContractId] }); + assert.ok(res !== undefined); + }); + it('should return array', function () { + if (res === undefined) this.skip(); + assert.ok(Array.isArray(res)); + }); + it('with length equals to 4', function () { + if (res === undefined || !Array.isArray(res)) this.skip(); + assert.strictEqual(res.length, 4); + }); + it('with all logs of both contracts', function () { + if (res === undefined || !Array.isArray(res) || res.length < 4) this.skip(); + assert.deepStrictEqual(res.map(([_, { address }]) => { + return address; + }), [contractAddress, contractAddress, anotherContractAddress, anotherContractAddress]); + }); + }); }); }); }); diff --git a/types/echo/api.d.ts b/types/echo/api.d.ts index 3415e28b..006e176c 100644 --- a/types/echo/api.d.ts +++ b/types/echo/api.d.ts @@ -36,6 +36,17 @@ import { VectorSerializer, SetSerializer } from '../serializers/collections'; type SidechainType = "" | "eth" | "btc"; +interface ContractLogsFilterOptions { + /** IDs of the contract */ + contracts?: SetSerializer["__TInput__"], + /** Filters by certain events if any provided */ + topics?: VectorSerializer>["__TInput__"], + /** Number of block to start retrieve from */ + fromBlock?: typeof int32["__TInput__"], + /** Number of block to end to retrieve */ + toBlock?: typeof int32["__TInput__"], +} + export default class Api { broadcastTransaction(tr: Object): Promise; broadcastTransactionWithCallback(signedTransactionObject: Object, wasBroadcastedCallback?: () => any): Promise; @@ -126,18 +137,10 @@ export default class Api { /** * Get logs of specified contract logs filter options - * @param contracts IDs of the contract - * @param topics Filters by certain events if any provided - * @param blocks Contract logs filter options - * @param blocks.from Number of block to start retrive from - * @param blocks.to Number of block to end to retrive + * @param opts Contract logs filter options (see {@link ContractLogsFilterOptions}) * @returns The contracts logs from specified blocks interval */ - getContractLogs( - contracts: SetSerializer["__TInput__"], - topics: VectorSerializer>["__TInput__"], - blocks?: { from?: typeof int32["__TInput__"], to?: typeof int32["__TInput__"] }, - ): Promise; + getContractLogs(opts?: ContractLogsFilterOptions): Promise; getContractLogs1(opts: { contracts?: string[], From 13656588162b52e455b297164180be3af111637f Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 23 Dec 2019 18:19:07 +0300 Subject: [PATCH 24/62] Check migration subtusks --- echo@0.14.0-rc.1-migration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index 91805aaf..e12522e8 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -26,9 +26,9 @@ * [x] Remove field `immutable_parameters` from `chain_property_object` * [x] Remove method `get_block_rewards` from `database-api` -* [ ] Update contract's logs' filter +* [x] Update contract's logs' filter * [ ] Update operations' id's in docs * [ ] Tests * [ ] `get_contract_history` * [ ] `get_relative_contract_history` - * [ ] `get_contract_logs` + * [x] `get_contract_logs` From 303128c3ac2f05f1cb016317e64470cfd2e6a358 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Tue, 24 Dec 2019 12:37:17 +0300 Subject: [PATCH 25/62] v1.10.0-rc.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5d8d4d9d..1a5cb006 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "echojs-lib", - "version": "1.9.8", + "version": "1.10.0-rc.0", "description": "Pure JavaScript ECHO library for node.js", "main": "./dist/index.js", "types": "./types/index.d.ts", From 37db2ff009a8d9b643c7f48341dc864655b0e3a9 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Thu, 26 Dec 2019 12:19:51 +0300 Subject: [PATCH 26/62] Update the contracts logs subscription filter --- .test/docker-compose.yml | 2 +- echo@0.14.0-rc.1-migration.md | 2 +- src/echo/api.js | 48 ++++------ src/echo/subscriber.js | 92 ++----------------- src/echo/ws-api/database-api.js | 19 +--- src/echo/ws/reconnection-websocket.js | 22 ++--- src/utils/converters.js | 47 ++++++++++ test/_event-emitter-contract.js | 80 ++++++++++++++++ ...ogs2.test.js => get-contract-logs.test.js} | 81 ++-------------- .../database/subscribe-contract-logs.test.js | 43 +++++++++ test/api/index.api.test.js | 3 +- test/subscriber.test.js | 18 ---- types/echo/api.d.ts | 15 +-- types/echo/subscriber.d.ts | 4 + types/echo/transaction.d.ts | 2 + 15 files changed, 236 insertions(+), 242 deletions(-) create mode 100644 test/_event-emitter-contract.js rename test/api/database/{get-contract-logs2.test.js => get-contract-logs.test.js} (65%) create mode 100644 test/api/database/subscribe-contract-logs.test.js diff --git a/.test/docker-compose.yml b/.test/docker-compose.yml index 67a9d1b5..6093cf02 100644 --- a/.test/docker-compose.yml +++ b/.test/docker-compose.yml @@ -28,7 +28,7 @@ services: container_name: echo-wallet command: -s ws://echo:6311 - --chain-id="1bfd3ec560c0b31ec0dc7da6d4d012ea7f58565cd9121241ac71e1c7499dccc1" + --chain-id="57f470d68dd10064f5a7fb5bd79d91d48ecfcfdff3243ff55b1173fd0404bfba" --wallet-file="/echo/walletdata/wallet.json" --history-file="/echo/walletdata/history" -r 0.0.0.0:6312 diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md index e12522e8..99c5d160 100644 --- a/echo@0.14.0-rc.1-migration.md +++ b/echo@0.14.0-rc.1-migration.md @@ -1,7 +1,7 @@ * [x] Add field `btc_block_number` to `sidechain_btc_aggregate_operation` and `btc_aggregating_object` * [x] Add fields `btc_deposit_withdrawal_min`, `btc_deposit_withdrawal_fee` to `sidechain_config` * [ ] Update contract subscription - * [ ] Update the contracts logs subscription filter + * [x] Update the contracts logs subscription filter * [ ] Add method `unsubscribe_contract_logs` in database API * [ ] Bitcoin key to configure-keys * [x] Implement 24 hours delay for deposit and withdrawal processing in Ethereum sidechain diff --git a/src/echo/api.js b/src/echo/api.js index f8d699c2..16274530 100644 --- a/src/echo/api.js +++ b/src/echo/api.js @@ -36,20 +36,14 @@ import { solveRegistrationTask, validateRegistrationOptions } from '../utils/pow /** @typedef {import('./ws-api').default} WSAPI */ import { ECHO_ASSET_ID, DYNAMIC_GLOBAL_OBJECT_ID, API_CONFIG, CACHE_MAPS } from '../constants'; -import { transaction, signedTransaction, operation, basic, chain, collections } from '../serializers'; +import { transaction, signedTransaction, operation, basic, chain } from '../serializers'; import { PublicKey } from '../crypto'; +import { toRawContractLogsFilterOptions } from '../utils/converters'; /** @typedef {import("bignumber.js").default} BigNumber */ /** @typedef {import("../../types/interfaces/vm/types").Log} Log */ /** @typedef {import("./ws-api/database-api").SidechainType} SidechainType */ -/** @typedef {string | number | BigNumber} ObjectId_t */ -/** @typedef {number | BigNumber | string} Integer_t */ -/** - * @template T - * @typedef {Set | T[] | undefined} Set_t - */ - /** @typedef { * { * previous:String, @@ -1934,36 +1928,32 @@ class API { } /** - * @param {Object} [opts] - * @param {Set_t} [opts.contracts] - * @param {Array>} [opts.topics] - * @param {Integer_t} [opts.fromBlock] - * @param {Integer_t} [opts.toBlock] + * @param {ContractLogsFilterOptions_t} [opts] * @returns {Promise} */ async getContractLogs(opts = {}) { - /** @type {string[]} */ - const contractsList = opts.contracts === undefined ? undefined : - collections.set(chain.ids.protocol.contractId).toRaw(opts.contracts, 'contracts'); - /** @type {Array} */ - const topicsList = opts.topics === undefined ? undefined : - collections.vector(collections.set(basic.string)).toRaw(opts.topics, '`topics`'); - const from = opts.fromBlock === undefined ? undefined : basic.integers.int32.toRaw(opts.fromBlock, 'fromBlock'); - const to = opts.toBlock === undefined ? undefined : basic.integers.int32.toRaw(opts.toBlock, 'toBlock'); - if (from !== undefined && from < 0) throw new Error('`fromBlock` must be greater than or equal to zero'); - if (to !== undefined && to <= 0) throw new Error('`toBlock` must be greater than zero'); - return new Promise((resolve) => this.wsApi.database.getContractLogs((res) => resolve(res), { - contracts: contractsList, - topics: topicsList, - from_block: from, - to_block: to, - })).then((res) => { + return new Promise((resolve) => { + this.wsApi.database.getContractLogs((res) => resolve(res), toRawContractLogsFilterOptions(opts)); + }).then((res) => { assert.ok(Array.isArray(res)); assert.strictEqual(res.length, 1); return res[0]; }); } + /** + * @param {(result: Log[]) => any} callback + * @param {ContractLogsFilterOptions_t} [opts] + * @returns {Promise} + */ + async subscribeContractLogs(callback, opts = {}) { + return this.wsApi.database.subscribeContractLogs((result) => { + assert.ok(Array.isArray(result)); + assert.strictEqual(result.length, 1); + callback(result[0]); + }, toRawContractLogsFilterOptions(opts)); + } + /** * @method getContractResult * diff --git a/src/echo/subscriber.js b/src/echo/subscriber.js index 3dfc9b3d..84c2866e 100644 --- a/src/echo/subscriber.js +++ b/src/echo/subscriber.js @@ -37,6 +37,10 @@ import { import { handleConnectionClosedError } from '../utils/helpers'; import { IMPLEMENTATION_OBJECT_TYPE_ID } from '../constants/chain-types'; +import { chain, collections, basic } from '../serializers'; +import { toRawContractLogsFilterOptions } from '../utils/converters'; + +/** @typedef {import("../../types/interfaces/vm/types").Log} Log */ class Subscriber extends EventEmitter { @@ -897,89 +901,13 @@ class Subscriber extends EventEmitter { } /** - * @method _contractLogsUpdate - * - * @param {Array>} contractLogsMap - * @param {*} result - * - * @return {undefined} - */ - _contractLogsUpdate(contractTopicsMap, result) { - let callbacks = []; - contractTopicsMap.forEach((topicMap) => { - const [contractId] = topicMap; - - callbacks = callbacks.concat(this.subscribers.logs[contractId]); - }); - - callbacks.forEach((callback) => callback(result)); - } - - /** - * @method _subscribeToContractLogs - * - * @param {Array>} contractLogsMap - * - * @return {undefined} - */ - async _subscribeToContractLogs(contractTopicsMap) { - await this._wsApi.database.subscribeContractLogs( - this._contractLogsUpdate.bind(this, contractTopicsMap), - contractTopicsMap, - ); - } - - /** - * @method setContractLogsSubscribe - * - * @param {Array>} contractTopicsMap - * @param {Function} callback - * @param {Number} [fromBlock] - * @param {Number} [toBlock] - * - * @return {undefined} - */ - async setContractLogsSubscribe(contractTopicsMap, callback, fromBlock, toBlock) { - const globalInfo = await this._wsApi.database.getDynamicGlobalProperties(); - - const contractsToSubscribe = []; - - await Promise.all(contractTopicsMap.map((topicsItem) => - (async () => { - const [contractId, topics] = topicsItem; - if (fromBlock) { - const logs = await this._wsApi.database.getContractLog( - contractId, - topics, - fromBlock, - toBlock || globalInfo.head_block_number, - ); - callback(logs); - } - - // set subscriber from current block - if (!this.subscribers.logs[contractId]) { - this.subscribers.logs[contractId] = []; - contractsToSubscribe.push(topicsItem); - } - - this.subscribers.logs[contractId].push(callback); - })())); - - await this._subscribeToContractLogs(contractsToSubscribe); - } - - /** - * @method removeMarketSubscribe - * - * @param {String} contractId - * @param {Function} callback - * - * @return {undefined} + * @method setContractLogsSubscribe + * @param {(result: Log[]) => any} callback + * @param {import('./api').ContractLogsFilterOptions_t} [options] + * @return {Promise} */ - removeContractLogsSubscribe(contractId, callback) { - this.subscribers.logs[contractId] = this.subscribers.logs[contractId] - .filter((c) => (c !== callback)); + async setContractLogsSubscribe(callback, options = {}) { + return this._wsApi.database.subscribeContractLogs(callback, toRawContractLogsFilterOptions(options)); } /** diff --git a/src/echo/ws-api/database-api.js b/src/echo/ws-api/database-api.js index 7920bd13..b8d28f02 100644 --- a/src/echo/ws-api/database-api.js +++ b/src/echo/ws-api/database-api.js @@ -499,25 +499,16 @@ class DatabaseAPI { /** * @param {(result: Log[]) => any} cb - * @param {Object} opts - * @param {string[]} opts.contracts - * @param {Array} opts.topics - * @param {number} [opts.from_block] - * @param {number} [opts.to_block] + * @param {ContractLogsFilterOptionsRaw} opts */ getContractLogs(cb, opts) { return this.db.exec('get_contract_logs', [cb, opts]); } /** - * @method subscribeContractLogs - * - * @param {Function} callback - * @param {Array>} contractTopicsMap - * - * @return {Promise} + * @param {(result: Log[]) => any} cb + * @param {ContractLogsFilterOptionsRaw} options + * @returns {Promise} */ - subscribeContractLogs(callback, contractTopicsMap) { - return this.db.exec('subscribe_contract_logs', [callback, contractTopicsMap]); - } + subscribeContractLogs(cb, options) { return this.db.exec('subscribe_contract_logs', [cb, options]); } /** * @method getContractResult diff --git a/src/echo/ws/reconnection-websocket.js b/src/echo/ws/reconnection-websocket.js index b9dbbfb6..df9b9a8f 100644 --- a/src/echo/ws/reconnection-websocket.js +++ b/src/echo/ws/reconnection-websocket.js @@ -208,22 +208,14 @@ class ReconnectionWebSocket { this._cbId += 1; - if (method === 'set_subscribe_callback' || - method === 'broadcast_transaction_with_callback' || method === 'set_pending_transaction_callback' || - method === 'set_block_applied_callback' || method === 'set_consensus_message_callback' || - method === 'subscribe_contract_logs' || method === 'submit_registration_solution' || - method === 'get_contract_logs' + if (method === 'set_subscribe_callback' || method === 'broadcast_transaction_with_callback' || + method === 'set_pending_transaction_callback' || method === 'set_block_applied_callback' || + method === 'set_consensus_message_callback' || method === 'submit_registration_solution' || + method === 'get_contract_logs' || method === 'subscribe_contract_logs' ) { - // Store callback in subs map - this._subs[this._cbId] = { - callback: params[2][0], - }; - - // Replace callback with the callback id + this._subs[this._cbId] = { callback: params[2][0] }; params[2][0] = this._cbId; - } - - if (method === 'unsubscribe_from_accounts') { + } else if (method === 'unsubscribe_from_accounts') { if (typeof params[2][0] !== 'function') { throw new Error('First parameter of unsub must be the original callback'); } @@ -253,7 +245,7 @@ class ReconnectionWebSocket { this._cbs[this._cbId] = { time: new Date(), - resolve, + resolve: method === 'subscribe_contract_logs' ? () => resolve(params[2][0]) : resolve, reject, timeoutId, }; diff --git a/src/utils/converters.js b/src/utils/converters.js index 6ba468e6..d162dc72 100644 --- a/src/utils/converters.js +++ b/src/utils/converters.js @@ -1,6 +1,7 @@ import { Long } from 'bytebuffer'; import BigNumber from 'bignumber.js'; import { idRegex } from './validators'; +import { collections, chain, basic } from '../serializers'; const MAX_UINT64 = new BigNumber(2).pow(64).minus(1); const MAX_INT64 = new BigNumber(2).pow(63).minus(1); @@ -39,3 +40,49 @@ export function toId(address, reservedSpaceId, objectTypeId) { else if (!objectTypeId.includes(actualObjectTypeId)) throw new Error('invalid objectTypeId'); return id; } + +/** @typedef {string | number | BigNumber} ObjectId_t */ +/** @typedef {number | BigNumber | string} Integer_t */ +/** + * @template T + * @typedef {Set | T[] | undefined} Set_t + */ + +/** + * @typedef {Object} ContractLogsFilterOptions_t + * @property {Set_t} [contracts] + * @property {Array>} [topics] + * @property {Integer_t} [fromBlock] + * @property {Integer_t} [toBlock] + */ + +/** + * @typedef {Object} ContractLogsFilterOptionsRaw + * @property {string[]} [contracts] + * @property {Array} [topics] + * @property {number} [from_block] + * @property {number} [to_block] + */ + +/** + * @param {ContractLogsFilterOptions_t} opts + * @returns {ContractLogsFilterOptionsRaw} + */ +export function toRawContractLogsFilterOptions(opts) { + /** @type {string[]} */ + const contractsList = opts.contracts === undefined ? undefined : + collections.set(chain.ids.protocol.contractId).toRaw(opts.contracts, 'contracts'); + /** @type {Array} */ + const topicsList = opts.topics === undefined ? undefined : + collections.vector(collections.set(basic.string)).toRaw(opts.topics, '`topics`'); + const from = opts.fromBlock === undefined ? undefined : basic.integers.int32.toRaw(opts.fromBlock, 'fromBlock'); + const to = opts.toBlock === undefined ? undefined : basic.integers.int32.toRaw(opts.toBlock, 'toBlock'); + if (from !== undefined && from < 0) throw new Error('`fromBlock` must be greater than or equal to zero'); + if (to !== undefined && to <= 0) throw new Error('`toBlock` must be greater than zero'); + return { + contracts: contractsList, + topics: topicsList, + from_block: from, + to_block: to, + }; +} diff --git a/test/_event-emitter-contract.js b/test/_event-emitter-contract.js new file mode 100644 index 00000000..7f79bee5 --- /dev/null +++ b/test/_event-emitter-contract.js @@ -0,0 +1,80 @@ +import assert from "assert"; +import { OPERATIONS_IDS } from ".."; +import { accountId, privateKey } from "./_test-data"; + +/** @typedef {import("..").Echo} Echo */ + +/* + * pragma solidity ^0.4.23; + * + * contract Emitter { + * event Event1(uint256 indexed indexedField, uint256 nonIndexedField); + * event Event2(uint256 indexed indexedField, uint256 nonIndexedField); + * function emit1(uint256 indexedField, uint256 nonIndexedField) public { + * emit Event1(indexedField, nonIndexedField); + * } + * function emit2(uint256 indexedField, uint256 nonIndexedField) public { + * emit Event2(indexedField, nonIndexedField); + * } + * } + */ +const bytecode = [ + "608060405234801561001057600080fd5b50610163806100206000396000f30060806040526004361061004c576000357c010000000000000", + "0000000000000000000000000000000000000000000900463ffffffff168063156d44ef146100515780631baea0ab14610088575b600080fd", + "5b34801561005d57600080fd5b5061008660048036038101908080359060200190929190803590602001909291905050506100bf565b005b3", + "4801561009457600080fd5b506100bd60048036038101908080359060200190929190803590602001909291905050506100fb565b005b817f", + "d3610b1c54575b7f4f0dc03d210b8ac55624ae007679b7a928a4f25a709331a8826040518082815260200191505060405180910390a250505", + "65b817f6a822560072e19c1981d3d3bb11e5954a77efa0caf306eb08d053f37de0040ba826040518082815260200191505060405180910390", + "a250505600a165627a7a72305820fddab02616eb79d169bffcec273868d1795db6ede88d13a007343987fa332a370029", +].join(""); + +export const emit1 = "156d44ef"; +export const emit2 = "1baea0ab"; + +/** + * @param {Echo} echo + * @param {number} [expirationOffset] + * @returns {Promise} + */ +export async function deploy(echo, expirationOffset = 0) { + const tx = echo.createTransaction().addOperation(OPERATIONS_IDS.CONTRACT_CREATE, { + registrar: accountId, + value: { amount: 0, asset_id: "1.3.0" }, + code: bytecode, + eth_accuracy: false, + extensions: [], + }).addSigner(privateKey); + tx.expiration = Math.ceil(Date.now() / 1e3) + expirationOffset; + const txRes = await tx.broadcast(); + /** @type {string} */ + const opResId = txRes[0].trx.operation_results[0][1]; + const opRes = await echo.api.getObject(opResId); + const contractId = opRes.contracts_id[0]; + assert.ok(contractId !== undefined); + return contractId; +} + +/** + * @param {Echo} echo + * @param {string} contractId + * @param {(typeof emit1)|(typeof emit2)} methodSignature + * @param {number} indexed + * @param {number} notIndexed + */ +export async function emit(echo, contractId, methodSignature, indexed, notIndexed) { + assert.ok(indexed >= 0); + assert.ok(notIndexed >= 0); + assert.ok(Number.isSafeInteger(indexed)); + assert.ok(Number.isSafeInteger(notIndexed)); + await echo.createTransaction().addOperation(OPERATIONS_IDS.CONTRACT_CALL, { + registrar: accountId, + value: { amount: 0, asset_id: '1.3.0' }, + code: [ + methodSignature, + indexed.toString(16).padStart(64, '0'), + notIndexed.toString(16).padStart(64, '0'), + ].join(''), + callee: contractId, + extensions: [], + }).addSigner(privateKey).broadcast(); +} diff --git a/test/api/database/get-contract-logs2.test.js b/test/api/database/get-contract-logs.test.js similarity index 65% rename from test/api/database/get-contract-logs2.test.js rename to test/api/database/get-contract-logs.test.js index b01e5a52..6cb4f7ad 100644 --- a/test/api/database/get-contract-logs2.test.js +++ b/test/api/database/get-contract-logs.test.js @@ -2,83 +2,16 @@ import * as assert from "assert"; import { Echo, OPERATIONS_IDS, BigNumber } from "../../.."; import { url, accountId, privateKey } from "../../_test-data"; import { shouldReject } from "../../_test-utils"; +import { deploy, emit, emit1, emit2 } from "../../_event-emitter-contract"; /** * @template T * @typedef {import("../../_test-utils").UnPromisify} UnPromisify */ -/* - * pragma solidity ^0.4.23; - * - * contract Emitter { - * event Event1(uint256 indexed indexedField, uint256 nonIndexedField); - * event Event2(uint256 indexed indexedField, uint256 nonIndexedField); - * function emit1(uint256 indexedField, uint256 nonIndexedField) public { - * emit Event1(indexedField, nonIndexedField); - * } - * function emit2(uint256 indexedField, uint256 nonIndexedField) public { - * emit Event2(indexedField, nonIndexedField); - * } - * } - */ -const bytecode = [ - "608060405234801561001057600080fd5b50610163806100206000396000f30060806040526004361061004c576000357c010000000000000", - "0000000000000000000000000000000000000000000900463ffffffff168063156d44ef146100515780631baea0ab14610088575b600080fd", - "5b34801561005d57600080fd5b5061008660048036038101908080359060200190929190803590602001909291905050506100bf565b005b3", - "4801561009457600080fd5b506100bd60048036038101908080359060200190929190803590602001909291905050506100fb565b005b817f", - "d3610b1c54575b7f4f0dc03d210b8ac55624ae007679b7a928a4f25a709331a8826040518082815260200191505060405180910390a250505", - "65b817f6a822560072e19c1981d3d3bb11e5954a77efa0caf306eb08d053f37de0040ba826040518082815260200191505060405180910390", - "a250505600a165627a7a72305820fddab02616eb79d169bffcec273868d1795db6ede88d13a007343987fa332a370029", -].join(""); - -const emit1 = "156d44ef"; -const emit2 = "1baea0ab"; - describe("getContractLogs", () => { const echo = new Echo(); - /** @returns {Promise} */ - async function deploy() { - const txRes = await echo.createTransaction().addOperation(OPERATIONS_IDS.CONTRACT_CREATE, { - registrar: accountId, - value: { amount: 0, asset_id: "1.3.0" }, - code: bytecode, - eth_accuracy: false, - extensions: [], - }).addSigner(privateKey).broadcast(); - /** @type {string} */ - const opResId = txRes[0].trx.operation_results[0][1]; - const opRes = await echo.api.getObject(opResId); - const contractId = opRes.contracts_id[0]; - assert.ok(contractId !== undefined); - return contractId; - } - - /** - * @param {string} contractId - * @param {string} methodSignature - * @param {number} indexed - * @param {number} notIndexed - */ - async function emit(contractId, methodSignature, indexed, notIndexed) { - assert.ok(indexed >= 0); - assert.ok(notIndexed >= 0); - assert.ok(Number.isSafeInteger(indexed)); - assert.ok(Number.isSafeInteger(notIndexed)); - await echo.createTransaction().addOperation(OPERATIONS_IDS.CONTRACT_CALL, { - registrar: accountId, - value: { amount: 0, asset_id: '1.3.0' }, - code: [ - methodSignature, - indexed.toString(16).padStart(64, '0'), - notIndexed.toString(16).padStart(64, '0'), - ].join(''), - callee: contractId, - extensions: [], - }).addSigner(privateKey).broadcast(); - } - before(async () => await echo.connect(url)); after(async () => await echo.disconnect()); @@ -133,10 +66,10 @@ describe("getContractLogs", () => { let contractAddress; before(async function () { this.timeout(25e3); - contractId = await deploy(); + contractId = await deploy(echo); contractAddress = `01${new BigNumber(contractId.split('.')[2]).toString(16).padStart(38, '0')}`; - await emit(contractId, emit1, 123, 234); - await emit(contractId, emit2, 345, 456); + await emit(echo, contractId, emit1, 123, 234); + await emit(echo, contractId, emit2, 345, 456); }); describe('when no filter provided', () => { /** @type {UnPromisify>} */ @@ -172,11 +105,11 @@ describe("getContractLogs", () => { let anotherContractAddress; before(async function () { this.timeout(30e3); - anotherContractId = await deploy(); + anotherContractId = await deploy(echo); const anotherContractInstanceIndex = new BigNumber(anotherContractId.split('.')[2]); anotherContractAddress = `01${anotherContractInstanceIndex.toString(16).padStart(38, '0')}`; - await emit(anotherContractId, emit1, 123, 234); - await emit(anotherContractId, emit2, 345, 456); + await emit(echo, anotherContractId, emit1, 123, 234); + await emit(echo, anotherContractId, emit2, 345, 456); }); describe('when first contract provided in `contracts` filter', () => { /** @type {UnPromisify>} */ diff --git a/test/api/database/subscribe-contract-logs.test.js b/test/api/database/subscribe-contract-logs.test.js new file mode 100644 index 00000000..bf0a9c3c --- /dev/null +++ b/test/api/database/subscribe-contract-logs.test.js @@ -0,0 +1,43 @@ +import assert from "assert"; +import { Echo } from "../../.."; +import { url } from "../../_test-data"; +import { deploy, emit, emit1 } from "../../_event-emitter-contract"; + +/** @typedef {import("../../../types/interfaces/vm/types").Log} Log */ + +describe('subscribeContractLogs', () => { + const echo = new Echo(); + let contract1; + let contract2; + before(async function () { + this.timeout(10e3); + await echo.connect(url); + [contract1, contract2] = await Promise.all(new Array(2).fill(null).map((_, i) => deploy(echo, 10 + i))); + }); + after(async () => echo.disconnect()); + describe('when no any options are provided', () => { + /** @type {number|string} */ + let cbId; + /** @type {Log[]} */ + let emits = []; + it('should succeed', async () => cbId = await echo.api.subscribeContractLogs((logs) => emits.push(...logs))); + describe('when different contracts emit', () => { + before(() => emits = []); + it('should not rejects', async function () { + this.timeout(10e3); + await Promise.all([contract1, contract2].map(async (contract) => { + await emit(echo, contract, emit1, 123, 234); + })); + await new Promise((resolve) => setTimeout(() => resolve(), 1e3)); + }); + it('should call callback', () => assert.ok(emits.length > 0)); + it('should call callback twice', () => assert.strictEqual(emits.length, 2)); + it('with both of contracts', function () { + if (emits.length !== 2) this.skip(); + assert.deepStrictEqual(new Set([contract1, contract2]), new Set(emits.map((log) => log[1].address))); + }); + }); + // TODO: unsubscribe + after(async () => { if (cbId !== undefined); }); + }); +}); diff --git a/test/api/index.api.test.js b/test/api/index.api.test.js index 87e527ee..c77994a9 100644 --- a/test/api/index.api.test.js +++ b/test/api/index.api.test.js @@ -1,6 +1,7 @@ describe('api', () => { require('./database/check-erc20-token.test'); - require('./database/get-contract-logs2.test'); + require('./database/get-contract-logs.test'); + require('./database/subscribe-contract-logs.test'); require('./register.account.test'); require('./network.api.test'); }); diff --git a/test/subscriber.test.js b/test/subscriber.test.js index 5a0df56e..5c88f498 100644 --- a/test/subscriber.test.js +++ b/test/subscriber.test.js @@ -437,24 +437,6 @@ describe('SUBSCRIBER', () => { }); }); - describe('setContractLogsSubscribe', () => { - it('test', async () => { - await echo.subscriber.setContractLogsSubscribe([[`1.${CONTRACT}.0`, []]], () => {}); - expect(echo.subscriber.subscribers.logs[`1.${CONTRACT}.0`].length).to.equal(1); - }); - }); - - describe('removeContractLogsSubscribe', () => { - it('test', async () => { - const callback = () => {}; - await echo.subscriber.setContractLogsSubscribe([[`1.${CONTRACT}.0`, []]], callback); - - const { length } = echo.subscriber.subscribers.logs[`1.${CONTRACT}.0`]; - await echo.subscriber.removeContractLogsSubscribe(`1.${CONTRACT}.0`, callback); - expect(echo.subscriber.subscribers.logs[`1.${CONTRACT}.0`].length).to.equal(length - 1); - }); - }); - after(async () => { await echo.disconnect(); }); diff --git a/types/echo/api.d.ts b/types/echo/api.d.ts index 006e176c..5291b513 100644 --- a/types/echo/api.d.ts +++ b/types/echo/api.d.ts @@ -142,13 +142,6 @@ export default class Api { */ getContractLogs(opts?: ContractLogsFilterOptions): Promise; - getContractLogs1(opts: { - contracts?: string[], - topics?: Array>, - fromBlock?: number | BigNumber, - toBlock?: number | BigNumber, - }): Promise; - getContractPoolBalance(resultContractId: string, force?: boolean): Promise<{asset_id: string, amount: number}>; getContractResult(resultContractId: string, force?: boolean): Promise; getDynamicAssetData(dynamicAssetDataId: string, force?: boolean): Promise; @@ -211,6 +204,14 @@ export default class Api { ): Promise<[{ block_num: number, tx_id: string }]>; requestRegistrationTask(): Promise + + /** + * @param cb + * @param options Contract logs filter options (see {@link ContractLogsFilterOptions}) + * @returns Callback id which should be referenced in {@link unsubscribeContractLogs} + */ + subscribeContractLogs(cb: (result: Log[]) => any, options?: ContractLogsFilterOptions): Promise; + validateTransaction(tr: Object): Promise; verifyAuthority(tr: Object): Promise; verifyAccountAuthority(accountNameOrId: Object, signers: Array): Promise; diff --git a/types/echo/subscriber.d.ts b/types/echo/subscriber.d.ts index bdafd820..a47a7532 100644 --- a/types/echo/subscriber.d.ts +++ b/types/echo/subscriber.d.ts @@ -1,3 +1,7 @@ +import { Log } from "../interfaces/vm/types"; +import { ContractLogsFilterOptions } from "./api"; + export default class Subscriber { setBlockApplySubscribe(cb: (blockHash: unknown) => any): Promise; + setContractLogsSubscribe(cb: (result: Log[]) => any, options?: ContractLogsFilterOptions): Promise; } diff --git a/types/echo/transaction.d.ts b/types/echo/transaction.d.ts index fa93fbc9..e473937b 100644 --- a/types/echo/transaction.d.ts +++ b/types/echo/transaction.d.ts @@ -33,6 +33,8 @@ export default class Transaction { readonly transactionObject: any; readonly operations: SerializerOutput[]; + expiration: number; + addOperation( operationId: T, props?: TOperationInput[1], From f8f89432d137c412721d57e9f00477f011e797e0 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Thu, 26 Dec 2019 13:24:13 +0300 Subject: [PATCH 27/62] `unsubscribe_contract_logs` method --- docs/Constants.md | 41 +++++++++++-------- echo@0.14.0-rc.1-migration.md | 34 --------------- package.json | 2 +- src/echo/api.js | 6 +++ src/echo/ws-api/database-api.js | 3 ++ .../database/subscribe-contract-logs.test.js | 23 ++++++++--- test/cache.test.js | 5 ++- types/echo/api.d.ts | 10 ++++- 8 files changed, 63 insertions(+), 61 deletions(-) delete mode 100644 echo@0.14.0-rc.1-migration.md diff --git a/docs/Constants.md b/docs/Constants.md index 12986a15..a7b883c7 100644 --- a/docs/Constants.md +++ b/docs/Constants.md @@ -228,24 +228,29 @@ console.log(constants.OPERATIONS_IDS); // operation id SIDECHAIN_ETH_CREATE_ADDRESS: 39, SIDECHAIN_ETH_APPROVE_ADDRESS: 40, SIDECHAIN_ETH_DEPOSIT: 41, - SIDECHAIN_ETH_WITHDRAW: 42, - SIDECHAIN_ETH_APPROVE_WITHDRAW: 43, - SIDECHAIN_ISSUE: 44, // VIRTUAL - SIDECHAIN_BURN: 45, // VIRTUAL - SIDECHAIN_ERC20_REGISTER_TOKEN: 46, - SIDECHAIN_ERC20_DEPOSIT_TOKEN: 47, - SIDECHAIN_ERC20_WITHDRAW_TOKEN: 48, - SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW: 49, - SIDECHAIN_ERC20_ISSUE: 50, // VIRTUAL - SIDECHAIN_ERC20_BURN: 51, // VIRTUAL - SIDECHAIN_BTC_CREATE_ADDRESS: 52, - SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT: 53, - SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT: 54, - SIDECHAIN_BTC_DEPOSIT: 55, - SIDECHAIN_BTC_WITHDRAW: 56, - SIDECHAIN_BTC_APPROVE_WITHDRAW: 57, - SIDECHAIN_BTC_AGGREGATE: 58, - BLOCK_REWARD: 59,// VIRTUAL + SIDECHAIN_ETH_SEND_DEPOSIT: 42, + SIDECHAIN_ETH_WITHDRAW: 43, + SIDECHAIN_ETH_SEND_WITHDRAW: 44, + SIDECHAIN_ETH_APPROVE_WITHDRAW: 45, + SIDECHAIN_ETH_UPDATE_CONTRACT_ADDRESS: 46, + SIDECHAIN_ISSUE: 47, // VIRTUAL + SIDECHAIN_BURN: 48, // VIRTUAL + SIDECHAIN_ERC20_REGISTER_TOKEN: 49, + SIDECHAIN_ERC20_DEPOSIT_TOKEN: 50, + SIDECHAIN_ERC20_SEND_DEPOSIT: 51, + SIDECHAIN_ERC20_WITHDRAW_TOKEN: 52, + SIDECHAIN_ERC20_SEND_WITHDRAW: 53, + SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW: 54, + SIDECHAIN_ERC20_ISSUE: 55, // VIRTUAL + SIDECHAIN_ERC20_BURN: 56, // VIRTUAL + SIDECHAIN_BTC_CREATE_ADDRESS: 57, + SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT: 58, + SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT: 59, + SIDECHAIN_BTC_DEPOSIT: 60, + SIDECHAIN_BTC_WITHDRAW: 61, + SIDECHAIN_BTC_AGGREGATE: 62, + SIDECHAIN_BTC_APPROVE_AGGREGATE: 63, + BLOCK_REWARD: 64, // VIRTUAL } */ ``` diff --git a/echo@0.14.0-rc.1-migration.md b/echo@0.14.0-rc.1-migration.md deleted file mode 100644 index 99c5d160..00000000 --- a/echo@0.14.0-rc.1-migration.md +++ /dev/null @@ -1,34 +0,0 @@ -* [x] Add field `btc_block_number` to `sidechain_btc_aggregate_operation` and `btc_aggregating_object` -* [x] Add fields `btc_deposit_withdrawal_min`, `btc_deposit_withdrawal_fee` to `sidechain_config` -* [ ] Update contract subscription - * [x] Update the contracts logs subscription filter - * [ ] Add method `unsubscribe_contract_logs` in database API -* [ ] Bitcoin key to configure-keys -* [x] Implement 24 hours delay for deposit and withdrawal processing in Ethereum sidechain - * [x] `sidechain_eth_send_deposit_operation` - * [x] `sidechain_eth_send_withdraw_operation` - * [x] `sidechain_erc20_send_deposit_operation` - * [x] `sidechain_erc20_send_withdraw_operation` -* [x] Add functionality to update ETH contract address - * [x] Add `sidechain_eth_update_contract_address_operation` - * [x] Add field `eth_update_contract_address` to `sidechain_config` -* [x] Add methods to wallet-api - * [x] `get_contract_history` - * [x] `get_relative_contract_history` -* [x] Change arguments of `get_contract_logs` method and make it async -* [x] Change type of argument in wallet-api method `get_btc_address` from `account_id` to `string` -* [x] Rename wallet-api method `generate_eth_address` to `create_eth_address` -* [x] Rename `deposit_erc20_token_object` to `erc20_deposit_token_object` -* [x] Rename `withdraw_erc20_token_object` to `erc20_withdraw_token_object` -* [x] wallet-api's `create_contract` method receives `amount` argument as `number|string|BigNumber` instead of `uint64` -* [x] wallet-api's `call_contract` method receives `amount` argument as `number|string|BigNumber` instead of `uint64` -* [x] Remove field `min_btc_deposit_withdrawal` from `sidechain_config` -* [x] Remove field `immutable_parameters` from `chain_property_object` -* [x] Remove method `get_block_rewards` from `database-api` - -* [x] Update contract's logs' filter -* [ ] Update operations' id's in docs -* [ ] Tests - * [ ] `get_contract_history` - * [ ] `get_relative_contract_history` - * [x] `get_contract_logs` diff --git a/package.json b/package.json index 1a5cb006..06a6e827 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "echojs-lib", - "version": "1.10.0-rc.0", + "version": "1.10.0-rc.1", "description": "Pure JavaScript ECHO library for node.js", "main": "./dist/index.js", "types": "./types/index.d.ts", diff --git a/src/echo/api.js b/src/echo/api.js index 16274530..3fb37be4 100644 --- a/src/echo/api.js +++ b/src/echo/api.js @@ -43,6 +43,7 @@ import { toRawContractLogsFilterOptions } from '../utils/converters'; /** @typedef {import("bignumber.js").default} BigNumber */ /** @typedef {import("../../types/interfaces/vm/types").Log} Log */ /** @typedef {import("./ws-api/database-api").SidechainType} SidechainType */ +/** @typedef {typeof basic.integers["uint64"]["__TInput__"]} UInt64 */ /** @typedef { * { @@ -1954,6 +1955,11 @@ class API { }, toRawContractLogsFilterOptions(opts)); } + /** @param {UInt64} subscribeId */ + async unsubscribeContractLogs(subscribeId) { + return this.wsApi.database.unsubscribeContractLogs(basic.integers.uint64.toRaw(subscribeId)); + } + /** * @method getContractResult * diff --git a/src/echo/ws-api/database-api.js b/src/echo/ws-api/database-api.js index b8d28f02..daa8185a 100644 --- a/src/echo/ws-api/database-api.js +++ b/src/echo/ws-api/database-api.js @@ -510,6 +510,9 @@ class DatabaseAPI { */ subscribeContractLogs(cb, options) { return this.db.exec('subscribe_contract_logs', [cb, options]); } + /** @param {number|string} cbId */ + unsubscribeContractLogs(cbId) { return this.db.exec('unsubscribe_contract_logs', [cbId]); } + /** * @method getContractResult * diff --git a/test/api/database/subscribe-contract-logs.test.js b/test/api/database/subscribe-contract-logs.test.js index bf0a9c3c..d9897a8a 100644 --- a/test/api/database/subscribe-contract-logs.test.js +++ b/test/api/database/subscribe-contract-logs.test.js @@ -1,5 +1,5 @@ import assert from "assert"; -import { Echo } from "../../.."; +import { Echo, BigNumber } from "../../.."; import { url } from "../../_test-data"; import { deploy, emit, emit1 } from "../../_event-emitter-contract"; @@ -17,10 +17,24 @@ describe('subscribeContractLogs', () => { after(async () => echo.disconnect()); describe('when no any options are provided', () => { /** @type {number|string} */ - let cbId; + let subscribeId; /** @type {Log[]} */ let emits = []; - it('should succeed', async () => cbId = await echo.api.subscribeContractLogs((logs) => emits.push(...logs))); + it('should succeed', async () => { + subscribeId = await echo.api.subscribeContractLogs((logs) => emits.push(...logs)); + }); + describe('should returns subscribeId', () => { + /** @type {BigNumber} */ + let subIdBN; + before('should returns subscribeId', () => { + assert.ok(subscribeId !== undefined); + subIdBN = new BigNumber(subscribeId); + }); + it('number', () => assert.ok(!new BigNumber(subscribeId).isNaN())); + it('integer', () => assert.ok(new BigNumber(subscribeId).isInteger())); + it('non-negative', () => assert.ok(new BigNumber(subscribeId).gte(0))); + it('less than 2**64', () => assert.ok(new BigNumber(subscribeId).lt(new BigNumber(2).pow(64)))); + }); describe('when different contracts emit', () => { before(() => emits = []); it('should not rejects', async function () { @@ -37,7 +51,6 @@ describe('subscribeContractLogs', () => { assert.deepStrictEqual(new Set([contract1, contract2]), new Set(emits.map((log) => log[1].address))); }); }); - // TODO: unsubscribe - after(async () => { if (cbId !== undefined); }); + after(async () => { if (subscribeId !== undefined) await echo.api.unsubscribeContractLogs(subscribeId); }); }); }); diff --git a/test/cache.test.js b/test/cache.test.js index df28035f..3a1bf837 100644 --- a/test/cache.test.js +++ b/test/cache.test.js @@ -191,6 +191,7 @@ describe('cache', () => { }); it('should not clean more often then minCleaningTime', async () => { + let tickTimeoutId; try { const promises = []; const expirationTime = 100; @@ -204,7 +205,8 @@ describe('cache', () => { res(); } else { if (currentCacheSize !== 0) { - setTimeout(() => { + tickTimeoutId = setTimeout(() => { + delete tickTimeoutId; tick(res, callCount + 1, currentCacheSize); }, tickInterval); } @@ -238,6 +240,7 @@ describe('cache', () => { }); } catch (e) { + if (tickTimeoutId !== undefined) clearTimeout(tickTimeoutId); throw(e); } }) diff --git a/types/echo/api.d.ts b/types/echo/api.d.ts index 5291b513..31fbe739 100644 --- a/types/echo/api.d.ts +++ b/types/echo/api.d.ts @@ -207,11 +207,17 @@ export default class Api { /** * @param cb - * @param options Contract logs filter options (see {@link ContractLogsFilterOptions}) - * @returns Callback id which should be referenced in {@link unsubscribeContractLogs} + * @param options Contract logs filter options (see `ContractLogsFilterOptions` method) + * @returns Callback id which should be referenced in `unsubscribeContractLogs` */ subscribeContractLogs(cb: (result: Log[]) => any, options?: ContractLogsFilterOptions): Promise; + /** + * Unsubscribe from contract log subscription + * @param subscribeId Subscribe id (returns by `subscribeContractLogs`) + */ + unsubscribeContractLogs(subscribeId: typeof uint64["__TInput__"]): Promise; + validateTransaction(tr: Object): Promise; verifyAuthority(tr: Object): Promise; verifyAccountAuthority(accountNameOrId: Object, signers: Array): Promise; From 955d4b0d2016aa490d66a6bdf8476292f4115e9d Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Thu, 26 Dec 2019 15:14:01 +0300 Subject: [PATCH 28/62] Fixes --- .test/docker-compose.yml | 2 +- test/cache.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.test/docker-compose.yml b/.test/docker-compose.yml index 6093cf02..663ec9b1 100644 --- a/.test/docker-compose.yml +++ b/.test/docker-compose.yml @@ -28,7 +28,7 @@ services: container_name: echo-wallet command: -s ws://echo:6311 - --chain-id="57f470d68dd10064f5a7fb5bd79d91d48ecfcfdff3243ff55b1173fd0404bfba" + --chain-id="4927f2eacd909c0a7f09268b61c9b1233817940cd5b66204ba8cad161360a4cd" --wallet-file="/echo/walletdata/wallet.json" --history-file="/echo/walletdata/history" -r 0.0.0.0:6312 diff --git a/test/cache.test.js b/test/cache.test.js index 3a1bf837..f7a7bda1 100644 --- a/test/cache.test.js +++ b/test/cache.test.js @@ -206,7 +206,7 @@ describe('cache', () => { } else { if (currentCacheSize !== 0) { tickTimeoutId = setTimeout(() => { - delete tickTimeoutId; + tickTimeoutId = undefined; tick(res, callCount + 1, currentCacheSize); }, tickInterval); } From a29c54b7563d49078d54cb1a2c1cb0b471b6bf65 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Fri, 3 Jan 2020 13:15:59 +0300 Subject: [PATCH 29/62] Add missing field in genesis && Change local-testnet chain id && Fix typings --- .test/docker-compose.yml | 2 +- .test/genesis.json | 1 + src/echo/subscriber.js | 1 - src/utils/validators.js | 2 ++ types/echo/api.d.ts | 21 +++++++------ types/index.d.ts | 4 +-- types/interfaces/Asset.d.ts | 10 ------ types/interfaces/Contract.d.ts | 9 ++++++ types/interfaces/objects.d.ts | 57 ++++++++++++++++++++++++++++++++++ types/interfaces/vm/types.d.ts | 7 ++--- types/utils/validators.d.ts | 1 + 11 files changed, 86 insertions(+), 29 deletions(-) delete mode 100644 types/interfaces/Asset.d.ts create mode 100644 types/interfaces/Contract.d.ts create mode 100644 types/interfaces/objects.d.ts diff --git a/.test/docker-compose.yml b/.test/docker-compose.yml index 663ec9b1..f9a978ec 100644 --- a/.test/docker-compose.yml +++ b/.test/docker-compose.yml @@ -28,7 +28,7 @@ services: container_name: echo-wallet command: -s ws://echo:6311 - --chain-id="4927f2eacd909c0a7f09268b61c9b1233817940cd5b66204ba8cad161360a4cd" + --chain-id="7c48ed2269d0a515e193f03f484a8fb0d004f5f7512383d2892ab7e93147a88c" --wallet-file="/echo/walletdata/wallet.json" --history-file="/echo/walletdata/history" -r 0.0.0.0:6312 diff --git a/.test/genesis.json b/.test/genesis.json index 1ffa2c1b..65d73be2 100644 --- a/.test/genesis.json +++ b/.test/genesis.json @@ -107,6 +107,7 @@ "eth_update_addr_method": { "method": "7ff203ab", "gas": 1000000 }, "eth_withdraw_token_method": { "method": "1c69c0e2", "gas": 1000000 }, "eth_collect_tokens_method": { "method": "5940a240", "gas": 1000000 }, + "eth_update_contract_address": { "method": "3659cfe6", "gas": 1000000 }, "eth_committee_updated_topic": "514bf7702a7d2aca90dcf3d947158aad29563a17c1dbdc76d2eae84c22420142", "eth_gen_address_topic": "1855f12530a368418f19b2b15227f19225915b8113c7e17d4c276e2a10225039", "eth_deposit_topic": "77227a376c41a7533c952ebde8d7b44ee36c7a6cec0d3448f1a1e4231398356f", diff --git a/src/echo/subscriber.js b/src/echo/subscriber.js index 84c2866e..68611554 100644 --- a/src/echo/subscriber.js +++ b/src/echo/subscriber.js @@ -37,7 +37,6 @@ import { import { handleConnectionClosedError } from '../utils/helpers'; import { IMPLEMENTATION_OBJECT_TYPE_ID } from '../constants/chain-types'; -import { chain, collections, basic } from '../serializers'; import { toRawContractLogsFilterOptions } from '../utils/converters'; /** @typedef {import("../../types/interfaces/vm/types").Log} Log */ diff --git a/src/utils/validators.js b/src/utils/validators.js index 2100ea48..a7ae90b1 100644 --- a/src/utils/validators.js +++ b/src/utils/validators.js @@ -54,6 +54,7 @@ const contractIdRegex = generateProtocolObjectIdRegExp(PROTOCOL_OBJECT_TYPE_ID.C const contractResultIdRegex = generateProtocolObjectIdRegExp(PROTOCOL_OBJECT_TYPE_ID.CONTRACT_RESULT); const ethAddressIdRegex = generateProtocolObjectIdRegExp(PROTOCOL_OBJECT_TYPE_ID.ETH_ADDRESS); const btcAddressIdRegex = generateProtocolObjectIdRegExp(PROTOCOL_OBJECT_TYPE_ID.BTC_ADDRESS); +const erc20TokenIdRegex = generateProtocolObjectIdRegExp(PROTOCOL_OBJECT_TYPE_ID.ERC20_TOKEN); const dynamicGlobalObjectIdRegex = new RegExp(`^2\\.${CHAIN_TYPES.IMPLEMENTATION_OBJECT_TYPE_ID.DYNAMIC_GLOBAL_PROPERTY}\\.0$`); const dynamicAssetDataIdRegex = generateProtocolImplObjectIdRegExp(CHAIN_TYPES.IMPLEMENTATION_OBJECT_TYPE_ID.ASSET_DYNAMIC_DATA); @@ -139,6 +140,7 @@ export const isAccountId = (v) => isString(v) && accountIdRegex.test(v); export const isAccountAddressId = (v) => isString(v) && accountAddressRegex.test(v); export const isAssetId = (v) => isString(v) && assetIdRegex.test(v); export const isBtcAddressId = (v) => isString(v) && btcAddressIdRegex.test(v); +export const isERC20TokenId = (v) => isString(v) && erc20TokenIdRegex.test(v); export const isEthAddressId = (v) => isString(v) && ethAddressIdRegex.test(v); export const isCommitteeMemberId = (v) => isString(v) && committeeMemberIdRegex.test(v); diff --git a/types/echo/api.d.ts b/types/echo/api.d.ts index 31fbe739..4ec5fe85 100644 --- a/types/echo/api.d.ts +++ b/types/echo/api.d.ts @@ -17,13 +17,13 @@ import ChainProperties from '../interfaces/ChainProperties'; import GlobalProperties from '../interfaces/GlobalProperties'; import Config from '../interfaces/Config'; import DynamicGlobalProperties from '../interfaces/DynamicGlobalProperties'; -import Asset from '../interfaces/Asset'; import ContractHistory from '../interfaces/ContractHistory'; import ContractResult from '../interfaces/ContractResult'; import FrozenBalance from '../interfaces/FrozenBalance'; import BtcAddress from '../interfaces/BtcAddress'; import { OperationHistoryObject } from '../interfaces/chain'; import { PotentialPeerRecord } from '../interfaces/net/peer-database'; +import { IObject, IAssetObject, IAccountObject } from '../interfaces/objects'; import RegistrationTask from '../interfaces/RegistrationTask'; import PeerDetails from '../interfaces/PeerDetails'; import { Log } from '../interfaces/vm/types'; @@ -33,6 +33,7 @@ import { StringSerializer } from '../serializers/basic'; import { uint32, uint64, int32 } from '../serializers/basic/integers'; import { committeeMemberId, contractId } from '../serializers/chain/id/protocol'; import { VectorSerializer, SetSerializer } from '../serializers/collections'; +import { Contract } from '../interfaces/Contract'; type SidechainType = "" | "eth" | "btc"; @@ -52,7 +53,7 @@ export default class Api { broadcastTransactionWithCallback(signedTransactionObject: Object, wasBroadcastedCallback?: () => any): Promise; checkERC20Token(contractId: string): Promise; get24Volume(baseAssetName: string, quoteAssetName: string): Promise; - getAccounts(accountIds: Array, force?: boolean): Promise>; + getAccounts(accountIds: Array, force?: boolean): Promise; getAccountBalances( accountId: string, @@ -60,7 +61,7 @@ export default class Api { force?: boolean, ): Promise['__TOutput__']>; - getAccountByName(accountName: string, force?: boolean): Promise; + getAccountByName(accountName: string, force?: boolean): Promise; getAccountByAddress(address: string): Promise; getAccountCount(): Promise; getAccountDeposits(account: string, type: SidechainType): Promise; @@ -74,7 +75,7 @@ export default class Api { limit: number, ): Promise; - getAccountReferences(accountId: string, force?: boolean): Promise; + getAccountReferences(accountId: string, force?: boolean): Promise; getAccountWithdrawals(account: string, type: SidechainType): Promise; getAllAssetHolders(): Promise>; @@ -85,7 +86,7 @@ export default class Api { }>>; getAssetHoldersCount(assetId: string): Promise; - getAssets(assetIds: Array, force?: boolean): Promise>; + getAssets(assetIds: Array, force?: boolean): Promise>; getBalanceObjects(keys: Object): any; getBitAssetData(bitAssetId: string, force?: boolean): Promise; getBlock(blockNum: number): Promise; @@ -101,7 +102,7 @@ export default class Api { getCommitteeMembers(committeeMemberIds: Array, force?: boolean): Promise>; getCommitteeMemberByAccount(accountId: string, force?: boolean): Promise; getConfig(force?: boolean): Promise; - getContract(contractId: string): Promise>; + getContract(contractId: string): Promise; getContractBalances(contractId: string, force?: boolean): Promise; getContractPoolWhitelist(contractId: string): Promise; @@ -160,7 +161,7 @@ export default class Api { getKeyReferences(keys: Array, force?: boolean): Promise; getMarginPositions(accountId: string): Promise; getNamedAccountBalances(accountName: string, assetIds: Array, force?: boolean): Promise; - getObject(objectId: string, force?: boolean): Promise; + getObject(objectId: string, force?: boolean): Promise; getObjects(objectIds: string, force?: boolean): Promise>; getPotentialSignatures(tr: Object): Promise; getProposedTransactions(accountNameOrId: string): Promise; @@ -190,10 +191,10 @@ export default class Api { code: string, ): Promise; - listAssets(lowerBoundSymbol: string, limit: number): Promise>; + listAssets(lowerBoundSymbol: string, limit: number): Promise; lookupAccounts(lowerBoundName: string, limit: number): Promise>; - lookupAccountNames(accountNames: Array, force?: boolean): Promise>; - lookupAssetSymbols(symbolsOrIds: Array, force?: boolean): Promise>; + lookupAccountNames(accountNames: Array, force?: boolean): Promise; + lookupAssetSymbols(symbolsOrIds: Array, force?: boolean): Promise; lookupCommitteeMemberAccounts(lowerBoundName: string, limit: number): Promise; registerAccount( diff --git a/types/index.d.ts b/types/index.d.ts index 3712b721..f9e5cfe5 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -5,6 +5,7 @@ import * as validators from './utils/validators' import * as converters from './utils/converters' import * as crypto from './crypto' +export { OPERATIONS_IDS } from "./constants"; export { default as Transaction } from './echo/transaction'; export { default as PublicKey } from './crypto/public-key'; export { default as PrivateKey } from './crypto/private-key'; @@ -16,10 +17,9 @@ import * as serializers from './serializers'; import Contract, { encode, decode } from "./contract"; export { handleConnectionClosedError } from './utils/helpers'; - declare const echo: Echo; export default echo; -export declare const { OPERATIONS_IDS, CACHE_MAPS }: typeof constants; +export declare const { CACHE_MAPS }: typeof constants; export { BigNumber, Echo, constants, validators, converters, serializers, Contract, encode, decode, crypto }; diff --git a/types/interfaces/Asset.d.ts b/types/interfaces/Asset.d.ts deleted file mode 100644 index 63285d25..00000000 --- a/types/interfaces/Asset.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -export default interface Asset { - id: string, - symbol: string, - precision:Number, - issuer: string, - options: Object, - dynamic_asset_data_id: string, - dynamic: Object, - bitasset: (Object | undefined) -} diff --git a/types/interfaces/Contract.d.ts b/types/interfaces/Contract.d.ts new file mode 100644 index 00000000..42cc3d59 --- /dev/null +++ b/types/interfaces/Contract.d.ts @@ -0,0 +1,9 @@ +import { VMType } from "./objects"; + +export type Contract = [T, { + [VMType.EVM]: { + code: string, + storage: { [key: string]: [string, string] }, + }, + [VMType.X86_64]: { code: string }, +}[T]]; diff --git a/types/interfaces/objects.d.ts b/types/interfaces/objects.d.ts new file mode 100644 index 00000000..30578f57 --- /dev/null +++ b/types/interfaces/objects.d.ts @@ -0,0 +1,57 @@ +import { protocol } from "../serializers"; + +export enum VMType { + EVM = 0, + X86_64 = 1, +} + +export interface IObject { id: string; } + +export interface IContractObject extends IObject { + type: VMType; + destroyed: boolean; + statistics: string; + supported_asset_id?: string; + owner?: string; + extensions: unknown[]; +} + +export interface IERC20TokenObject extends IObject { + owner: string; + eth_addr: string; + contract: string; + name: string; + symbol: string; + decimals: number; + extensions: unknown[]; +} + +export interface IAssetObject extends IObject { + symbol: string; + precision: number; + issuer: string; + options: typeof protocol.asset.options["__TOutput__"]; + dynamic_asset_data_id: string; + bitasset_data_id?: string; + buyback_account?: string; + extensions: unknown[]; +} + +export interface IAccountObject extends IObject { + registrar: string; + name: string; + active: typeof protocol.authority["__TOutput__"]; + echorand_key: string; + active_delegate_share: number; + options: typeof protocol.account.options["__TOutput__"]; + statistics: string; + whitelisting_accounts: string[]; + blacklisting_accounts: string[]; + whitelisted_accounts: string[]; + blacklisted_accounts: string[]; + active_special_authority: unknown; + top_n_control_flags: number; + allowed_assets?: string[]; + accumulated_reward: number | string; + extensions: unknown[]; +} diff --git a/types/interfaces/vm/types.d.ts b/types/interfaces/vm/types.d.ts index b2358adc..d2d9c58b 100644 --- a/types/interfaces/vm/types.d.ts +++ b/types/interfaces/vm/types.d.ts @@ -1,7 +1,4 @@ -export enum LogType { - EVM = 0, - X86_X64 = 1, -} +import { VMType } from "../objects"; export interface LogEntry { address: string; @@ -12,4 +9,4 @@ export interface LogEntry { op_num: number; } -export type Log = [LogType, LogEntry]; +export type Log = [VMType, LogEntry]; diff --git a/types/utils/validators.d.ts b/types/utils/validators.d.ts index edf438cc..a6cef90b 100644 --- a/types/utils/validators.d.ts +++ b/types/utils/validators.d.ts @@ -34,6 +34,7 @@ export declare function isContractResultId(value?: any): boolean; export declare function isAccountBalanceId(value?: any): boolean; export declare function isOperationId(value?: any): boolean; export declare function isVoteId(value?: any): boolean; +export declare function isERC20TokenId(value?: string): boolean; export declare function isObjectId(value?: any): boolean; export declare function isBuffer(value?: any): boolean; From 0be8fe20dc795e223bc671725ca4b888e3557e50 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Fri, 3 Jan 2020 13:16:29 +0300 Subject: [PATCH 30/62] Up version to 1.10.0-rc.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 06a6e827..cdbab866 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "echojs-lib", - "version": "1.10.0-rc.1", + "version": "1.10.0-rc.2", "description": "Pure JavaScript ECHO library for node.js", "main": "./dist/index.js", "types": "./types/index.d.ts", From 1ee514ae1c8d70bc5f4bf12fc2926f1191b6453b Mon Sep 17 00:00:00 2001 From: Mikhail Shautsou Date: Thu, 20 Feb 2020 12:15:22 +0300 Subject: [PATCH 31/62] add sendSignedTransaction --- src/echo/transaction.js | 5 +++++ src/serializers/transaction.js | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/echo/transaction.js b/src/echo/transaction.js index 4ec9c7af..7bb734fd 100644 --- a/src/echo/transaction.js +++ b/src/echo/transaction.js @@ -277,6 +277,7 @@ class Transaction { operations: this.operations, extensions: [], signatures: this._signatures.map((signature) => signature.toBuffer()), + signed_with_echorand_key: false, }); } @@ -284,6 +285,10 @@ class Transaction { return transaction.serialize(this.transactionObject); } + signedTransactionSerializer() { + return signedTransaction.serialize(this.transactionObject); + } + /** * @param {()=>* =} wasBroadcastedCallback * @returns {Promise<*>} diff --git a/src/serializers/transaction.js b/src/serializers/transaction.js index 9eeaddc6..df59f849 100644 --- a/src/serializers/transaction.js +++ b/src/serializers/transaction.js @@ -1,6 +1,6 @@ import { struct, vector } from './collections'; import { uint16, uint32, int64 } from './basic/integers'; -import { timePointSec, bytes } from './basic'; +import { timePointSec, bytes, bool } from './basic'; import { extensions } from './chain'; import OperationSerializer from './operation'; import OperationResultSerializer from './operation_result'; @@ -17,6 +17,7 @@ export default transactionSerializer; export const signedTransactionSerializer = struct({ ...transactionSerializer.serializers, signatures: vector(bytes(64)), + signed_with_echorand_key: bool, }); export const processedTransactionSerializer = struct({ From f9b916ae2ebe65e12b7e4f2ef3d5003a06f3242b Mon Sep 17 00:00:00 2001 From: Mikhail Shautsou Date: Fri, 21 Feb 2020 15:54:22 +0300 Subject: [PATCH 32/62] comment api function --- src/echo/transaction.js | 40 ++++++++++++++++++++++++++++++++++++- types/echo/transaction.d.ts | 1 + 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/echo/transaction.js b/src/echo/transaction.js index 7bb734fd..12e7577e 100644 --- a/src/echo/transaction.js +++ b/src/echo/transaction.js @@ -51,7 +51,7 @@ class Transaction { /** @param {Api} value */ set api(value) { - if (!(value instanceof Api)) throw new Error('value is not a Api instance'); + // if (!(value instanceof Api)) throw new Error('value is not a Api instance'); /** * @private * @type {Api} @@ -249,6 +249,44 @@ class Transaction { this._signatures = this._signers.map(({ privateKey }) => Signature.signBuffer(bufferToSign, privateKey)); } + /** + * @param {PrivateKey=} _privateKey + * @param {Object=} dynamicGlobalChainData + */ + async offlineSign(_privateKey, dynamicGlobalChainData, chainId) { + this.checkNotFinalized(); + if (_privateKey !== undefined) this.addSigner(_privateKey); + if (!this.hasAllFees) await this.setRequiredFees(); + // const dynamicGlobalChainData = await this.api.getObject(DYNAMIC_GLOBAL_OBJECT_ID, true); + if (this.expiration === undefined) this.expiration = Math.ceil(Date.now() / 1e3) + EXPIRATION_SECONDS; + // const chainId = await this.api.getChainId(); + // one more check to avoid that the sign method was called several times + // without waiting for the first call to be executed + this.checkNotFinalized(); + this._finalized = true; + /** + * @private + * @type {number|undefined} + */ + this._refBlockNum = dynamicGlobalChainData.head_block_number & 0xffff; // eslint-disable-line no-bitwise + /** + * @private + * @type {number|undefined} + */ + this._refBlockPrefix = Buffer.from(dynamicGlobalChainData.head_block_id, 'hex').readUInt32LE(4); + const transactionBuffer = transaction.serialize({ + ref_block_num: this.refBlockNum, + ref_block_prefix: this.refBlockPrefix, + expiration: this.expiration, + operations: this.operations, + extensions: [], + }); + + const chainBuffer = Buffer.from(chainId, 'hex'); + const bufferToSign = Buffer.concat([chainBuffer, Buffer.from(transactionBuffer)]); + this._signatures = this._signers.map(({ privateKey }) => Signature.signBuffer(bufferToSign, privateKey)); + } + /** * @returns {Promise<{ publicKeys:Array }>} */ diff --git a/types/echo/transaction.d.ts b/types/echo/transaction.d.ts index e473937b..1af18f17 100644 --- a/types/echo/transaction.d.ts +++ b/types/echo/transaction.d.ts @@ -46,4 +46,5 @@ export default class Transaction { broadcast(wasBroadcastedCallback?: () => any): Promise<[BroadcastingResult]>; setRequiredFees(assetId?: string): Promise; serialize(): Buffer; + signedTransactionSerializer(): Buffer; } From 0a7f28f000a6c653328cee38e1c9333ea7ef2775 Mon Sep 17 00:00:00 2001 From: alesichko Date: Wed, 26 Feb 2020 12:27:47 +0300 Subject: [PATCH 33/62] add in transaction sing ability to sing offline --- src/constants/chain-config.js | 1 + src/echo/transaction.js | 130 ++++++++++++-------------- test/transaction.test.js | 166 +++++++++++++++++++++++++++++----- 3 files changed, 205 insertions(+), 92 deletions(-) diff --git a/src/constants/chain-config.js b/src/constants/chain-config.js index 9a4d9fe6..ee1097fa 100644 --- a/src/constants/chain-config.js +++ b/src/constants/chain-config.js @@ -3,6 +3,7 @@ export const ADDRESS_PREFIX = 'ECHO'; export const EXPIRE_IN_SECONDS = 15; export const EXPIRE_IN_SECONDS_PROPOSAL = 24 * 60 * 60; export const REVIEW_IN_SECONDS_COMMITTEE = 24 * 60 * 60; +export const CHAIN_ID_LENGTH = 64; export const NETWORKS = { ECHO_DEV: { diff --git a/src/echo/transaction.js b/src/echo/transaction.js index 12e7577e..d6e487b7 100644 --- a/src/echo/transaction.js +++ b/src/echo/transaction.js @@ -2,11 +2,18 @@ import BigNumber from 'bignumber.js'; import { cloneDeep } from 'lodash'; import Api from './api'; -import { isObject, validateUnsignedSafeInteger } from '../utils/validators'; +import { + isObject, + validateUnsignedSafeInteger, + validatePositiveSafeInteger, + isHex, + isBuffer, + isUInt32, +} from '../utils/validators'; import PrivateKey from '../crypto/private-key'; import PublicKey from '../crypto/public-key'; import Signature from '../crypto/signature'; -import { ECHO_ASSET_ID, DYNAMIC_GLOBAL_OBJECT_ID } from '../constants'; +import { ECHO_ASSET_ID, DYNAMIC_GLOBAL_OBJECT_ID, CHAIN_CONFIG } from '../constants'; import { EXPIRATION_SECONDS } from '../constants/api-config'; import { transaction, signedTransaction, operation } from '../serializers'; @@ -17,23 +24,47 @@ import { transaction, signedTransaction, operation } from '../serializers'; class Transaction { /** - * @readonly * @type {number} */ get refBlockNum() { - this.checkFinalized(); return this._refBlockNum; } + /** @param {number|undefined} value */ + set refBlockNum(value) { + validatePositiveSafeInteger(value); + if ((value > 0xffff)) throw new Error('number is not safe'); + this._refBlockNum = value; + } + /** * @readonly * @type {number} */ get refBlockPrefix() { - this.checkFinalized(); return this._refBlockPrefix; } + /** @param {string|number|buffer|undefined} value */ + set refBlockPrefix(value) { + if (!isUInt32(value) && !isHex(value) && !isBuffer(value)) throw new Error('invalid refBlockPrefix format'); + this._refBlockPrefix = Buffer.from(value, 'hex').readUInt32LE(4); + } + + /** @param {string|undefined} value */ + set chainId(value) { + if (!isHex(value) && value.length !== CHAIN_CONFIG.CHAIN_ID_LENGTH) { + throw new Error('invalid chainId format or length'); + } + this._chainId = value; + } + + /** + * @readonly + * @type {string} + */ + get chainId() { return this._chainId; } + /** * @readonly * @type {Array<_Operation>} @@ -44,14 +75,19 @@ class Transaction { * @readonly * @type {boolean} */ - get finalized() { return this._finalized; } + get finalized() { + return this._refBlockNum !== undefined && + this._refBlockPrefix !== undefined && !!this._chainId && this.hasAllFees; + } /** @type {Api} */ - get api() { return this._api; } + get api() { + if (!(this._api instanceof Api)) throw new Error('value is not a Api instance'); + return this._api; + } /** @param {Api} value */ set api(value) { - // if (!(value instanceof Api)) throw new Error('value is not a Api instance'); /** * @private * @type {Api} @@ -98,11 +134,6 @@ class Transaction { * @type {Array} */ this._signatures = []; - /** - * @private - * @type {boolean} - */ - this._finalized = false; /** * @private * @type {number} @@ -200,7 +231,6 @@ class Transaction { * @returns {Transaction} */ addSigner(privateKey, publicKey = privateKey.toPublicKey()) { - this.checkNotFinalized(); if (Buffer.isBuffer(privateKey)) privateKey = PrivateKey.fromBuffer(privateKey); if (!(privateKey instanceof PrivateKey)) throw new Error('private key is not instance of PrivateKey class'); if (!(publicKey instanceof PublicKey)) throw new Error('public key is not instance of PublicKey class'); @@ -216,64 +246,24 @@ class Transaction { * @param {PrivateKey=} _privateKey */ async sign(_privateKey) { - this.checkNotFinalized(); if (_privateKey !== undefined) this.addSigner(_privateKey); - if (!this.hasAllFees) await this.setRequiredFees(); - const dynamicGlobalChainData = await this.api.getObject(DYNAMIC_GLOBAL_OBJECT_ID, true); - if (this.expiration === undefined) this.expiration = Math.ceil(Date.now() / 1e3) + EXPIRATION_SECONDS; - const chainId = await this.api.getChainId(); - // one more check to avoid that the sign method was called several times - // without waiting for the first call to be executed - this.checkNotFinalized(); - this._finalized = true; - /** - * @private - * @type {number|undefined} - */ - this._refBlockNum = dynamicGlobalChainData.head_block_number & 0xffff; // eslint-disable-line no-bitwise - /** - * @private - * @type {number|undefined} - */ - this._refBlockPrefix = Buffer.from(dynamicGlobalChainData.head_block_id, 'hex').readUInt32LE(4); - const transactionBuffer = transaction.serialize({ - ref_block_num: this.refBlockNum, - ref_block_prefix: this.refBlockPrefix, - expiration: this.expiration, - operations: this.operations, - extensions: [], - }); - const chainBuffer = Buffer.from(chainId, 'hex'); - const bufferToSign = Buffer.concat([chainBuffer, Buffer.from(transactionBuffer)]); - this._signatures = this._signers.map(({ privateKey }) => Signature.signBuffer(bufferToSign, privateKey)); - } - - /** - * @param {PrivateKey=} _privateKey - * @param {Object=} dynamicGlobalChainData - */ - async offlineSign(_privateKey, dynamicGlobalChainData, chainId) { - this.checkNotFinalized(); - if (_privateKey !== undefined) this.addSigner(_privateKey); - if (!this.hasAllFees) await this.setRequiredFees(); - // const dynamicGlobalChainData = await this.api.getObject(DYNAMIC_GLOBAL_OBJECT_ID, true); + if (!this.finalized) { + if (!this.hasAllFees) await this.setRequiredFees(); + const dynamicGlobalChainData = await this.api.getObject(DYNAMIC_GLOBAL_OBJECT_ID, true); + if (!this.refBlockNum) { + // eslint-disable-next-line no-bitwise + this.refBlockNum = dynamicGlobalChainData.head_block_number; + } + if (!this.refBlockPrefix) { + this.refBlockPrefix = dynamicGlobalChainData.head_block_id; + } + if (!this.chainId) { + this.chainId = await this.api.getChainId(); + } + } if (this.expiration === undefined) this.expiration = Math.ceil(Date.now() / 1e3) + EXPIRATION_SECONDS; - // const chainId = await this.api.getChainId(); - // one more check to avoid that the sign method was called several times - // without waiting for the first call to be executed - this.checkNotFinalized(); - this._finalized = true; - /** - * @private - * @type {number|undefined} - */ - this._refBlockNum = dynamicGlobalChainData.head_block_number & 0xffff; // eslint-disable-line no-bitwise - /** - * @private - * @type {number|undefined} - */ - this._refBlockPrefix = Buffer.from(dynamicGlobalChainData.head_block_id, 'hex').readUInt32LE(4); + const transactionBuffer = transaction.serialize({ ref_block_num: this.refBlockNum, ref_block_prefix: this.refBlockPrefix, @@ -282,7 +272,7 @@ class Transaction { extensions: [], }); - const chainBuffer = Buffer.from(chainId, 'hex'); + const chainBuffer = Buffer.from(this.chainId, 'hex'); const bufferToSign = Buffer.concat([chainBuffer, Buffer.from(transactionBuffer)]); this._signatures = this._signers.map(({ privateKey }) => Signature.signBuffer(bufferToSign, privateKey)); } diff --git a/test/transaction.test.js b/test/transaction.test.js index 05f06cc7..7c20873a 100644 --- a/test/transaction.test.js +++ b/test/transaction.test.js @@ -1,18 +1,24 @@ import 'mocha'; import { expect } from 'chai'; -import { Echo } from '../src'; -import Transaction from '../src/echo/transaction'; +import { Echo, Transaction } from '../src'; import { strictEqual, notStrictEqual, deepStrictEqual, fail, ok } from 'assert'; import { TRANSFER } from '../src/constants/operations-ids'; import PrivateKey from '../src/crypto/private-key'; -import { url } from './_test-data'; +import { url, WIF } from './_test-data'; import { ACCOUNT, ASSET} from '../src/constants/object-types'; +import { DYNAMIC_GLOBAL_OBJECT_ID } from '../src/constants'; const echo = new Echo(); +const options = { + from: `1.${ACCOUNT}.6`, + to: `1.${ACCOUNT}.10`, + amount: { asset_id: `1.${ASSET}.0`, amount: 1000 }, + fee: { asset_id: '1.3.0', amount: 300 }, +}; -describe.skip('Transaction', () => { +describe.only('Transaction', () => { //skip before(() => echo.connect(url)); @@ -27,7 +33,7 @@ describe.skip('Transaction', () => { // deepStrictEqual(transaction.operations, []); // }); // }); - + // // describe('addOperation', () => { // describe('failure', () => { // it('without name', () => { @@ -67,7 +73,7 @@ describe.skip('Transaction', () => { // // TODO: test with excess fields // }); // }); - + // // describe('setRequiredFees', () => { // describe('failure', () => { // it('no operations', async () => { @@ -110,10 +116,10 @@ describe.skip('Transaction', () => { // strictEqual(fee.asset_id, `1.${ASSET}.1`); // ok(fee.amount > 0); // }); - + // // }); // }); - + // // describe('broadcast', () => { // it('qwe', async () => { // const pk = 'WIF'; @@ -129,19 +135,135 @@ describe.skip('Transaction', () => { // }).timeout(11000); // }); - describe('get potential signatures', () => { - it('asd', async () => { - const pk = '5KPT6sFAgx8sEiNyuF2QijsNCAPAvs4r6MV9Vn26z4NuTv86mfd'; - const transaction = echo.createTransaction(); - transaction.addOperation(TRANSFER, { - from: `1.${ACCOUNT}.6`, - to: `1.${ACCOUNT}.7`, - amount: { asset_id: `1.${ASSET}.0`, amount: 1000 }, - }); - // await transaction.sign(PrivateKey.fromWif(pk)); - // console.log(await transaction.broadcast(console.log)); - console.log(await transaction.getPotentialSignatures()); - }).timeout(12e3); - }); + // describe('get potential signatures', () => { + // it('asd', async () => { + // const pk = '5KPT6sFAgx8sEiNyuF2QijsNCAPAvs4r6MV9Vn26z4NuTv86mfd'; + // const transaction = echo.createTransaction(); + // transaction.addOperation(TRANSFER, { + // from: `1.${ACCOUNT}.6`, + // to: `1.${ACCOUNT}.7`, + // amount: { asset_id: `1.${ASSET}.0`, amount: 1000 }, + // }); + // // await transaction.sign(PrivateKey.fromWif(pk)); + // // console.log(await transaction.broadcast(console.log)); + // console.log(await transaction.getPotentialSignatures()); + // }).timeout(12e3); + // }); + + describe('sing transaction offline', () => { + //create 2 different instance of ECHO 1 use for getting data, second for use TX and offline sing + it('should fall, already finalized', async () => { + const tx = echo.createTransaction(); + const dynamicGlobalChainData = await echo.api.getObject(DYNAMIC_GLOBAL_OBJECT_ID, true); + tx.chainId = await echo.api.getChainId(); + tx.refBlockNum = dynamicGlobalChainData.head_block_number; + tx.refBlockPrefix = dynamicGlobalChainData.head_block_id; + try { + tx.addOperation(TRANSFER, options); + } catch (err) { + expect(err.message).to.equal('already finalized'); + } + }).timeout(11000); + it('should fall, when use invalid chainId data', async () => { + const tx = new Transaction(); + try { + tx.chainId = 'you shall not pass!!!'; + } catch (err) { + expect(err.message).to.equal('invalid chainId format or length'); + } + }); + it('should fall, when use negative refBlockNum value', async () => { + const tx = new Transaction(); + try { + tx.refBlockNum = -1; + } catch (err) { + expect(err.message).to.equal('value is not positive'); + } + }); + it('should fall, when use not integer as refBlockNum value', async () => { + const tx = new Transaction(); + try { + tx.refBlockNum = 1.23; + await tx.sign(privateKey); + } catch (err) { + expect(err.message).to.equal('undefined is not a integer'); + } + }); + it('should fall, when use not a number as refBlockNum value', async () => { + const tx = new Transaction(); + try { + tx.refBlockNum = 'you shall not pass!!!'; + await tx.sign(privateKey); + } catch (err) { + expect(err.message).to.equal('undefined is not a number'); + } + }); + it('should fall, when use not safe number as refBlockNum value', async () => { + const tx = new Transaction(); + try { + tx.refBlockNum = 100000000000000; + await tx.sign(privateKey); + } catch (err) { + expect(err.message).to.equal('number is not safe'); + } + }); + it('should fall, when use not UInt32 as refBlockPrefix value', async () => { + const tx = new Transaction(); + try { + tx.refBlockPrefix = 'notPass'; + await tx.sign(privateKey); + } catch (err) { + expect(err.message).to.equal('invalid refBlockPrefix format'); + } + }); + it('should fall, when use offline sign did not provide all needed data', async () => { + const tx = new Transaction(); + const dynamicGlobalChainData = await echo.api.getObject(DYNAMIC_GLOBAL_OBJECT_ID, true); + const privateKey = PrivateKey.fromWif(WIF); + tx.addOperation(TRANSFER, options); + tx.refBlockNum = dynamicGlobalChainData.head_block_number; + try { + await tx.sign(privateKey); + } catch (err) { + expect(err.message).to.equal('value is not a Api instance'); + } + }); + it('should succeeded, sing offline and broadcast', async () => { + const tx = new Transaction(); + const dynamicGlobalChainData = await echo.api.getObject(DYNAMIC_GLOBAL_OBJECT_ID, true); + const privateKey = PrivateKey.fromWif(WIF); + tx.addOperation(TRANSFER, options); + tx.chainId = await echo.api.getChainId(); + tx.refBlockNum = dynamicGlobalChainData.head_block_number; + tx.refBlockPrefix = dynamicGlobalChainData.head_block_id; + await tx.sign(privateKey); + // const result2 = await tx.broadcast((res) => console.log('res', res)); + // console.log('result2', result2); + }); + }); + describe('sing transaction online', () => { + it('should fall, when try sing offline', async () => { + const tx = new Transaction(); + const dynamicGlobalChainData = await echo.api.getObject(DYNAMIC_GLOBAL_OBJECT_ID, true); + const privateKey = PrivateKey.fromWif(WIF); + tx.addOperation(TRANSFER, options); + tx.refBlockPrefix = dynamicGlobalChainData.head_block_id; + try { + await tx.sign(privateKey); + } catch (err) { + expect(err.message).to.equal('value is not a Api instance'); + } + }); + it.skip('should succeeded, sing with provided data and get rest of needed data', async () => { + const dynamicGlobalChainData = await echo.api.getObject(DYNAMIC_GLOBAL_OBJECT_ID, true); + const privateKey = PrivateKey.fromWif(WIF); + const tx = echo.createTransaction(); + tx.addOperation(TRANSFER, options); + tx.refBlockPrefix = dynamicGlobalChainData.head_block_id; + await tx.sign(privateKey); + const result2 = await tx.broadcast((res) => console.log('res', res)); + console.log('result2', result2); + }) + }) }); From 6fea0f755c7edd82d35d6716b051cec2c8478278 Mon Sep 17 00:00:00 2001 From: Ales Pazniak Date: Thu, 27 Feb 2020 17:44:31 +0300 Subject: [PATCH 34/62] tools for sendSignedTransaction --- src/crypto/ecdsa.js | 2 +- src/echo/subscriber.js | 8 ++++---- src/echo/ws/reconnection-websocket.js | 2 +- src/serializers/collections/Set.js | 2 +- test/wallet-api.test.js | 16 ++++++++-------- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/crypto/ecdsa.js b/src/crypto/ecdsa.js index 99b3d04d..0ccc5395 100644 --- a/src/crypto/ecdsa.js +++ b/src/crypto/ecdsa.js @@ -13,7 +13,7 @@ import { validateUnsignedSafeInteger } from '../utils/validators'; */ export function deterministicGenerateK(curve, hash, d, checkSig, nonce) { if (nonce) hash = sha256(Buffer.concat([hash, Buffer.alloc(nonce)])); - // sanity check + // sanity transaction.js if (hash.length !== 32) throw new Error('invalid sha256 hash length'); const x = d.toBuffer(32); let k = Buffer.alloc(32); diff --git a/src/echo/subscriber.js b/src/echo/subscriber.js index 68611554..4d52f597 100644 --- a/src/echo/subscriber.js +++ b/src/echo/subscriber.js @@ -186,7 +186,7 @@ class Subscriber extends EventEmitter { * @return {null} */ _updateObject(object) { - // check is id param exists -> if no - check settle order params + // transaction.js is id param exists -> if no - transaction.js settle order params if (!object.id) { if (object.balance && object.owner && object.settlement_date) { this.emit('settle-order-update', object); @@ -207,7 +207,7 @@ class Subscriber extends EventEmitter { [], ); - // check interested by id type + // transaction.js interested by id type if (isTransactionId(object.id)) { return null; } @@ -289,7 +289,7 @@ class Subscriber extends EventEmitter { return null; } - // check if dynamic global object + // transaction.js if dynamic global object if (isDynamicGlobalObjectId(object.id)) { const dynamicGlobalObject = new Map(object); @@ -498,7 +498,7 @@ class Subscriber extends EventEmitter { const orders = []; const updates = messages.filter((msg) => { - // check is object id + // transaction.js is object id if (isObjectId(msg)) { return false; } diff --git a/src/echo/ws/reconnection-websocket.js b/src/echo/ws/reconnection-websocket.js index df9b9a8f..f57e7092 100644 --- a/src/echo/ws/reconnection-websocket.js +++ b/src/echo/ws/reconnection-websocket.js @@ -364,7 +364,7 @@ class ReconnectionWebSocket { } /** - * make call for check connection + * make call for transaction.js connection * @private */ async _ping() { diff --git a/src/serializers/collections/Set.js b/src/serializers/collections/Set.js index ab61a905..3d5eebeb 100644 --- a/src/serializers/collections/Set.js +++ b/src/serializers/collections/Set.js @@ -59,7 +59,7 @@ export default class SetSerializer extends VectorSerializer { */ readFromBuffer(buffer, offset = 0) { const { res, newOffset } = super.readFromBuffer(buffer, offset); - // `this.toRaw` is used here to check duplicates + // `this.toRaw` is used here to transaction.js duplicates return { res: this.toRaw(res), newOffset }; } diff --git a/test/wallet-api.test.js b/test/wallet-api.test.js index be4a9dbe..7e1d8269 100644 --- a/test/wallet-api.test.js +++ b/test/wallet-api.test.js @@ -539,7 +539,7 @@ describe('WALLET API', () => { useEthereumAssetAccuracy, shouldSaveToWallet, ); - + contractResultId = result.operation_results[0][1]; expect(result) .to @@ -1048,7 +1048,7 @@ describe('WALLET API', () => { }).timeout(5000); }); - + describe('#listAssets()', () => { it('Should get lists of all assets registered', async () => { const result = await echo.walletApi.listAssets( @@ -1269,7 +1269,7 @@ describe('WALLET API', () => { } }).timeout(5000); }); - + describe.skip('#issueAsset()', () => { it('Should do issue new shares of an asset', async () => { try { @@ -1410,7 +1410,7 @@ describe('WALLET API', () => { bitassetOpts, shouldDoBroadcastToNetwork, ); - console.log('check', check.operations[0][1]); + console.log('transaction.js.js', check.operations[0][1]); const bitasset = '1.3.0'; const result = await echo.walletApi.getBitassetData(bitasset); expect(result) @@ -1554,7 +1554,7 @@ describe('WALLET API', () => { } }).timeout(5000); }); - + describe.skip('#proposeParameterChange()', () => { it('Should creates a transaction to propose a parameter change', async () => { try { @@ -1859,7 +1859,7 @@ describe('WALLET API', () => { }).timeout(5000); }); - + describe('TRANSACTION BUILDER', () => { beforeEach(async () => await echo.walletApi.beginBuilderTransaction()); @@ -2114,7 +2114,7 @@ describe('WALLET API', () => { expect(result) .to .be - .an('object').that.is.not.empty; + .an('object').that.is.not.empty; } catch (e) { console.log(e); throw e; @@ -2179,7 +2179,7 @@ describe('WALLET API', () => { expect(result[0].extensions) .to .be - .an('array'); + .an('array'); } catch (e) { console.log(e); throw e; From 3b19ffdf64bae6cf40a06984be4bc119f5821902 Mon Sep 17 00:00:00 2001 From: Ales Pazniak Date: Fri, 28 Feb 2020 10:46:23 +0300 Subject: [PATCH 35/62] changed method sing and set/get api --- src/echo/transaction.js | 19 ++++++++++++++----- test/transaction.test.js | 7 ++++--- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/echo/transaction.js b/src/echo/transaction.js index d6e487b7..ffbb32f0 100644 --- a/src/echo/transaction.js +++ b/src/echo/transaction.js @@ -82,12 +82,13 @@ class Transaction { /** @type {Api} */ get api() { - if (!(this._api instanceof Api)) throw new Error('value is not a Api instance'); + if (!this._api) throw new Error('Api instance does not exist, check your connection'); return this._api; } /** @param {Api} value */ set api(value) { + if (value && !(value instanceof Api)) throw new Error('value is not a Api instance'); /** * @private * @type {Api} @@ -144,6 +145,14 @@ class Transaction { checkNotFinalized() { if (this.finalized) throw new Error('already finalized'); } checkFinalized() { if (!this.finalized) throw new Error('transaction is not finalized'); } + async getGlobalChainData() { + if (this.refBlockPrefix && this.refBlockNum) { + return { refBlockNum: this.refBlockNum, refBlockPrefix: this.refBlockPrefix }; + } + const globalChainData = await this.api.getObject(DYNAMIC_GLOBAL_OBJECT_ID, true); + return { refBlockNum: globalChainData.head_block_number, refBlockPrefix: globalChainData.head_block_id }; + } + /** * @param {OperationId} operationId * @param {{ [key: string]: any }} [props] @@ -249,14 +258,14 @@ class Transaction { if (_privateKey !== undefined) this.addSigner(_privateKey); if (!this.finalized) { + const { refBlockNum, refBlockPrefix } = await this.getGlobalChainData(); + if (!this.hasAllFees) await this.setRequiredFees(); - const dynamicGlobalChainData = await this.api.getObject(DYNAMIC_GLOBAL_OBJECT_ID, true); if (!this.refBlockNum) { - // eslint-disable-next-line no-bitwise - this.refBlockNum = dynamicGlobalChainData.head_block_number; + this.refBlockNum = refBlockNum; } if (!this.refBlockPrefix) { - this.refBlockPrefix = dynamicGlobalChainData.head_block_id; + this.refBlockPrefix = refBlockPrefix; } if (!this.chainId) { this.chainId = await this.api.getChainId(); diff --git a/test/transaction.test.js b/test/transaction.test.js index 7c20873a..fecaef1d 100644 --- a/test/transaction.test.js +++ b/test/transaction.test.js @@ -18,7 +18,7 @@ const options = { fee: { asset_id: '1.3.0', amount: 300 }, }; -describe.only('Transaction', () => { //skip +describe('Transaction', () => { before(() => echo.connect(url)); @@ -225,7 +225,7 @@ describe.only('Transaction', () => { //skip try { await tx.sign(privateKey); } catch (err) { - expect(err.message).to.equal('value is not a Api instance'); + expect(err.message).to.equal('Api instance does not exist, check your connection'); } }); it('should succeeded, sing offline and broadcast', async () => { @@ -251,7 +251,8 @@ describe.only('Transaction', () => { //skip try { await tx.sign(privateKey); } catch (err) { - expect(err.message).to.equal('value is not a Api instance'); + console.log('err.message', err.message); + expect(err.message).to.equal('Api instance does not exist, check your connection'); } }); it.skip('should succeeded, sing with provided data and get rest of needed data', async () => { From f9c5ef825aa22b83a8caae2a450a69735bca7957 Mon Sep 17 00:00:00 2001 From: Ales Pazniak Date: Fri, 28 Feb 2020 14:18:37 +0300 Subject: [PATCH 36/62] fixed set/get api in Transaction --- src/echo/transaction.js | 8 +++++--- test/transaction.test.js | 23 +++++++++++++---------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/echo/transaction.js b/src/echo/transaction.js index ffbb32f0..496b74c1 100644 --- a/src/echo/transaction.js +++ b/src/echo/transaction.js @@ -7,7 +7,6 @@ import { validateUnsignedSafeInteger, validatePositiveSafeInteger, isHex, - isBuffer, isUInt32, } from '../utils/validators'; import PrivateKey from '../crypto/private-key'; @@ -47,8 +46,11 @@ class Transaction { /** @param {string|number|buffer|undefined} value */ set refBlockPrefix(value) { - if (!isUInt32(value) && !isHex(value) && !isBuffer(value)) throw new Error('invalid refBlockPrefix format'); - this._refBlockPrefix = Buffer.from(value, 'hex').readUInt32LE(4); + if (isHex(value) || isUInt32(value)) { + this._refBlockPrefix = Buffer.from(value, 'hex').readUInt32LE(4); + return; + } + throw new Error('invalid refBlockPrefix format'); } /** @param {string|undefined} value */ diff --git a/test/transaction.test.js b/test/transaction.test.js index fecaef1d..67205997 100644 --- a/test/transaction.test.js +++ b/test/transaction.test.js @@ -14,11 +14,11 @@ const echo = new Echo(); const options = { from: `1.${ACCOUNT}.6`, to: `1.${ACCOUNT}.10`, - amount: { asset_id: `1.${ASSET}.0`, amount: 1000 }, - fee: { asset_id: '1.3.0', amount: 300 }, + amount: { asset_id: `1.${ASSET}.0`, amount: 10 }, + fee: { asset_id: '1.3.0', amount: 0 }, }; -describe('Transaction', () => { +describe.only('Transaction', () => { //skip before(() => echo.connect(url)); @@ -155,9 +155,13 @@ describe('Transaction', () => { it('should fall, already finalized', async () => { const tx = echo.createTransaction(); const dynamicGlobalChainData = await echo.api.getObject(DYNAMIC_GLOBAL_OBJECT_ID, true); - tx.chainId = await echo.api.getChainId(); + console.log('dynamicGlobalChainData.head_block_id', dynamicGlobalChainData.head_block_id); tx.refBlockNum = dynamicGlobalChainData.head_block_number; tx.refBlockPrefix = dynamicGlobalChainData.head_block_id; + tx.chainId = await echo.api.getChainId(); + // tx.refBlockNum = dynamicGlobalChainData.head_block_number; + // tx.refBlockPrefix = dynamicGlobalChainData.head_block_id; + try { tx.addOperation(TRANSFER, options); } catch (err) { @@ -233,11 +237,13 @@ describe('Transaction', () => { const dynamicGlobalChainData = await echo.api.getObject(DYNAMIC_GLOBAL_OBJECT_ID, true); const privateKey = PrivateKey.fromWif(WIF); tx.addOperation(TRANSFER, options); - tx.chainId = await echo.api.getChainId(); + const chainId = await echo.api.getChainId(); + tx.chainId = chainId.slice(2); tx.refBlockNum = dynamicGlobalChainData.head_block_number; tx.refBlockPrefix = dynamicGlobalChainData.head_block_id; await tx.sign(privateKey); - // const result2 = await tx.broadcast((res) => console.log('res', res)); + console.log('tx', tx._operations[0]); + // const result2 = await /*tx.broadcast*/echo.api.broadcastTransactionWithCallback(tx,(res) => console.log('res', res)); // console.log('result2', result2); }); }); @@ -251,19 +257,16 @@ describe('Transaction', () => { try { await tx.sign(privateKey); } catch (err) { - console.log('err.message', err.message); expect(err.message).to.equal('Api instance does not exist, check your connection'); } }); - it.skip('should succeeded, sing with provided data and get rest of needed data', async () => { + it('should succeeded, sing with provided data and get rest of needed data', async () => { const dynamicGlobalChainData = await echo.api.getObject(DYNAMIC_GLOBAL_OBJECT_ID, true); const privateKey = PrivateKey.fromWif(WIF); const tx = echo.createTransaction(); tx.addOperation(TRANSFER, options); tx.refBlockPrefix = dynamicGlobalChainData.head_block_id; await tx.sign(privateKey); - const result2 = await tx.broadcast((res) => console.log('res', res)); - console.log('result2', result2); }) }) From 6b4d3a2546b4c585c32e708afdb1f57d515542d3 Mon Sep 17 00:00:00 2001 From: Ales Pazniak Date: Fri, 28 Feb 2020 15:28:46 +0300 Subject: [PATCH 37/62] fixed get/set chainId in Transaction --- src/echo/transaction.js | 15 ++++++++++----- test/transaction.test.js | 28 +++++++++++++++++----------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/echo/transaction.js b/src/echo/transaction.js index 496b74c1..b2d9b155 100644 --- a/src/echo/transaction.js +++ b/src/echo/transaction.js @@ -44,21 +44,26 @@ class Transaction { return this._refBlockPrefix; } - /** @param {string|number|buffer|undefined} value */ + /** @param {string|number|undefined} value */ set refBlockPrefix(value) { - if (isHex(value) || isUInt32(value)) { + if (isHex(value)) { this._refBlockPrefix = Buffer.from(value, 'hex').readUInt32LE(4); return; } + if (isUInt32(value)) { + this._refBlockPrefix = value; + return; + } throw new Error('invalid refBlockPrefix format'); } /** @param {string|undefined} value */ set chainId(value) { - if (!isHex(value) && value.length !== CHAIN_CONFIG.CHAIN_ID_LENGTH) { - throw new Error('invalid chainId format or length'); + if (isHex(value) && value.length === CHAIN_CONFIG.CHAIN_ID_LENGTH) { + this._chainId = value; + return; } - this._chainId = value; + throw new Error('invalid chainId format or length'); } /** diff --git a/test/transaction.test.js b/test/transaction.test.js index 67205997..96c996e4 100644 --- a/test/transaction.test.js +++ b/test/transaction.test.js @@ -2,23 +2,33 @@ import 'mocha'; import { expect } from 'chai'; import { Echo, Transaction } from '../src'; import { strictEqual, notStrictEqual, deepStrictEqual, fail, ok } from 'assert'; -import { TRANSFER } from '../src/constants/operations-ids'; +import { CONTRACT_CREATE, TRANSFER } from '../src/constants/operations-ids'; import PrivateKey from '../src/crypto/private-key'; import { url, WIF } from './_test-data'; import { ACCOUNT, ASSET} from '../src/constants/object-types'; import { DYNAMIC_GLOBAL_OBJECT_ID } from '../src/constants'; +import { bytecode } from './operations/_contract.test'; const echo = new Echo(); const options = { from: `1.${ACCOUNT}.6`, to: `1.${ACCOUNT}.10`, + // eth_accuracy: false, amount: { asset_id: `1.${ASSET}.0`, amount: 10 }, fee: { asset_id: '1.3.0', amount: 0 }, + extensions: [], +}; +const options2 = { + registrar: `1.${ACCOUNT}.6`, + value: { asset_id: '1.3.0', amount: 0 }, + eth_accuracy: false, + code: bytecode, + fee: { asset_id: '1.3.0', amount: 500 }, }; -describe.only('Transaction', () => { //skip +describe('Transaction', () => { //skip before(() => echo.connect(url)); @@ -151,7 +161,6 @@ describe.only('Transaction', () => { //skip // }); describe('sing transaction offline', () => { - //create 2 different instance of ECHO 1 use for getting data, second for use TX and offline sing it('should fall, already finalized', async () => { const tx = echo.createTransaction(); const dynamicGlobalChainData = await echo.api.getObject(DYNAMIC_GLOBAL_OBJECT_ID, true); @@ -159,9 +168,6 @@ describe.only('Transaction', () => { //skip tx.refBlockNum = dynamicGlobalChainData.head_block_number; tx.refBlockPrefix = dynamicGlobalChainData.head_block_id; tx.chainId = await echo.api.getChainId(); - // tx.refBlockNum = dynamicGlobalChainData.head_block_number; - // tx.refBlockPrefix = dynamicGlobalChainData.head_block_id; - try { tx.addOperation(TRANSFER, options); } catch (err) { @@ -237,13 +243,12 @@ describe.only('Transaction', () => { //skip const dynamicGlobalChainData = await echo.api.getObject(DYNAMIC_GLOBAL_OBJECT_ID, true); const privateKey = PrivateKey.fromWif(WIF); tx.addOperation(TRANSFER, options); - const chainId = await echo.api.getChainId(); - tx.chainId = chainId.slice(2); + tx.addOperation(CONTRACT_CREATE, options2); + tx.chainId = await echo.api.getChainId(); tx.refBlockNum = dynamicGlobalChainData.head_block_number; tx.refBlockPrefix = dynamicGlobalChainData.head_block_id; await tx.sign(privateKey); - console.log('tx', tx._operations[0]); - // const result2 = await /*tx.broadcast*/echo.api.broadcastTransactionWithCallback(tx,(res) => console.log('res', res)); + // const result2 = await echo.api.broadcastTransactionWithCallback(tx); // console.log('result2', result2); }); }); @@ -267,7 +272,8 @@ describe.only('Transaction', () => { //skip tx.addOperation(TRANSFER, options); tx.refBlockPrefix = dynamicGlobalChainData.head_block_id; await tx.sign(privateKey); - }) + // await tx.broadcast(); + }); }) }); From 45a8ffd78507c7ac446ce40ed6e7463d14589275 Mon Sep 17 00:00:00 2001 From: Mikhail Shautsou Date: Fri, 28 Feb 2020 16:07:30 +0300 Subject: [PATCH 38/62] up version to 1.10.0-rc.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cdbab866..f699d8d8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "echojs-lib", - "version": "1.10.0-rc.2", + "version": "1.10.0-rc.3", "description": "Pure JavaScript ECHO library for node.js", "main": "./dist/index.js", "types": "./types/index.d.ts", From d84bc7d06e4783085e9413fe2921b8d79e684f47 Mon Sep 17 00:00:00 2001 From: "a.lozyuk" Date: Wed, 25 Mar 2020 22:15:08 +0300 Subject: [PATCH 39/62] [EEX-773] fix constacts for echo.17 --- docs/Constants.md | 44 +++++++++++-------- package.json | 2 +- src/constants/object-types.js | 1 + src/constants/operations-ids.js | 42 ++++++++++-------- src/serializers/chain/id/protocol.js | 1 + src/serializers/operation.js | 6 +++ src/serializers/protocol/evm_address.js | 14 ++++++ src/serializers/protocol/fee_parameters.js | 6 +++ src/serializers/protocol/index.js | 4 ++ src/serializers/protocol/sidechain/erc20.js | 14 ++++++ src/serializers/protocol/sidechain/eth.js | 23 +++++++++- src/serializers/protocol/sidechain/index.js | 5 +++ types/interfaces/OperationId.d.ts | 42 ++++++++++-------- types/interfaces/ProtocolObjectTypeId.d.ts | 3 +- types/serializers/chain/id/protocol.d.ts | 3 +- types/serializers/operation.d.ts | 6 +++ types/serializers/protocol/evm_address.d.ts | 11 +++++ .../serializers/protocol/fee_parameters.d.ts | 6 +++ types/serializers/protocol/index.d.ts | 2 + .../serializers/protocol/sidechain/erc20.d.ts | 14 ++++++ types/serializers/protocol/sidechain/eth.d.ts | 25 ++++++++++- .../serializers/protocol/sidechain/index.d.ts | 5 +++ 22 files changed, 219 insertions(+), 60 deletions(-) create mode 100644 src/serializers/protocol/evm_address.js create mode 100644 types/serializers/protocol/evm_address.d.ts diff --git a/docs/Constants.md b/docs/Constants.md index a40375bf..1aa209d1 100644 --- a/docs/Constants.md +++ b/docs/Constants.md @@ -230,24 +230,30 @@ console.log(constants.OPERATIONS_IDS); // operation id SIDECHAIN_ETH_CREATE_ADDRESS: 39, SIDECHAIN_ETH_APPROVE_ADDRESS: 40, SIDECHAIN_ETH_DEPOSIT: 41, - SIDECHAIN_ETH_WITHDRAW: 42, - SIDECHAIN_ETH_APPROVE_WITHDRAW: 43, - SIDECHAIN_ISSUE: 44, // VIRTUAL - SIDECHAIN_BURN: 45, // VIRTUAL - SIDECHAIN_ERC20_REGISTER_TOKEN: 46, - SIDECHAIN_ERC20_DEPOSIT_TOKEN: 47, - SIDECHAIN_ERC20_WITHDRAW_TOKEN: 48, - SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW: 49, - SIDECHAIN_ERC20_ISSUE: 50, // VIRTUAL - SIDECHAIN_ERC20_BURN: 51, // VIRTUAL - SIDECHAIN_BTC_CREATE_ADDRESS: 52, - SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT: 53, - SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT: 54, - SIDECHAIN_BTC_DEPOSIT: 55, - SIDECHAIN_BTC_WITHDRAW: 56, - SIDECHAIN_BTC_APPROVE_WITHDRAW: 57, - SIDECHAIN_BTC_AGGREGATE: 58, - BLOCK_REWARD: 59,// VIRTUAL -} + SIDECHAIN_ETH_SEND_DEPOSIT = 42; + SIDECHAIN_ETH_WITHDRAW = 43; + SIDECHAIN_ETH_SEND_WITHDRAW = 44; + SIDECHAIN_ETH_APPROVE_WITHDRAW = 45; + SIDECHAIN_ETH_UPDATE_CONTRACT_ADDRESS = 46; + SIDECHAIN_ISSUE = 47; // VIRTUAL + SIDECHAIN_BURN = 48; // VIRTUAL + SIDECHAIN_ERC20_REGISTER_TOKEN = 49; + SIDECHAIN_ERC20_DEPOSIT_TOKEN = 50; + SIDECHAIN_ERC20_SEND_DEPOSIT_TOKEN = 51; + SIDECHAIN_ERC20_WITHDRAW_TOKEN = 52; + SIDECHAIN_ERC20_SEND_WITHDRAW_TOKEN = 53; + SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 54; + SIDECHAIN_ERC20_ISSUE = 55; // VIRTUAL + SIDECHAIN_ERC20_BURN = 56; // VIRTUAL + SIDECHAIN_BTC_CREATE_ADDRESS = 57; + SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 58; + SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 59; + SIDECHAIN_BTC_DEPOSIT = 60; + SIDECHAIN_BTC_WITHDRAW = 61; + SIDECHAIN_BTC_AGGREGATE = 62; + SIDECHAIN_BTC_APPROVE_AGGREGATE = 63; + BLOCK_REWARD = 64;// VIRTUAL + EVM_ADDRESS_REGISTER = 65; + } */ ``` diff --git a/package.json b/package.json index 5e0e0561..d308a10a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "echojs-lib", - "version": "1.11.0-rc.1", + "version": "1.9.11-echo.17", "description": "Pure JavaScript ECHO library for node.js", "main": "./dist/index.js", "types": "./types/index.d.ts", diff --git a/src/constants/object-types.js b/src/constants/object-types.js index 14c11bc1..b906f86b 100644 --- a/src/constants/object-types.js +++ b/src/constants/object-types.js @@ -22,4 +22,5 @@ export const BTC_INTERMEDIATE_DEPOSIT = 20; export const BTC_DEPOSIT = 21; export const BTC_WITHDRAW = 22; export const BTC_AGGREGATING = 23; +export const EVM_ADDRESS = 24; diff --git a/src/constants/operations-ids.js b/src/constants/operations-ids.js index dcabbe94..47476dec 100644 --- a/src/constants/operations-ids.js +++ b/src/constants/operations-ids.js @@ -40,21 +40,27 @@ export const CONTRACT_WHITELIST = 38; export const SIDECHAIN_ETH_CREATE_ADDRESS = 39; export const SIDECHAIN_ETH_APPROVE_ADDRESS = 40; export const SIDECHAIN_ETH_DEPOSIT = 41; -export const SIDECHAIN_ETH_WITHDRAW = 42; -export const SIDECHAIN_ETH_APPROVE_WITHDRAW = 43; -export const SIDECHAIN_ISSUE = 44; // VIRTUAL -export const SIDECHAIN_BURN = 45; // VIRTUAL -export const SIDECHAIN_ERC20_REGISTER_TOKEN = 46; -export const SIDECHAIN_ERC20_DEPOSIT_TOKEN = 47; -export const SIDECHAIN_ERC20_WITHDRAW_TOKEN = 48; -export const SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 49; -export const SIDECHAIN_ERC20_ISSUE = 50; // VIRTUAL -export const SIDECHAIN_ERC20_BURN = 51; // VIRTUAL -export const SIDECHAIN_BTC_CREATE_ADDRESS = 52; -export const SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 53; -export const SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 54; -export const SIDECHAIN_BTC_DEPOSIT = 55; -export const SIDECHAIN_BTC_WITHDRAW = 56; -export const SIDECHAIN_BTC_AGGREGATE = 57; -export const SIDECHAIN_BTC_APPROVE_AGGREGATE = 58; -export const BLOCK_REWARD = 59;// VIRTUAL +export const SIDECHAIN_ETH_SEND_DEPOSIT = 42; +export const SIDECHAIN_ETH_WITHDRAW = 43; +export const SIDECHAIN_ETH_SEND_WITHDRAW = 44; +export const SIDECHAIN_ETH_APPROVE_WITHDRAW = 45; +export const SIDECHAIN_ETH_UPDATE_CONTRACT_ADDRESS = 46; +export const SIDECHAIN_ISSUE = 47; // VIRTUAL +export const SIDECHAIN_BURN = 48; // VIRTUAL +export const SIDECHAIN_ERC20_REGISTER_TOKEN = 49; +export const SIDECHAIN_ERC20_DEPOSIT_TOKEN = 50; +export const SIDECHAIN_ERC20_SEND_DEPOSIT_TOKEN = 51; +export const SIDECHAIN_ERC20_WITHDRAW_TOKEN = 52; +export const SIDECHAIN_ERC20_SEND_WITHDRAW_TOKEN = 53; +export const SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 54; +export const SIDECHAIN_ERC20_ISSUE = 55; // VIRTUAL +export const SIDECHAIN_ERC20_BURN = 56; // VIRTUAL +export const SIDECHAIN_BTC_CREATE_ADDRESS = 57; +export const SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 58; +export const SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 59; +export const SIDECHAIN_BTC_DEPOSIT = 60; +export const SIDECHAIN_BTC_WITHDRAW = 61; +export const SIDECHAIN_BTC_AGGREGATE = 62; +export const SIDECHAIN_BTC_APPROVE_AGGREGATE = 63; +export const BLOCK_REWARD = 64;// VIRTUAL +export const EVM_ADDRESS_REGISTER = 65; diff --git a/src/serializers/chain/id/protocol.js b/src/serializers/chain/id/protocol.js index 0c94f44a..da8caedf 100644 --- a/src/serializers/chain/id/protocol.js +++ b/src/serializers/chain/id/protocol.js @@ -48,3 +48,4 @@ export const btcAggregatingId = new ObjectIdSerializer( PROTOCOL_OBJECT_TYPE_ID.BTC_AGGREGATING, ); +export const evmAddressId = new ObjectIdSerializer(RESERVED_SPACE_ID.PROTOCOL, PROTOCOL_OBJECT_TYPE_ID.EVM_ADDRESS); diff --git a/src/serializers/operation.js b/src/serializers/operation.js index 21334e75..b553003c 100644 --- a/src/serializers/operation.js +++ b/src/serializers/operation.js @@ -44,15 +44,20 @@ const operationProps = { [OPERATIONS_IDS.SIDECHAIN_ETH_CREATE_ADDRESS]: protocol.sidechain.eth.createAddress, [OPERATIONS_IDS.SIDECHAIN_ETH_APPROVE_ADDRESS]: protocol.sidechain.eth.approveAddress, [OPERATIONS_IDS.SIDECHAIN_ETH_DEPOSIT]: protocol.sidechain.eth.deposit, + [OPERATIONS_IDS.SIDECHAIN_ETH_SEND_DEPOSIT]: protocol.sidechain.eth.sendDeposit, [OPERATIONS_IDS.SIDECHAIN_ETH_WITHDRAW]: protocol.sidechain.eth.withdraw, + [OPERATIONS_IDS.SIDECHAIN_ETH_SEND_WITHDRAW]: protocol.sidechain.eth.sendWithdraw, [OPERATIONS_IDS.SIDECHAIN_ETH_APPROVE_WITHDRAW]: protocol.sidechain.eth.approveWithdraw, + [OPERATIONS_IDS.SIDECHAIN_ETH_UPDATE_CONTRACT_ADDRESS]: protocol.sidechain.eth.updateContractAddress, [OPERATIONS_IDS.CONTRACT_FUND_POOL]: protocol.contract.fundPool, [OPERATIONS_IDS.CONTRACT_WHITELIST]: protocol.contract.whitelist, [OPERATIONS_IDS.SIDECHAIN_ISSUE]: protocol.sidechain.issue, [OPERATIONS_IDS.SIDECHAIN_BURN]: protocol.sidechain.burn, [OPERATIONS_IDS.SIDECHAIN_ERC20_REGISTER_TOKEN]: protocol.sidechain.erc20.registerToken, [OPERATIONS_IDS.SIDECHAIN_ERC20_DEPOSIT_TOKEN]: protocol.sidechain.erc20.depositToken, + [OPERATIONS_IDS.SIDECHAIN_ERC20_SEND_DEPOSIT_TOKEN]: protocol.sidechain.erc20.sendDepositToken, [OPERATIONS_IDS.SIDECHAIN_ERC20_WITHDRAW_TOKEN]: protocol.sidechain.erc20.withdrawToken, + [OPERATIONS_IDS.SIDECHAIN_ERC20_SEND_WITHDRAW_TOKEN]: protocol.sidechain.erc20.sendWithdrawToken, [OPERATIONS_IDS.SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW]: protocol.sidechain.erc20.approveTokenWithdraw, [OPERATIONS_IDS.SIDECHAIN_ERC20_ISSUE]: protocol.sidechain.erc20.issue, [OPERATIONS_IDS.SIDECHAIN_ERC20_BURN]: protocol.sidechain.erc20.burn, @@ -64,6 +69,7 @@ const operationProps = { [OPERATIONS_IDS.SIDECHAIN_BTC_AGGREGATE]: protocol.sidechain.btc.aggregate, [OPERATIONS_IDS.SIDECHAIN_BTC_APPROVE_AGGREGATE]: protocol.sidechain.btc.approveAggregate, [OPERATIONS_IDS.BLOCK_REWARD]: protocol.blockReward, + [OPERATIONS_IDS.EVM_ADDRESS_REGISTER]: protocol.evmAddress, }; const operationSerializer = staticVariant(operationProps); diff --git a/src/serializers/protocol/evm_address.js b/src/serializers/protocol/evm_address.js new file mode 100644 index 00000000..e078e2af --- /dev/null +++ b/src/serializers/protocol/evm_address.js @@ -0,0 +1,14 @@ +import { asset, extensions } from '../chain'; +import { accountId } from '../chain/id/protocol'; +import { struct } from '../collections'; +import ethAddress from './ethAddress'; + + +const evmAddressRegisterOperationPropsSerializer = struct({ + fee: asset, + owner: accountId, + evm_address: ethAddress, + extensions, +}); + +export default evmAddressRegisterOperationPropsSerializer; diff --git a/src/serializers/protocol/fee_parameters.js b/src/serializers/protocol/fee_parameters.js index ecf1428d..8cc824b0 100644 --- a/src/serializers/protocol/fee_parameters.js +++ b/src/serializers/protocol/fee_parameters.js @@ -52,13 +52,18 @@ const feeParametersSerializer = staticVariant({ [OPERATIONS_IDS.SIDECHAIN_ETH_CREATE_ADDRESS]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ETH_APPROVE_ADDRESS]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ETH_DEPOSIT]: defaultFeeParametersSerializer, + [OPERATIONS_IDS.SIDECHAIN_ETH_SEND_DEPOSIT]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ETH_WITHDRAW]: defaultFeeParametersSerializer, + [OPERATIONS_IDS.SIDECHAIN_ETH_SEND_WITHDRAW]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ETH_APPROVE_WITHDRAW]: defaultFeeParametersSerializer, + [OPERATIONS_IDS.SIDECHAIN_ETH_UPDATE_CONTRACT_ADDRESS]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ISSUE]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_BURN]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ERC20_REGISTER_TOKEN]: struct({ fee: uint64, pool_fee: uint64 }), [OPERATIONS_IDS.SIDECHAIN_ERC20_DEPOSIT_TOKEN]: defaultFeeParametersSerializer, + [OPERATIONS_IDS.SIDECHAIN_ERC20_SEND_DEPOSIT_TOKEN]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ERC20_WITHDRAW_TOKEN]: defaultFeeParametersSerializer, + [OPERATIONS_IDS.SIDECHAIN_ERC20_SEND_WITHDRAW_TOKEN]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ERC20_ISSUE]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_ERC20_BURN]: defaultFeeParametersSerializer, @@ -70,5 +75,6 @@ const feeParametersSerializer = staticVariant({ [OPERATIONS_IDS.SIDECHAIN_BTC_AGGREGATE]: defaultFeeParametersSerializer, [OPERATIONS_IDS.SIDECHAIN_BTC_APPROVE_AGGREGATE]: defaultFeeParametersSerializer, [OPERATIONS_IDS.BLOCK_REWARD]: defaultFeeParametersSerializer, + [OPERATIONS_IDS.EVM_ADDRESS_REGISTER]: defaultFeeParametersSerializer, }); export default feeParametersSerializer; diff --git a/src/serializers/protocol/index.js b/src/serializers/protocol/index.js index 555be9a9..9653d059 100644 --- a/src/serializers/protocol/index.js +++ b/src/serializers/protocol/index.js @@ -75,6 +75,8 @@ import { import VoteIdSerializer from './VoteId'; +import evmAddress from './evm_address'; + export { AccountListingSerializer, accountListing, ACCOUNT_LISTING } from './account'; export const account = { @@ -173,3 +175,5 @@ export const voteId = new VoteIdSerializer(); export { VoteIdSerializer }; export { blockRewardOperationPropsSerializer as blockReward } from './block_reward'; + +export { evmAddress }; diff --git a/src/serializers/protocol/sidechain/erc20.js b/src/serializers/protocol/sidechain/erc20.js index 7d87d395..a3c95822 100644 --- a/src/serializers/protocol/sidechain/erc20.js +++ b/src/serializers/protocol/sidechain/erc20.js @@ -26,6 +26,13 @@ export const sidechainERC20DepositTokenOperationPropsSerializer = struct({ extensions, }); +export const sidechainERC20SendDepositTokenOperationPropsSerializer = struct({ + fee: asset, + committee_member_id: accountId, + deposit_id: depositErc20TokenId, + extensions, +}); + export const sidechainERC20WithdrawTokenOperationPropsSerializer = struct({ fee: asset, account: accountId, @@ -35,6 +42,13 @@ export const sidechainERC20WithdrawTokenOperationPropsSerializer = struct({ extensions, }); +export const sidechainERC20SendWithdrawTokenOperationPropsSerializer = struct({ + fee: asset, + committee_member_id: accountId, + deposit_id: depositErc20TokenId, + extensions, +}); + export const sidechainERC20ApproveTokenWithdrawOperationPropsSerializer = struct({ fee: asset, committee_member_id: accountId, diff --git a/src/serializers/protocol/sidechain/eth.js b/src/serializers/protocol/sidechain/eth.js index fa70c8c9..b0e8742e 100644 --- a/src/serializers/protocol/sidechain/eth.js +++ b/src/serializers/protocol/sidechain/eth.js @@ -1,7 +1,7 @@ import ethAddress from '../ethAddress'; import { uint64 } from '../../basic/integers'; import { asset, extensions } from '../../chain'; -import { accountId } from '../../chain/id/protocol'; +import { accountId, depositId } from '../../chain/id/protocol'; import { struct, vector } from '../../collections'; export const sidechainEthCreateAddressOperationPropsSerializer = struct({ @@ -28,6 +28,14 @@ export const sidechainEthDepositOperationPropsSerializer = struct({ extensions, }); +export const sidechainEthSendDepositOperationPropsSerializer = struct({ + fee: asset, + committee_member_id: accountId, + deposit_id: depositId, + extensions, +}); + + export const sidechainEthWithdrawOperationPropsSerializer = struct({ fee: asset, account: accountId, @@ -36,9 +44,22 @@ export const sidechainEthWithdrawOperationPropsSerializer = struct({ extensions, }); +export const sidechainEthSendWithdrawOperationPropsSerializer = struct({ + fee: asset, + committee_member_id: accountId, + deposit_id: depositId, + extensions, +}); + export const sidechainEthApproveWithdrawOperationPropsSerializer = struct({ fee: asset, committee_member_id: accountId, withdraw_id: uint64, extensions, }); + +export const sidechainEthUpdateContractAddressOperationPropsSerializer = struct({ + fee: asset, + new_addr: ethAddress, + extensions, +}); diff --git a/src/serializers/protocol/sidechain/index.js b/src/serializers/protocol/sidechain/index.js index 442988c0..6824e68c 100644 --- a/src/serializers/protocol/sidechain/index.js +++ b/src/serializers/protocol/sidechain/index.js @@ -25,7 +25,9 @@ export const sidechainBurnOperationPropsSerializer = struct({ export const erc20 = { registerToken: _erc20.sidechainERC20RegisterTokenOperationPropsSerializer, depositToken: _erc20.sidechainERC20DepositTokenOperationPropsSerializer, + sendDepositToken: _erc20.sidechainERC20SendDepositTokenOperationPropsSerializer, withdrawToken: _erc20.sidechainERC20WithdrawTokenOperationPropsSerializer, + sendWithdrawToken: _erc20.sidechainERC20SendWithdrawTokenOperationPropsSerializer, approveTokenWithdraw: _erc20.sidechainERC20ApproveTokenWithdrawOperationPropsSerializer, issue: _erc20.sidechainERC20IssueOperationPropsSerializer, burn: _erc20.sidechainERC20BurnOperationPropsSerializer, @@ -35,8 +37,11 @@ export const eth = { createAddress: _eth.sidechainEthCreateAddressOperationPropsSerializer, approveAddress: _eth.sidechainEthApproveAddressOperationPropsSerializer, deposit: _eth.sidechainEthDepositOperationPropsSerializer, + sendDeposit: _eth.sidechainEthSendDepositOperationPropsSerializer, withdraw: _eth.sidechainEthWithdrawOperationPropsSerializer, + sendWithdraw: _eth.sidechainEthSendWithdrawOperationPropsSerializer, approveWithdraw: _eth.sidechainEthApproveWithdrawOperationPropsSerializer, + updateContractAddress: _eth.sidechainEthUpdateContractAddressOperationPropsSerializer, }; export const btc = { diff --git a/types/interfaces/OperationId.d.ts b/types/interfaces/OperationId.d.ts index a5d62ae5..9a1cc49b 100644 --- a/types/interfaces/OperationId.d.ts +++ b/types/interfaces/OperationId.d.ts @@ -42,24 +42,30 @@ declare enum OperationId { SIDECHAIN_ETH_CREATE_ADDRESS = 39, SIDECHAIN_ETH_APPROVE_ADDRESS = 40, SIDECHAIN_ETH_DEPOSIT = 41, - SIDECHAIN_ETH_WITHDRAW = 42, - SIDECHAIN_ETH_APPROVE_WITHDRAW = 43, - SIDECHAIN_ISSUE = 44, // VIRTUAL - SIDECHAIN_BURN = 45, // VIRTUAL - SIDECHAIN_ERC20_REGISTER_TOKEN = 46, - SIDECHAIN_ERC20_DEPOSIT_TOKEN = 47, - SIDECHAIN_ERC20_WITHDRAW_TOKEN = 48, - SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 49, - SIDECHAIN_ERC20_ISSUE = 50, // VIRTUAL - SIDECHAIN_ERC20_BURN = 51, // VIRTUAL - SIDECHAIN_BTC_CREATE_ADDRESS = 52, - SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 53, - SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 54, - SIDECHAIN_BTC_DEPOSIT = 55, - SIDECHAIN_BTC_WITHDRAW = 56, - SIDECHAIN_BTC_AGGREGATE = 57, - SIDECHAIN_BTC_APPROVE_AGGREGATE = 58, - BLOCK_REWARD = 59,// VIRTUAL + SIDECHAIN_ETH_SEND_DEPOSIT = 42, + SIDECHAIN_ETH_WITHDRAW = 43, + SIDECHAIN_ETH_SEND_WITHDRAW = 44, + IDECHAIN_ETH_APPROVE_WITHDRAW = 45, + SIDECHAIN_ETH_UPDATE_CONTRACT_ADDRESS = 46, + SIDECHAIN_ISSUE = 47, // VIRTUAL + SIDECHAIN_BURN = 48, // VIRTUAL + SIDECHAIN_ERC20_REGISTER_TOKEN = 49, + SIDECHAIN_ERC20_DEPOSIT_TOKEN = 50, + SIDECHAIN_ERC20_SEND_DEPOSIT_TOKEN = 51, + SIDECHAIN_ERC20_WITHDRAW_TOKEN = 52, + SIDECHAIN_ERC20_SEND_WITHDRAW_TOKEN = 53, + SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW = 54, + SIDECHAIN_ERC20_ISSUE = 55, // VIRTUAL + SIDECHAIN_ERC20_BURN = 56, // VIRTUAL + SIDECHAIN_BTC_CREATE_ADDRESS = 57, + SIDECHAIN_BTC_CREATE_INTERMEDIATE_DEPOSIT = 58, + SIDECHAIN_BTC_INTERMEDIATE_DEPOSIT = 59, + SIDECHAIN_BTC_DEPOSIT = 60, + SIDECHAIN_BTC_WITHDRAW = 61, + SIDECHAIN_BTC_AGGREGATE = 62, + SIDECHAIN_BTC_APPROVE_AGGREGATE = 63, + BLOCK_REWARD = 64,// VIRTUAL + EVM_ADDRESS_REGISTER = 65, } diff --git a/types/interfaces/ProtocolObjectTypeId.d.ts b/types/interfaces/ProtocolObjectTypeId.d.ts index 640ffe2f..97921d65 100644 --- a/types/interfaces/ProtocolObjectTypeId.d.ts +++ b/types/interfaces/ProtocolObjectTypeId.d.ts @@ -22,7 +22,8 @@ declare enum PROTOCOL_OBJECT_TYPE_ID { BTC_INTERMEDIATE_DEPOSIT = 20, BTC_DEPOSIT = 21, BTC_WITHDRAW = 22, - BTC_AGGREGATING = 23 + BTC_AGGREGATING = 23, + EVM_ADDRESS = 24, } export default PROTOCOL_OBJECT_TYPE_ID; diff --git a/types/serializers/chain/id/protocol.d.ts b/types/serializers/chain/id/protocol.d.ts index 59dc464e..518e0447 100644 --- a/types/serializers/chain/id/protocol.d.ts +++ b/types/serializers/chain/id/protocol.d.ts @@ -17,4 +17,5 @@ export declare const btcAddressId: ObjectIdSerializer; export declare const btcDepositId: ObjectIdSerializer; export declare const btcWithdrawId: ObjectIdSerializer; -export const btcAggregatingId: ObjectIdSerializer; \ No newline at end of file +export declare const btcAggregatingId: ObjectIdSerializer; +export declare const evmAddressId: ObjectIdSerializer; diff --git a/types/serializers/operation.d.ts b/types/serializers/operation.d.ts index d7e1773f..ce43bea5 100644 --- a/types/serializers/operation.d.ts +++ b/types/serializers/operation.d.ts @@ -44,15 +44,20 @@ export type OperationPropsSerializer = { [OperationId.SIDECHAIN_ETH_CREATE_ADDRESS]: typeof protocol.sidechain.eth.createAddress, [OperationId.SIDECHAIN_ETH_APPROVE_ADDRESS]: typeof protocol.sidechain.eth.approveAddress, [OperationId.SIDECHAIN_ETH_DEPOSIT]: typeof protocol.sidechain.eth.deposit, + [OperationId.SIDECHAIN_ETH_SEND_DEPOSIT]: typeof protocol.sidechain.eth.sendDeposit, [OperationId.SIDECHAIN_ETH_WITHDRAW]: typeof protocol.sidechain.eth.withdraw, + [OperationId.SIDECHAIN_ETH_SEND_WITHDRAW]: typeof protocol.sidechain.eth.sendWithdraw, [OperationId.SIDECHAIN_ETH_APPROVE_WITHDRAW]: typeof protocol.sidechain.eth.approveWithdraw, + [OperationId.SIDECHAIN_ETH_UPDATE_CONTRACT_ADDRESS]: typeof protocol.sidechain.eth.updateContractAddress, [OperationId.CONTRACT_FUND_POOL]: typeof protocol.contract.fundPool, [OperationId.CONTRACT_WHITELIST]: typeof protocol.contract.whitelist, [OperationId.SIDECHAIN_ISSUE]: typeof protocol.sidechain.issue, [OperationId.SIDECHAIN_BURN]: typeof protocol.sidechain.burn, [OperationId.SIDECHAIN_ERC20_REGISTER_TOKEN]: typeof protocol.sidechain.erc20.registerToken, [OperationId.SIDECHAIN_ERC20_DEPOSIT_TOKEN]: typeof protocol.sidechain.erc20.depositToken, + [OperationId.SIDECHAIN_ERC20_SEND_DEPOSIT_TOKEN]: typeof protocol.sidechain.erc20.sendDepositToken, [OperationId.SIDECHAIN_ERC20_WITHDRAW_TOKEN]: typeof protocol.sidechain.erc20.withdrawToken, + [OperationId.SIDECHAIN_ERC20_SEND_WITHDRAW_TOKEN]: typeof protocol.sidechain.erc20.withdrawToken, [OperationId.SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW]: typeof protocol.sidechain.erc20.approveTokenWithdraw, [OperationId.SIDECHAIN_ERC20_ISSUE]: typeof protocol.sidechain.erc20.issue, [OperationId.SIDECHAIN_ERC20_BURN]: typeof protocol.sidechain.erc20.burn, @@ -64,6 +69,7 @@ export type OperationPropsSerializer = { [OperationId.SIDECHAIN_BTC_AGGREGATE]: typeof protocol.sidechain.btc.aggregate, [OperationId.SIDECHAIN_BTC_APPROVE_AGGREGATE]: typeof protocol.sidechain.btc.approveAggregate, [OperationId.BLOCK_REWARD]: typeof protocol.blockReward, + [OperationId.EVM_ADDRESS_REGISTER]: typeof protocol.evmAddress, }[T]; type OperationInput = SerializerInput>; diff --git a/types/serializers/protocol/evm_address.d.ts b/types/serializers/protocol/evm_address.d.ts new file mode 100644 index 00000000..c8f68d00 --- /dev/null +++ b/types/serializers/protocol/evm_address.d.ts @@ -0,0 +1,11 @@ +import { StructSerializer } from "../collections"; +import { asset, extensions } from "../chain"; +import { accountId } from "../chain/id/protocol"; +import ethAddress from "./ethAddress"; + +export declare const evmAddressRegisterOperationPropsSerializer: StructSerializer<{ + fee: typeof asset, + owner: typeof accountId, + evm_address: typeof ethAddress, + extensions: typeof extensions, +}>; diff --git a/types/serializers/protocol/fee_parameters.d.ts b/types/serializers/protocol/fee_parameters.d.ts index 83db79e0..18744d4e 100644 --- a/types/serializers/protocol/fee_parameters.d.ts +++ b/types/serializers/protocol/fee_parameters.d.ts @@ -62,13 +62,18 @@ export type FeeParametersSerializer = { [OperationId.SIDECHAIN_ETH_CREATE_ADDRESS]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ETH_APPROVE_ADDRESS]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ETH_DEPOSIT]: typeof defaultFeeParametersSerializer, + [OperationId.SIDECHAIN_ETH_SEND_DEPOSIT]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ETH_WITHDRAW]: typeof defaultFeeParametersSerializer, + [OperationId.SIDECHAIN_ETH_SEND_WITHDRAW]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ETH_APPROVE_WITHDRAW]: typeof defaultFeeParametersSerializer, + [OperationId.SIDECHAIN_ETH_UPDATE_CONTRACT_ADDRESS]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ISSUE]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_BURN]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ERC20_REGISTER_TOKEN]: StructSerializer<{ fee: typeof uint64, pool_fee: typeof uint64 }>, [OperationId.SIDECHAIN_ERC20_DEPOSIT_TOKEN]: typeof defaultFeeParametersSerializer, + [OperationId.SIDECHAIN_ERC20_SEND_DEPOSIT_TOKEN]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ERC20_WITHDRAW_TOKEN]: typeof defaultFeeParametersSerializer, + [OperationId.SIDECHAIN_ERC20_SEND_WITHDRAW_TOKEN]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ERC20_APPROVE_TOKEN_WITHDRAW]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ERC20_ISSUE]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_ERC20_BURN]: typeof defaultFeeParametersSerializer, @@ -80,6 +85,7 @@ export type FeeParametersSerializer = { [OperationId.SIDECHAIN_BTC_AGGREGATE]: typeof defaultFeeParametersSerializer, [OperationId.SIDECHAIN_BTC_APPROVE_AGGREGATE]: typeof defaultFeeParametersSerializer, [OperationId.BLOCK_REWARD]: typeof defaultFeeParametersSerializer, + [OperationId.EVM_ADDRESS_REGISTER]: typeof defaultFeeParametersSerializer, }[T]; declare const feeParametersSerializer: StaticVariantSerializer<{ diff --git a/types/serializers/protocol/index.d.ts b/types/serializers/protocol/index.d.ts index ccd42940..a7855c60 100644 --- a/types/serializers/protocol/index.d.ts +++ b/types/serializers/protocol/index.d.ts @@ -79,6 +79,8 @@ export { AccountListingSerializer, accountListing, ACCOUNT_LISTING } from './acc export { blockRewardOperationPropsSerializer as blockReward } from './block_reward'; +export { evmAddressRegisterOperationPropsSerializer as evmAddress } from './evm_address'; + export declare const account: { options: typeof accountOptionsSerializer, create: typeof accountCreateOperationPropsSerializer, diff --git a/types/serializers/protocol/sidechain/erc20.d.ts b/types/serializers/protocol/sidechain/erc20.d.ts index cf1585a9..bccd76a4 100644 --- a/types/serializers/protocol/sidechain/erc20.d.ts +++ b/types/serializers/protocol/sidechain/erc20.d.ts @@ -26,6 +26,13 @@ export declare const sidechainERC20DepositTokenOperationPropsSerializer: StructS extensions: typeof extensions, }>; +export declare const sidechainERC20SendDepositTokenOperationPropsSerializer: StructSerializer<{ + fee: typeof asset, + committee_member_id: typeof accountId, + deposit_id: typeof depositErc20TokenId, + extensions: typeof extensions, +}>; + export declare const sidechainERC20WithdrawTokenOperationPropsSerializer: StructSerializer<{ fee: typeof asset, account: typeof accountId, @@ -35,6 +42,13 @@ export declare const sidechainERC20WithdrawTokenOperationPropsSerializer: Struct extensions: typeof extensions, }>; +export declare const sidechainERC20SendWithdrawTokenOperationPropsSerializer: StructSerializer<{ + fee: typeof asset, + committee_member_id: typeof accountId, + deposit_id: typeof depositErc20TokenId, + extensions: typeof extensions, +}>; + export declare const sidechainERC20ApproveTokenWithdrawOperationPropsSerializer: StructSerializer<{ fee: typeof asset, committee_member_id: typeof accountId, diff --git a/types/serializers/protocol/sidechain/eth.d.ts b/types/serializers/protocol/sidechain/eth.d.ts index 4a174e1a..dc1e3ec5 100644 --- a/types/serializers/protocol/sidechain/eth.d.ts +++ b/types/serializers/protocol/sidechain/eth.d.ts @@ -1,7 +1,7 @@ import ethAddress from "../ethAddress"; import { uint64 } from "../../basic/integers"; import { asset, extensions } from "../../chain"; -import { accountId } from "../../chain/id/protocol"; +import { accountId, depositId } from "../../chain/id/protocol"; import { VectorSerializer, StructSerializer } from "../../collections"; export declare const sidechainEthCreateAddressOperationPropsSerializer: StructSerializer<{ @@ -28,6 +28,13 @@ export declare const sidechainEthDepositOperationPropsSerializer: StructSerializ extensions: typeof extensions, }>; +export declare const sidechainEthSendDepositOperationPropsSerializer: StructSerializer<{ + fee: typeof asset, + committee_member_id: typeof accountId, + deposit_id: typeof depositId, + extensions: typeof extensions, +}>; + export declare const sidechainEthWithdrawOperationPropsSerializer: StructSerializer<{ fee: typeof asset, account: typeof accountId, @@ -36,9 +43,25 @@ export declare const sidechainEthWithdrawOperationPropsSerializer: StructSeriali extensions: typeof extensions, }>; +export declare const sidechainEthSendWithdrawOperationPropsSerializer: StructSerializer<{ + fee: typeof asset, + committee_member_id: typeof accountId, + deposit_id: typeof depositId, + extensions: typeof extensions, +}>; + export declare const sidechainEthApproveWithdrawOperationPropsSerializer: StructSerializer<{ fee: typeof asset, committee_member_id: typeof accountId, withdraw_id: typeof uint64, extensions: typeof extensions, }>; + +export declare const sidechainEthUpdateContractAddressOperationPropsSerializer: StructSerializer<{ + fee: typeof asset, + new_addr: typeof ethAddress, + extensions: typeof extensions, +}>; + + + diff --git a/types/serializers/protocol/sidechain/index.d.ts b/types/serializers/protocol/sidechain/index.d.ts index 678c3103..8bd9ecb7 100644 --- a/types/serializers/protocol/sidechain/index.d.ts +++ b/types/serializers/protocol/sidechain/index.d.ts @@ -24,7 +24,9 @@ export declare const sidechainBurnOperationPropsSerializer: StructSerializer<{ export declare const erc20: { registerToken: typeof _erc20.sidechainERC20RegisterTokenOperationPropsSerializer, depositToken: typeof _erc20.sidechainERC20DepositTokenOperationPropsSerializer, + sendDepositToken: typeof _erc20.sidechainERC20SendDepositTokenOperationPropsSerializer, withdrawToken: typeof _erc20.sidechainERC20WithdrawTokenOperationPropsSerializer, + sendWithdrawToken: typeof _erc20.sidechainERC20SendWithdrawTokenOperationPropsSerializer, approveTokenWithdraw: typeof _erc20.sidechainERC20ApproveTokenWithdrawOperationPropsSerializer, issue: typeof _erc20.sidechainERC20IssueOperationPropsSerializer, burn: typeof _erc20.sidechainERC20BurnOperationPropsSerializer, @@ -34,8 +36,11 @@ export declare const eth: { createAddress: typeof _eth.sidechainEthCreateAddressOperationPropsSerializer, approveAddress: typeof _eth.sidechainEthApproveAddressOperationPropsSerializer, deposit: typeof _eth.sidechainEthDepositOperationPropsSerializer, + sendDeposit: typeof _eth.sidechainEthSendDepositOperationPropsSerializer, withdraw: typeof _eth.sidechainEthWithdrawOperationPropsSerializer, + sendWithdraw: typeof _eth.sidechainEthSendWithdrawOperationPropsSerializer, approveWithdraw: typeof _eth.sidechainEthApproveWithdrawOperationPropsSerializer, + updateContractAddress: typeof _eth.sidechainEthUpdateContractAddressOperationPropsSerializer, }; export declare const btc: { From 32620d26b90bdc92304a918e7e771179549ea830 Mon Sep 17 00:00:00 2001 From: Alina Lozyuk <32218750+AlinaLoz@users.noreply.github.com> Date: Thu, 2 Apr 2020 11:16:57 +0300 Subject: [PATCH 40/62] [ECHOJS-247] up devnet from 0.17 to 0.18 (#159) --- .eslintignore | 1 + docs/API.md | 4 +++- package.json | 2 +- src/echo/api.js | 6 ++++-- src/serializers/protocol/asset.js | 2 +- types/interfaces/AccountHistory.d.ts | 3 ++- types/interfaces/ContractHistory.d.ts | 1 + types/serializers/protocol/asset.d.ts | 2 +- 8 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.eslintignore b/.eslintignore index ca146357..0ff0108e 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,3 +2,4 @@ node_modules/* dist/* test/* scripts/* +client.js diff --git a/docs/API.md b/docs/API.md index 98518a60..cff7bc58 100644 --- a/docs/API.md +++ b/docs/API.md @@ -1223,7 +1223,8 @@ try { block_num:Number, trx_in_block:Number, op_in_block:Number, - virtual_op:Number + virtual_op:Number, + proposal_hist_id: Number|undefined, } ``` ## FullAccount : Object @@ -1406,6 +1407,7 @@ or result: [0, {}], trx_in_block:Number, virtual_op:Number, + proposal_hist_id: Number } ``` diff --git a/package.json b/package.json index d308a10a..7dbc4054 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "echojs-lib", - "version": "1.9.11-echo.17", + "version": "1.12.0-rc.0", "description": "Pure JavaScript ECHO library for node.js", "main": "./dist/index.js", "types": "./types/index.d.ts", diff --git a/src/echo/api.js b/src/echo/api.js index ef818a51..80f200d8 100644 --- a/src/echo/api.js +++ b/src/echo/api.js @@ -334,7 +334,8 @@ import { PublicKey } from '../crypto'; * block_num:Number, * trx_in_block:Number, * op_in_block:Number, -* virtual_op:Number +* virtual_op:Number, +* proposal_hist_id: Number|undefined * } * } AccountHistory */ @@ -479,7 +480,8 @@ import { PublicKey } from '../crypto'; * op_in_trx:Number, * result: [0, {}], * trx_in_block:Number, -* virtual_op:Number +* virtual_op:Number, +* proposal_hist_id: Number * } * } ContractHistory */ diff --git a/src/serializers/protocol/asset.js b/src/serializers/protocol/asset.js index 296b6982..a50d0e4b 100644 --- a/src/serializers/protocol/asset.js +++ b/src/serializers/protocol/asset.js @@ -93,7 +93,7 @@ export const assetPublishFeedOperationPropsSerializer = struct({ fee: asset, publisher: accountId, asset_id: assetId, - feed: priceFeedSerializer, + core_exchange_rate: priceSerializer, extensions, }); diff --git a/types/interfaces/AccountHistory.d.ts b/types/interfaces/AccountHistory.d.ts index 241b9741..260c59de 100644 --- a/types/interfaces/AccountHistory.d.ts +++ b/types/interfaces/AccountHistory.d.ts @@ -5,5 +5,6 @@ export default interface AccountHistory { block_num: number, trx_in_block: number, op_in_block: number, - virtual_op: number + virtual_op: number, + proposal_hist_id: number|undefined, } diff --git a/types/interfaces/ContractHistory.d.ts b/types/interfaces/ContractHistory.d.ts index d8fa89ab..6faacf4a 100644 --- a/types/interfaces/ContractHistory.d.ts +++ b/types/interfaces/ContractHistory.d.ts @@ -6,4 +6,5 @@ export default interface ContractHistory { result: [0, {}], trx_in_block: number, virtual_op: number, + proposal_hist_id: number|undefined; } diff --git a/types/serializers/protocol/asset.d.ts b/types/serializers/protocol/asset.d.ts index 3a4011f6..77592671 100644 --- a/types/serializers/protocol/asset.d.ts +++ b/types/serializers/protocol/asset.d.ts @@ -94,7 +94,7 @@ export declare const assetPublishFeedOperationPropsSerializer: StructSerializer< fee: typeof asset, publisher: typeof accountId, asset_id: typeof assetId, - feed: typeof priceFeedSerializer, + core_exchange_rate: typeof priceSerializer, extensions: typeof extensions, }>; From 121c90a77d23feb7f9e4406ff1f58e22ce9f53fd Mon Sep 17 00:00:00 2001 From: "a.lozyuk" Date: Thu, 2 Apr 2020 13:57:18 +0300 Subject: [PATCH 41/62] fix --- src/echo/api.js | 15 ++++++------ test/api/database/get-contract-logs.test.js | 26 --------------------- 2 files changed, 8 insertions(+), 33 deletions(-) diff --git a/src/echo/api.js b/src/echo/api.js index def7eaad..0d2cdf79 100644 --- a/src/echo/api.js +++ b/src/echo/api.js @@ -1,5 +1,6 @@ /* eslint-disable no-continue,no-await-in-loop,camelcase,no-restricted-syntax */ import * as assert from 'assert'; +import { ok } from 'assert'; import { Map, List, fromJS } from 'immutable'; import BigNumber from 'bignumber.js'; import { @@ -1942,13 +1943,13 @@ class API { */ async getContractLogs(opts = { }) { if (opts.contracts !== undefined) { - assert.ok(Array.isArray(opts.contracts), '"contracts" option is not an array'); - for (const contractId of opts.contracts) assert.ok(isContractId(contractId)); + ok(Array.isArray(opts.contracts), '"contracts" option is not an array'); + for (const contractId of opts.contracts) ok(isContractId(contractId)); } /** @type {typeof opts["topics"]} */ let topics; if (opts.topics !== undefined) { - assert.ok(Array.isArray(opts.topics), '"topics" option is not an array'); + ok(Array.isArray(opts.topics), '"topics" option is not an array'); topics = new Array(opts.topics.length).fill(null); for (let topicIndex = 0; topicIndex < opts.topics.length; topicIndex += 1) { let topicVariants = opts.topics[topicIndex]; @@ -1958,16 +1959,16 @@ class API { for (let variantIndex = 0; variantIndex < topicVariants.length; variantIndex += 1) { let variant = topicVariants[variantIndex]; if (Buffer.isBuffer(variant)) variant = variant.toString('hex'); - assert.ok(typeof variant === 'string', 'invalid "topic" option type'); + ok(typeof variant === 'string', 'invalid "topic" option type'); if (variant.startsWith('0x')) variant = variant.slice(2); - assert.ok(/^([\da-fA-F]{2})+$/.test(variant), '"topic" is not a hex'); - assert.ok(variant.length === 64, 'invalid "topic" length'); + ok(/^([\da-fA-F]{2})+$/.test(variant), '"topic" is not a hex'); + ok(variant.length === 64, 'invalid "topic" length'); topics[topicIndex][variantIndex] = variant; } } } for (const field of ['fromBlock', 'toBlock']) { - assert.ok(opts[field] === undefined || isUInt32(opts[field]), `"${field}" option is not uint32`); + ok(opts[field] === undefined || isUInt32(opts[field]), `"${field}" option is not uint32`); } return new Promise((resolve) => { const cb = (logs) => { diff --git a/test/api/database/get-contract-logs.test.js b/test/api/database/get-contract-logs.test.js index 6cb4f7ad..de981e26 100644 --- a/test/api/database/get-contract-logs.test.js +++ b/test/api/database/get-contract-logs.test.js @@ -21,14 +21,6 @@ describe("getContractLogs", () => { }, 'contracts: vector is not an array'); }); - describe('when `contracts` has duplicates', () => { - shouldReject( - async () => await echo.api.getContractLogs({ contracts: ['1.11.1', '1.11.1'] }), - 'contracts element with index 1 is equals to the other one with index 0', - 'with indexes of duplicated elements', - ); - }); - describe('when `contracts` first element is not a contract id', () => { shouldReject(async () => { await echo.api.getContractLogs({ contracts: ['1.10.1'] }); @@ -41,24 +33,6 @@ describe("getContractLogs", () => { }, '`topics` is not an array'); }); - describe('when `fromBlock` is negative', () => { - shouldReject(async () => { - await echo.api.getContractLogs({ fromBlock: -1 }); - }, '`fromBlock` must be greater than or equal to zero'); - }); - - describe('when `toBlock` is negative', () => { - shouldReject(async () => { - await echo.api.getContractLogs({ toBlock: -1 }); - }, '`toBlock` must be greater than zero'); - }); - - describe('when `toBlock` is equals to zero', () => { - shouldReject(async () => { - await echo.api.getContractLogs({ toBlock: 0 }); - }, '`toBlock` must be greater than zero'); - }); - describe('when different events are emitted in different blocks', () => { /** @type {string} */ let contractId; From f1fcf2fe7a27a6935f7001e4504e55dfa546e611 Mon Sep 17 00:00:00 2001 From: "a.lozyuk" Date: Thu, 2 Apr 2020 14:16:41 +0300 Subject: [PATCH 42/62] fix --- src/echo/api.js | 6 +++--- test/api/database/get-contract-logs.test.js | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/echo/api.js b/src/echo/api.js index 0d2cdf79..5d4f5483 100644 --- a/src/echo/api.js +++ b/src/echo/api.js @@ -1943,13 +1943,13 @@ class API { */ async getContractLogs(opts = { }) { if (opts.contracts !== undefined) { - ok(Array.isArray(opts.contracts), '"contracts" option is not an array'); - for (const contractId of opts.contracts) ok(isContractId(contractId)); + ok(Array.isArray(opts.contracts), 'contracts: vector is not an array'); + for (const contractId of opts.contracts) ok(isContractId(contractId), 'invalid object type id'); } /** @type {typeof opts["topics"]} */ let topics; if (opts.topics !== undefined) { - ok(Array.isArray(opts.topics), '"topics" option is not an array'); + ok(Array.isArray(opts.topics), '`topics` is not an array'); topics = new Array(opts.topics.length).fill(null); for (let topicIndex = 0; topicIndex < opts.topics.length; topicIndex += 1) { let topicVariants = opts.topics[topicIndex]; diff --git a/test/api/database/get-contract-logs.test.js b/test/api/database/get-contract-logs.test.js index de981e26..1a16d49b 100644 --- a/test/api/database/get-contract-logs.test.js +++ b/test/api/database/get-contract-logs.test.js @@ -24,7 +24,7 @@ describe("getContractLogs", () => { describe('when `contracts` first element is not a contract id', () => { shouldReject(async () => { await echo.api.getContractLogs({ contracts: ['1.10.1'] }); - }, 'contracts: vector element with index 0: invalid object type id'); + }, 'invalid object type id'); }); describe('when `topics` is not an `set_t`', () => { @@ -65,11 +65,11 @@ describe("getContractLogs", () => { }); it('with all logs of contract', function () { if (events === undefined) this.skip(); - assert.ok(events.every(([_, { address }]) => address === contractAddress)); + assert.ok(events.every(({ address }) => address === contractAddress)); }); it('with different blocks', function () { if (events === undefined) this.skip(); - assert.ok(events[0][1].block_num !== events[1][1].block_num); + assert.ok(events[0].block_num !== events[1].block_num); }); }); describe('when there are another contract with the same logs', () => { @@ -102,11 +102,11 @@ describe("getContractLogs", () => { }); it('with all logs of contract', function () { if (res === undefined || !Array.isArray(res) || res.length < 2) this.skip(); - assert.ok(res.every(([_, { address }]) => address === contractAddress)); + assert.ok(res.every(({ address }) => address === contractAddress)); }); it('with different blocks', function () { if (res === undefined || !Array.isArray(res) || res.length < 2) this.skip(); - assert.ok(res[0][1].block_num !== res[1][1].block_num); + assert.ok(res[0].block_num !== res[1].block_num); }); }); describe('when both contracts are provided in `contracts` filter', () => { @@ -126,7 +126,7 @@ describe("getContractLogs", () => { }); it('with all logs of both contracts', function () { if (res === undefined || !Array.isArray(res) || res.length < 4) this.skip(); - assert.deepStrictEqual(res.map(([_, { address }]) => { + assert.deepStrictEqual(res.map(({ address }) => { return address; }), [contractAddress, contractAddress, anotherContractAddress, anotherContractAddress]); }); From 978d28a33ce8e8bd389efe34cb0934bfcebfec70 Mon Sep 17 00:00:00 2001 From: "a.lozyuk" Date: Thu, 2 Apr 2020 14:42:14 +0300 Subject: [PATCH 43/62] fix --- test/wallet-api.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/wallet-api.test.js b/test/wallet-api.test.js index 83e0eebd..10fc1fa5 100644 --- a/test/wallet-api.test.js +++ b/test/wallet-api.test.js @@ -55,7 +55,7 @@ describe('WALLET API', () => { before(async () => { await echo.connect(url, { - connectionTimeout: 10000, + connectionTimeout: 100000, apis: constants.WS_CONSTANTS.CHAIN_APIS, wallet: walletURL, } From 6950f54e0e139397bc9502635d5f50e7d1309e86 Mon Sep 17 00:00:00 2001 From: "a.lozyuk" Date: Thu, 2 Apr 2020 14:54:49 +0300 Subject: [PATCH 44/62] fix --- test/wallet-api.test.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/wallet-api.test.js b/test/wallet-api.test.js index 10fc1fa5..cb541e6d 100644 --- a/test/wallet-api.test.js +++ b/test/wallet-api.test.js @@ -55,7 +55,10 @@ describe('WALLET API', () => { before(async () => { await echo.connect(url, { - connectionTimeout: 100000, + connectionTimeout: 10000, + maxRetries: 5, + pingTimeout: 3000, + pingDelay: 10000, apis: constants.WS_CONSTANTS.CHAIN_APIS, wallet: walletURL, } From 9c09916e915357e64cb57836a5ddd606ec6c8507 Mon Sep 17 00:00:00 2001 From: "a.lozyuk" Date: Thu, 2 Apr 2020 16:38:40 +0300 Subject: [PATCH 45/62] fix --- .test/docker-compose.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.test/docker-compose.yml b/.test/docker-compose.yml index 5e6aa4a7..f28df0ad 100644 --- a/.test/docker-compose.yml +++ b/.test/docker-compose.yml @@ -2,7 +2,7 @@ version: "2" services: echo: - image: echoprotocol/echo:0.17.1-rc.5 + image: echoprotocol/echo:0.18.0-rc.7 command: --start-echorand --account-info="[\"1.2.6\", \"5KkYp8qdQBaRmLqLz8WVrGjzkt7E13qVcr7cpdLowgJ1mjRyDx2\"]" @@ -24,11 +24,11 @@ services: container_name: echo echo-wallet: - image: echoprotocol/echo-wallet:0.17.1-rc.5 + image: echoprotocol/echo-wallet:0.18.0-rc.7 container_name: echo-wallet command: -s ws://echo:6311 - --chain-id="8cc5ced88147e2b6bef07d0c016274fb3dca8db8d1f20f1d15b5e34fa80cb89f" + --chain-id="ae55e9cc332c46bdc8d4eac06e6e909ca51ad074150ce42775ee90345fdeff0e" --wallet-file="/echo/walletdata/wallet.json" --history-file="/echo/walletdata/history" -r 0.0.0.0:6312 From 8fad8f49a58768ee633d5d0dec7fcfd4db01defc Mon Sep 17 00:00:00 2001 From: "a.lozyuk" Date: Thu, 2 Apr 2020 16:47:23 +0300 Subject: [PATCH 46/62] fix --- src/echo/ws-api/wallet-api.js | 8 ++--- test/wallet-api.test.js | 65 +++++++++-------------------------- 2 files changed, 21 insertions(+), 52 deletions(-) diff --git a/src/echo/ws-api/wallet-api.js b/src/echo/ws-api/wallet-api.js index be4afa46..c95d62f3 100644 --- a/src/echo/ws-api/wallet-api.js +++ b/src/echo/ws-api/wallet-api.js @@ -30,7 +30,7 @@ const { ripemd160, } = serializers.chain; const { options, bitassetOptions } = serializers.protocol.asset; -const { priceFeed } = serializers.protocol; +const { price } = serializers.protocol; const { config } = serializers.plugins.echorand; const { anyObjectId } = serializers.chain.ids; @@ -1223,11 +1223,11 @@ class WalletAPI { * * @param {string} accountIdOrName the account publishing the price feed * @param {string} assetIdOrName the name or id of the asset whose feed we're publishing - * @param {any} priceOfFeed object containing the three prices making up the feed + * @param {any} coreEchangeRate object containing the three prices making up the feed * @param {boolean} shouldDoBroadcastToNetwork true to broadcast the transaction on the network * @returns {Promise} the signed transaction updating the price feed for the given asset */ - publishAssetFeed(accountIdOrName, assetIdOrName, priceOfFeed, shouldDoBroadcastToNetwork) { + publishAssetFeed(accountIdOrName, assetIdOrName, coreEchangeRate, shouldDoBroadcastToNetwork) { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } @@ -1237,7 +1237,7 @@ class WalletAPI { return this.wsRpc.call([0, 'publish_asset_feed', [ string.toRaw(accountIdOrName), string.toRaw(assetIdOrName), - priceFeed.toRaw(priceOfFeed), + price.toRaw(coreEchangeRate), bool.toRaw(shouldDoBroadcastToNetwork), ]]); } diff --git a/test/wallet-api.test.js b/test/wallet-api.test.js index cb541e6d..4b0f7958 100644 --- a/test/wallet-api.test.js +++ b/test/wallet-api.test.js @@ -55,10 +55,7 @@ describe('WALLET API', () => { before(async () => { await echo.connect(url, { - connectionTimeout: 10000, - maxRetries: 5, - pingTimeout: 3000, - pingDelay: 10000, + connectionTimeout: 1000, apis: constants.WS_CONSTANTS.CHAIN_APIS, wallet: walletURL, } @@ -1195,34 +1192,20 @@ describe('WALLET API', () => { describe('#publishAssetFeed()', () => { it('Should publishes a price feed for the named asset', async () => { - const priceFeed = { - "settlement_price": { - "base": { - "amount": 1, - "asset_id": "1.3.0", - }, - "quote": { - "amount": 1, - "asset_id": "1.3.1", - }, + const core_exchange_rate = { + "base": { + "amount": 1, + "asset_id": '1.3.0', }, - "core_exchange_rate": { - "base": { - "amount": 1, - "asset_id": "1.3.0", - }, - "quote": { - "amount": 1, - "asset_id": "1.3.1", - }, + "quote": { + "amount": 1, + "asset_id": '1.3.1', }, - "maintenance_collateral_ratio": 32e3, - "maximum_short_squeeze_ratio": 32e3, }; const result = await echo.walletApi.publishAssetFeed( accountId, constants.ECHO_ASSET_ID, - priceFeed, + core_exchange_rate, shouldDoBroadcastToNetwork, ); expect(result) @@ -1340,34 +1323,20 @@ describe('WALLET API', () => { describe('#publishAssetFeed()', () => { it('Should publishes a price feed for the named asset', async () => { - const priceFeed = { - "settlement_price": { - "base": { - "amount": 1, - "asset_id": "1.3.0", - }, - "quote": { - "amount": 1, - "asset_id": "1.3.1", - }, + const core_exchange_rate = { + "base": { + "amount": 1, + "asset_id": '1.3.0', }, - "core_exchange_rate": { - "base": { - "amount": 1, - "asset_id": "1.3.0", - }, - "quote": { - "amount": 1, - "asset_id": "1.3.1", - }, + "quote": { + "amount": 1, + "asset_id": '1.3.1', }, - "maintenance_collateral_ratio": 32e3, - "maximum_short_squeeze_ratio": 32e3, }; const result = await echo.walletApi.publishAssetFeed( accountId, constants.ECHO_ASSET_ID, - priceFeed, + core_exchange_rate, shouldDoBroadcastToNetwork, ); expect(result) From d5df6087d5025619b4a908c129a093efb76a6c7e Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Wed, 8 Apr 2020 18:58:07 +0300 Subject: [PATCH 47/62] [ECHOJS-250] WIP --- .test/docker-compose.yml | 2 +- package.json | 1 + src/echo/providers.js | 42 ++ src/echo/providers/HTTPProvider.js | 19 + src/echo/providers/WSProvider.js | 490 ++++++++++++++++++++++ src/echo/providers/connection-types.js | 2 + src/echo/ws-api/registration-api.js | 10 +- src/echo/ws/echo-api.js | 40 +- src/echo/ws/reconnection-websocket.js | 21 +- src/serializers/protocol/asset.js | 2 +- types/echo/echo-api.d.ts | 9 + types/echo/engine.d.ts | 11 + types/echo/providers/base-provider.d.ts | 13 + types/echo/providers/connection-type.d.ts | 6 + types/echo/providers/http-provider.d.ts | 8 + types/echo/providers/index.d.ts | 4 + types/echo/providers/ws-provider.d.ts | 22 + 17 files changed, 673 insertions(+), 29 deletions(-) create mode 100644 src/echo/providers.js create mode 100644 src/echo/providers/HTTPProvider.js create mode 100644 src/echo/providers/WSProvider.js create mode 100644 src/echo/providers/connection-types.js create mode 100644 types/echo/echo-api.d.ts create mode 100644 types/echo/engine.d.ts create mode 100644 types/echo/providers/base-provider.d.ts create mode 100644 types/echo/providers/connection-type.d.ts create mode 100644 types/echo/providers/http-provider.d.ts create mode 100644 types/echo/providers/index.d.ts create mode 100644 types/echo/providers/ws-provider.d.ts diff --git a/.test/docker-compose.yml b/.test/docker-compose.yml index 5e6aa4a7..cd40c0cc 100644 --- a/.test/docker-compose.yml +++ b/.test/docker-compose.yml @@ -2,7 +2,7 @@ version: "2" services: echo: - image: echoprotocol/echo:0.17.1-rc.5 + image: echoprotocol/echo:0.18.0 command: --start-echorand --account-info="[\"1.2.6\", \"5KkYp8qdQBaRmLqLz8WVrGjzkt7E13qVcr7cpdLowgJ1mjRyDx2\"]" diff --git a/package.json b/package.json index 5e0e0561..43372f84 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "@types/crypto-js": "^3.1.43", "@types/node": "^12.0.10", "assert": "^1.4.1", + "axios": "^0.19.2", "bigi": "^1.4.2", "bignumber.js": "^8.0.1", "bs58": "^4.0.1", diff --git a/src/echo/providers.js b/src/echo/providers.js new file mode 100644 index 00000000..2673d845 --- /dev/null +++ b/src/echo/providers.js @@ -0,0 +1,42 @@ +import axios from 'axios'; +import ReconnectionWebSocket from './ws/reconnection-websocket'; + +export const ConnectionType = { + WS: 'ws', + HTTP: 'http', +}; + +export class WSProvider { + + get connectionType() { return ConnectionType.WS; } + + constructor() { + this._ws = new ReconnectionWebSocket(); + } + + async connect(url, options) { + this.url = url; + await this._ws.connect(url, options); + } + + call(apiId, method, params) { + return this._ws.call([apiId, method, params]); + } + +} + +export class HttpProvider { + + get connectionType() { return ConnectionType.HTTP; } + + constructor(url) { + this.url = url; + } + + call(method, params) { + return axios.post(this.url, { + jsonrpc: '2.0', id: 0, method, params, + }); + } + +} diff --git a/src/echo/providers/HTTPProvider.js b/src/echo/providers/HTTPProvider.js new file mode 100644 index 00000000..9b4ea5af --- /dev/null +++ b/src/echo/providers/HTTPProvider.js @@ -0,0 +1,19 @@ +import Axios from 'axios'; + +import * as ConnectionType from './connection-types'; + +export default class HttpProvider { + + get connectionType() { return ConnectionType.HTTP; } + + constructor(url) { + this.url = url; + } + + call(method, params) { + return Axios.post(this.url, { + jsonrpc: '2.0', id: 0, method, params, + }); + } + +} diff --git a/src/echo/providers/WSProvider.js b/src/echo/providers/WSProvider.js new file mode 100644 index 00000000..4ecb7933 --- /dev/null +++ b/src/echo/providers/WSProvider.js @@ -0,0 +1,490 @@ +import WebSocket from 'isomorphic-ws'; + +import { + CONNECTION_TIMEOUT, + MAX_RETRIES, + PING_TIMEOUT, + PING_DELAY, + DEBUG, + CONNECTION_CLOSED_ERROR_MESSAGE, +} from '../../constants/ws-constants'; + +import { isVoid } from '../../utils/validators'; +import * as ConnectionType from './connection-types'; + +export default class WSProvider { + + get connectionType() { return ConnectionType.WS; } + + constructor() { + this.onOpen = null; + this.onClose = null; + this.onError = null; + + this._currentRetry = 0; + this._pingDelayId = null; + this._options = {}; + + this._cbId = 0; + this._responseCbId = 0; + this._cbs = {}; + this._subs = []; + this._unsub = {}; + } + + /** + * init params and connect to chain + * + * @param {string} url remote node address, + * should be (http|https|ws|wws)://(domain|ipv4|ipv6):port(?)/resource(?)?param=param(?). + * + * @param {Object} options connection params. + * + * @param {number} options.connectionTimeout + * delay in ms between reconnection requests, default call delay before reject it. + * + * @param {number} options.maxRetries - max count retries before close socket. + * @param {number} options.pingTimeout - delay time in ms between ping request and socket disconnect. + * @param {number} options.pingDelay - delay between last recived message and start checking connection. + * @param {boolean} options.debug - debug mode status. + * @returns {Promise} + */ + async connect(url, options = {}) { + if (this.ws && this.ws.readyState === WebSocket.OPEN) await this.close(); + this._options = { + connectionTimeout: isVoid(options.connectionTimeout) ? CONNECTION_TIMEOUT : options.connectionTimeout, + maxRetries: isVoid(options.maxRetries) ? MAX_RETRIES : options.maxRetries, + pingTimeout: isVoid(options.pingTimeout) ? PING_TIMEOUT : options.pingTimeout, + pingDelay: isVoid(options.pingDelay) ? PING_DELAY : options.pingDelay, + debug: isVoid(options.debug) ? DEBUG : options.debug, + }; + + this.url = url; + this._isFirstConnection = true; + this._currentRetry = 0; + this._forceClosePromise = null; + this._reconnectionTimeoutId = null; + + this._cbId = 0; + this._responseCbId = 0; + this._cbs = {}; + this._cbLogs = []; + this._subs = []; + this._unsub = {}; + + return this._connect(); + } + + /** + * inner connection method + * @returns {Promise} + */ + _connect() { + + this._debugLog('[ReconnectionWebSocket] >---- retry _connect'); + + this._currentRetry += 1; + return new Promise((resolve, reject) => { + let ws = null; + try { + ws = new WebSocket(this.url); + } catch (error) { + ws = null; + if (this._isFirstConnection) { + this._isFirstConnection = false; + return reject(error); + } + } + + ws.onopen = () => { + + this._currentRetry = 0; + + if (this._isFirstConnection) { + this._isFirstConnection = false; + resolve(); + } + + if (this.onOpen) this.onOpen(); + + this._setPingDelay(); + + this._debugLog('[ReconnectionWebSocket] >---- event -----> ONOPEN'); + return true; + }; + + ws.onmessage = (message) => { + + if (ws !== this.ws) { + return false; + } + + this._responseHandler(JSON.parse(message.data)); + + this._debugLog('[ReconnectionWebSocket] >---- event -----> ONMESSAGE'); + + this._setPingDelay(); + + return true; + }; + + ws.onclose = () => { + + if (ws !== this.ws) { + return false; + } + + if (this._isFirstConnection) { + this._isFirstConnection = false; + reject(new Error('Could\'t reach server or bad internet access')); + return false; + } + + this._forceClose(); + + return true; + + }; + + ws.onerror = (error) => { + + if (ws !== this.ws) { + return false; + } + + if (this.onError) this.onError(error); + + this._debugLog('[ReconnectionWebSocket] >---- event -----> ONERROR'); + + return true; + }; + + this.ws = ws; + + return ws; + }); + } + + /** + * connect to socket, can't be used after close + * @returns {Promise} + */ + async reconnect() { + if (!this.ws) { + throw new Error('Socket not exist.'); + } + + this._debugLog('[ReconnectionWebSocket] >---- event -----> FORCE RECONNECTING'); + await this.connect(this.url, this._options); + } + + /** + * set debug option + * @param {Boolean} status + */ + setDebugOption(status) { + this._options.debug = Boolean(status); + } + + /** + * call a method with params via RPC + * @param {Array} params + * @param {Number} timeout - timeout before reject + * @returns {Promise} + */ + call(params, timeout = this._options.connectionTimeout) { + if (!this.ws) { + return Promise.reject(new Error('Websocket is closed')); + } + + if (this.ws.readyState !== WebSocket.OPEN) { + return Promise.reject(new Error(`Websocket state error: ${this.ws.readyState}`)); + } + + const method = params[1]; + this._debugLog(`[ReconnectionWebSocket] >---- call -----> "id":${this._cbId + 1}`, JSON.stringify(params)); + + this._cbId += 1; + + if ( + method === 'set_subscribe_callback' || + method === 'broadcast_transaction_with_callback' || + method === 'set_pending_transaction_callback' || + method === 'set_block_applied_callback' || + method === 'set_echorand_message_callback' || + method === 'subscribe_contract_logs' || + method === 'submit_registration_solution' || + method === 'get_contract_logs' + ) { + // Store callback in subs map + this._subs[this._cbId] = { + callback: params[2][0], + }; + + // Replace callback with the callback id + params[2][0] = this._cbId; + + if (method === 'get_contract_logs') { + this._cbLogs.push(this._cbId); + } + } + + if (method === 'unsubscribe_from_accounts') { + if (typeof params[2][0] !== 'function') { + throw new Error('First parameter of unsub must be the original callback'); + } + + const unSubCb = params[2].splice(0, 1)[0]; + + this._subs.forEach((id) => { + if (id.callback === unSubCb) { + this._unsub[this._cbId] = id; + } + }); + } + + const request = { + method: 'call', + params, + }; + request.id = this._cbId; + + return new Promise((resolve, reject) => { + + const timeoutId = setTimeout(() => { + reject(new Error(`RPC call time is over Id: ${request.id}`)); + + this._removePendingRequest(request.id); + }, timeout); + + this._cbs[this._cbId] = { + time: new Date(), + resolve, + reject, + timeoutId, + }; + + this.ws.send(JSON.stringify(request)); + }); + + } + + /** + * message handler + * @param response + */ + _responseHandler(response) { + this._debugLog('[ReconnectionWebSocket] <---- reply ----<', JSON.stringify(response)); + + let sub = false; + let callback = null; + + if (response.method === 'notice') { + sub = true; + response = { + ...response, + id: response.params[0], + }; + } + + if (!sub) { + callback = this._cbs[response.id]; + this._responseCbId = response.id; + } else if (this._subs[response.id].callback instanceof Array) { + [callback] = this._subs[response.id].callback; + } else if (typeof this._subs[response.id].callback === 'function') { + // eslint-disable-next-line prefer-destructuring + callback = this._subs[response.id].callback; + } + + if (callback && !sub) { + const { timeoutId } = callback; + if (timeoutId) clearTimeout(timeoutId); + if (response.error) { + callback.reject(response.error); + } else { + callback.resolve(response.result); + } + + this._removeSuccessfulRequest(response.id); + + } else if (callback && sub) { + callback(response.params[1]); + if (this._cbLogs.includes(response.id)) { + delete this._subs[response.id]; + const indexCb = this._cbLogs.indexOf(response.id); + this._cbLogs.splice(indexCb); + } + + } else { + this._debugLog('[ReconnectionWebSocket] >---- warning ----> Unknown websocket response', response); + } + } + + /** + * get access to chain + * @param {String} user + * @param {String} password + * @param {Number} timeout - timeout before reject + * @returns {Promise} + */ + login(user, password, timeout = this._options.pingTimeout) { + return this.call([1, 'login', [user, password]], timeout); + } + + /** + * update ping delay timeout + * @private + */ + _setPingDelay() { + this._clearPingDelay(); + this._pingDelayId = setTimeout(() => this._ping(), this._options.pingDelay); + } + + /** + * clear reconnection timeout + * @private + */ + _clearReconnectionTimeout() { + if (this._reconnectionTimeoutId) { + clearTimeout(this._reconnectionTimeoutId); + this._reconnectionTimeoutId = null; + } + } + + /** + * clear ping delay timeout + * @private + */ + _clearPingDelay() { + if (this._pingDelayId) { + clearTimeout(this._pingDelayId); + this._pingDelayId = null; + } + } + + /** + * clear waiting calls + * @private + */ + _clearWaitingCallPromises() { + const err = new Error(CONNECTION_CLOSED_ERROR_MESSAGE); + + for (let cbId = this._responseCbId + 1; cbId <= this._cbId; cbId += 1) { + if (this._cbs[cbId]) this._cbs[cbId].reject(err); + } + } + + /** + * reset calls id + * @private + */ + _resetId() { + this._cbId = 0; + } + + /** + * make call for check connection + * @private + */ + async _ping() { + try { + await this.login(); + } catch (_) { + if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return; + this._forceClose(); + } + } + + /** + * show debug logs + * @private + */ + _debugLog(...messages) { + if (!this._options.debug) return; + console.log(...messages); + } + + /** + * remove pending request from map + * @private + */ + _removePendingRequest(id) { + delete this._cbs[id]; + delete this._subs[id]; + delete this._unsub[id]; + } + + /** + * remove successful request from map + * @private + */ + _removeSuccessfulRequest(id) { + delete this._cbs[id]; + + if (this._unsub[id]) { + delete this._subs[this._unsub[id]]; + delete this._unsub[id]; + } + } + + _forceClose() { + + this._debugLog('[ReconnectionWebSocket] >---- _forceClose '); + + const { ws } = this; + this.ws = null; + + if (ws) { + ws.onopen = () => { }; + ws.onclose = () => { }; + ws.onerror = () => { }; + ws.onmessage = () => { }; + ws.close(); + } + + this._clearWaitingCallPromises(); + this._clearPingDelay(); + this._clearReconnectionTimeout(); + this._resetId(); + + if (this.onClose && this._currentRetry === 0) this.onClose(); + + this._debugLog('[ReconnectionWebSocket] >---- event -----> ONCLOSE'); + + if (this._forceClosePromise) { + this._forceClosePromise(); + this._forceClosePromise = null; + return true; + } + + if (this._currentRetry >= this._options.maxRetries) { + return true; + } + + this._reconnectionTimeoutId = setTimeout(async () => { + try { + await this._connect(); + } catch (_) { + // + } + }, this._options.connectionTimeout); + + return true; + } + /** + * + * @returns {Promise} + */ + close() { + if (!this.ws || this.ws.readyState === WebSocket.CLOSING || this.ws.readyState === WebSocket.CLOSED) { + return Promise.reject(new Error('Socket already close')); + } + + return new Promise((resolve) => { + this._forceClosePromise = resolve; + this._forceClose(); + }); + } + +} diff --git a/src/echo/providers/connection-types.js b/src/echo/providers/connection-types.js new file mode 100644 index 00000000..549cb517 --- /dev/null +++ b/src/echo/providers/connection-types.js @@ -0,0 +1,2 @@ +export const WS = 'ws'; +export const HTTP = 'http'; diff --git a/src/echo/ws-api/registration-api.js b/src/echo/ws-api/registration-api.js index 5cb7dc35..dc341974 100644 --- a/src/echo/ws-api/registration-api.js +++ b/src/echo/ws-api/registration-api.js @@ -33,7 +33,15 @@ class RegistrationAPI { * @return {Promise} */ submitRegistrationSolution(callback, name, activeKey, echorandKey, evmAddress, nonce, randNum) { - return this.db.exec('submit_registration_solution', [callback, name, activeKey, echorandKey, evmAddress, nonce, randNum]); + return this.db.exec('submit_registration_solution', [ + callback, + name, + activeKey, + echorandKey, + evmAddress, + nonce, + randNum, + ]); } /** diff --git a/src/echo/ws/echo-api.js b/src/echo/ws/echo-api.js index fb40b890..dbd334c5 100644 --- a/src/echo/ws/echo-api.js +++ b/src/echo/ws/echo-api.js @@ -1,13 +1,20 @@ +import { ConnectionType } from '../providers'; + +/** @typedef {import("../providers").WSProvider} WSProvider */ +/** @typedef {import("../providers").HttpProvider} HttpProvider */ + class EchoApi { /** * - * @param {ReconnectionWebSocket} wsRpc + * @param {HttpProvider | WSProvider} provider * @param {String} apiName */ - constructor(wsRpc, apiName) { - this.ws_rpc = wsRpc; - this.api_name = apiName; + constructor(provider, apiName) { + this.provider = provider; + this.apiName = apiName; + /** @type {number | undefined} */ + this.apiId = undefined; } /** @@ -15,12 +22,10 @@ class EchoApi { * @returns {Promise} */ async init() { - try { - this.api_id = await this.ws_rpc.call([1, this.api_name, []]); - return this; - } catch (e) { - throw e; - } + if (this.provider.connectionType === ConnectionType.WS) { + this.apiId = await this.provider.call(1, this.apiName, []); + } else this.apiId = 0; + return this; } /** @@ -30,14 +35,13 @@ class EchoApi { * @returns {Promise} */ exec(method, params) { - if (!this.api_id) { - const errMessage = [ - `${this.api_name} API is not available`, - 'try to specify this in connection option called "apis"', - ].join(', '); - return Promise.reject(new Error(errMessage)); - } - return this.ws_rpc.call([this.api_id, method, params]); + if (this.provider.connectionType === ConnectionType.HTTP) return this.provider.call(method, params); + if (this.apiId !== undefined) return this.provider.call(this.apiId, method, params); + const errMessage = [ + `${this.apiName} API is not available`, + 'try to specify this in connection option called "apis"', + ].join(', '); + return Promise.reject(new Error(errMessage)); } } diff --git a/src/echo/ws/reconnection-websocket.js b/src/echo/ws/reconnection-websocket.js index 4becf8fb..baab9871 100644 --- a/src/echo/ws/reconnection-websocket.js +++ b/src/echo/ws/reconnection-websocket.js @@ -209,10 +209,15 @@ class ReconnectionWebSocket { this._cbId += 1; - if (method === 'set_subscribe_callback' || - method === 'broadcast_transaction_with_callback' || method === 'set_pending_transaction_callback' || - method === 'set_block_applied_callback' || method === 'set_echorand_message_callback' || - method === 'subscribe_contract_logs' || method === 'submit_registration_solution' || method === 'get_contract_logs' + if ( + method === 'set_subscribe_callback' || + method === 'broadcast_transaction_with_callback' || + method === 'set_pending_transaction_callback' || + method === 'set_block_applied_callback' || + method === 'set_echorand_message_callback' || + method === 'subscribe_contract_logs' || + method === 'submit_registration_solution' || + method === 'get_contract_logs' ) { // Store callback in subs map this._subs[this._cbId] = { @@ -434,10 +439,10 @@ class ReconnectionWebSocket { this.ws = null; if (ws) { - ws.onopen = () => {}; - ws.onclose = () => {}; - ws.onerror = () => {}; - ws.onmessage = () => {}; + ws.onopen = () => { }; + ws.onclose = () => { }; + ws.onerror = () => { }; + ws.onmessage = () => { }; ws.close(); } diff --git a/src/serializers/protocol/asset.js b/src/serializers/protocol/asset.js index 296b6982..b5623d20 100644 --- a/src/serializers/protocol/asset.js +++ b/src/serializers/protocol/asset.js @@ -28,7 +28,7 @@ export const assetCreateOperationPropsSerializer = struct({ fee: asset, issuer: accountId, symbol: stringSerializer, - precision: uint8, + precision: uint32, common_options: assetOptionsSerializer, bitasset_options: optional(bitassetOptionsSerializer), extensions, diff --git a/types/echo/echo-api.d.ts b/types/echo/echo-api.d.ts new file mode 100644 index 00000000..57ce96ec --- /dev/null +++ b/types/echo/echo-api.d.ts @@ -0,0 +1,9 @@ +import { HttpProvider, WsProvider } from "./providers"; + +export default class EchoApi { + public readonly apiName: string; + public readonly provider: HttpProvider | WsProvider; + constructor(provider: HttpProvider | WsProvider, apiName: string); + init(): Promise; + exec(method: string, params: any[]): Promise; +} diff --git a/types/echo/engine.d.ts b/types/echo/engine.d.ts new file mode 100644 index 00000000..3abb9281 --- /dev/null +++ b/types/echo/engine.d.ts @@ -0,0 +1,11 @@ +import ChainApi from "../interfaces/ChainApi"; +import EchoApi from "./echo-api"; +import { HttpProvider, WsProvider } from "./providers"; + +export default class EchoApiEngine { + public readonly availableApis: readonly ChainApi[]; + public readonly api: Readonly<{ [apiName in ChainApi]: EchoApi }>; + public readonly provider: HttpProvider | WsProvider; + constructor(apis: readonly ChainApi[]); + public init(): Promise; +} diff --git a/types/echo/providers/base-provider.d.ts b/types/echo/providers/base-provider.d.ts new file mode 100644 index 00000000..30329538 --- /dev/null +++ b/types/echo/providers/base-provider.d.ts @@ -0,0 +1,13 @@ +import ConnectionType from "./connection-type"; + +export interface BaseProviderOptions { + debug?: boolean; +} + +export default abstract class BaseProvider { + public readonly connectionType: ConnectionType; + public readonly url: string; + public debug: boolean; + constructor(url: string, options?: BaseProviderOptions); + protected log(message: string): void; +} diff --git a/types/echo/providers/connection-type.d.ts b/types/echo/providers/connection-type.d.ts new file mode 100644 index 00000000..52efe99f --- /dev/null +++ b/types/echo/providers/connection-type.d.ts @@ -0,0 +1,6 @@ +declare enum ConnectionType { + WS = "ws", + HTTP = "http", +} + +export default ConnectionType; diff --git a/types/echo/providers/http-provider.d.ts b/types/echo/providers/http-provider.d.ts new file mode 100644 index 00000000..3196986a --- /dev/null +++ b/types/echo/providers/http-provider.d.ts @@ -0,0 +1,8 @@ +import BaseProvider, { BaseProviderOptions } from "./base-provider"; +import ConnectionType from "./connection-type"; + +export default class HttpProvider extends BaseProvider { + public readonly connectionType: ConnectionType.HTTP; + constructor(url: string, options: BaseProviderOptions); + public call(method: string, params: any[]): Promise; +} diff --git a/types/echo/providers/index.d.ts b/types/echo/providers/index.d.ts new file mode 100644 index 00000000..ac4aef23 --- /dev/null +++ b/types/echo/providers/index.d.ts @@ -0,0 +1,4 @@ +export { default as BaseProvider, BaseProviderOptions } from "./base-provider"; +export { default as ConnectionType } from "./connection-type"; +export { default as HttpProvider } from "./http-provider"; +export { default as WsProvider, WsProviderOptions } from "./ws-provider"; diff --git a/types/echo/providers/ws-provider.d.ts b/types/echo/providers/ws-provider.d.ts new file mode 100644 index 00000000..2b23736f --- /dev/null +++ b/types/echo/providers/ws-provider.d.ts @@ -0,0 +1,22 @@ +import BaseProvider, { BaseProviderOptions } from "./base-provider"; +import ConnectionType from "./connection-type"; + +export interface WsProviderOptions extends BaseProviderOptions { + connectionTimeout?: number; + maxRetries?: number; + pingDelay?: number; + pingTimeout?: number; +} + +export default class WsProvider extends BaseProvider { + public readonly connectionType: ConnectionType.WS; + public connectionTimeout: number; + public maxRetries: number; + public pingDelay: number; + public pingTimeout: number; + constructor(url: string, options?: WsProviderOptions); + public call(apiId: number, method: string, params: any[]): Promise; + public close(): Promise; + public connect(): Promise; + public reconnect(): Promise; +} From e5130aabc376dd350bcee511ca21f3fbdf63dade Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Thu, 9 Apr 2020 21:59:10 +0300 Subject: [PATCH 48/62] [ECHOJS-250] WIP --- src/echo/api.js | 136 ++--- src/echo/{ws-api => apis}/asset-api.js | 0 src/echo/{ws/echo-api.js => apis/base-api.js} | 29 +- src/echo/{ws-api => apis}/database-api.js | 150 +++--- src/echo/{ws-api => apis}/echorand-api.js | 0 src/echo/{ws-api => apis}/history-api.js | 0 src/echo/apis/index.js | 9 + src/echo/{ws-api => apis}/login-api.js | 0 src/echo/{ws-api => apis}/network-api.js | 0 src/echo/{ws-api => apis}/network-node-api.js | 0 src/echo/{ws-api => apis}/registration-api.js | 0 src/echo/{ws-api => apis}/wallet-api.js | 6 +- src/echo/engine.js | 30 ++ src/echo/index.js | 61 +-- src/echo/providers.js | 42 -- .../{HTTPProvider.js => HttpProvider.js} | 0 .../{WSProvider.js => WsProvider.js} | 13 +- src/echo/providers/index.js | 6 + src/echo/ws-api/index.js | 33 -- src/echo/ws/reconnection-websocket.js | 495 ------------------ src/serializers/protocol/asset.js | 2 +- test/api.test.js | 2 +- types/echo/echo-api.d.ts | 1 + types/echo/engine.d.ts | 2 +- 24 files changed, 244 insertions(+), 773 deletions(-) rename src/echo/{ws-api => apis}/asset-api.js (100%) rename src/echo/{ws/echo-api.js => apis/base-api.js} (61%) rename src/echo/{ws-api => apis}/database-api.js (70%) rename src/echo/{ws-api => apis}/echorand-api.js (100%) rename src/echo/{ws-api => apis}/history-api.js (100%) create mode 100644 src/echo/apis/index.js rename src/echo/{ws-api => apis}/login-api.js (100%) rename src/echo/{ws-api => apis}/network-api.js (100%) rename src/echo/{ws-api => apis}/network-node-api.js (100%) rename src/echo/{ws-api => apis}/registration-api.js (100%) rename src/echo/{ws-api => apis}/wallet-api.js (99%) create mode 100644 src/echo/engine.js delete mode 100644 src/echo/providers.js rename src/echo/providers/{HTTPProvider.js => HttpProvider.js} (100%) rename src/echo/providers/{WSProvider.js => WsProvider.js} (97%) create mode 100644 src/echo/providers/index.js delete mode 100644 src/echo/ws-api/index.js delete mode 100644 src/echo/ws/reconnection-websocket.js diff --git a/src/echo/api.js b/src/echo/api.js index ef818a51..7905a2b8 100644 --- a/src/echo/api.js +++ b/src/echo/api.js @@ -488,12 +488,12 @@ class API { /** * * @param {Cache} cache - * @param {WSAPI} wsApi + * @param {import("./engine").default} engine * @param {import("./index").RegistrationOptions} [registrationOptions] */ - constructor(cache, wsApi, registrationOptions = {}) { + constructor(cache, engine, registrationOptions = {}) { this.cache = cache; - this.wsApi = wsApi; + this.engine = engine; this.registrationOptions = validateRegistrationOptions(registrationOptions); } @@ -518,7 +518,7 @@ class API { } try { - const requestedObject = await this.wsApi.database[methodName](); + const requestedObject = await this.engine.database[methodName](); this.cache.set(cacheName, new Map(requestedObject)); @@ -569,7 +569,7 @@ class API { let requestedObjects; try { - requestedObjects = await this.wsApi.database[methodName](requestedObjectsKeys); + requestedObjects = await this.engine.database[methodName](requestedObjectsKeys); } catch (error) { throw error; } @@ -617,7 +617,7 @@ class API { } try { - let requestedObject = await this.wsApi.database[methodName](key); + let requestedObject = await this.engine.database[methodName](key); if (!requestedObject) { return requestedObject; } @@ -656,7 +656,7 @@ class API { try { - const requestedObject = await this.wsApi.database[methodName](...params); + const requestedObject = await this.engine.database[methodName](...params); if (!requestedObject) { return requestedObject; @@ -777,7 +777,7 @@ class API { let requestedObjects; try { - requestedObjects = await this.wsApi.database[methodName](requestedObjectsKeys); + requestedObjects = await this.engine.database[methodName](requestedObjectsKeys); for (let i = 0; i < length; i += 1) { @@ -876,7 +876,7 @@ class API { */ async checkERC20Token(contractId) { if (!isContractId(contractId)) throw new Error('invalid contract id format'); - return this.wsApi.database.checkERC20Token(contractId); + return this.engine.database.checkERC20Token(contractId); } /** @@ -1024,7 +1024,7 @@ class API { } try { - const requestedObject = await this.wsApi.database.getChainId(); + const requestedObject = await this.engine.database.getChainId(); this.cache.set(CACHE_MAPS.CHAIN_ID, requestedObject); @@ -1107,7 +1107,7 @@ class API { let requestedObjects; try { - requestedObjects = await this.wsApi.database.getAccounts(requestedObjectsKeys); + requestedObjects = await this.engine.database.getAccounts(requestedObjectsKeys); for (let i = 0; i < length; i += 1) { if (resultArray[i]) continue; @@ -1145,7 +1145,7 @@ class API { async getAccountDeposits(account, type) { if (!isAccountId(account)) throw new Error('Invalid account id format'); validateSidechainType(type); - return this.wsApi.database.getAccountDeposits(account, type); + return this.engine.database.getAccountDeposits(account, type); } /** @@ -1157,7 +1157,7 @@ class API { async getAccountWithdrawals(account, type) { if (!isAccountId(account)) throw new Error('Invalid account id format'); validateSidechainType(type); - return this.wsApi.database.getAccountWithdrawals(account, type); + return this.engine.database.getAccountWithdrawals(account, type); } /** @@ -1212,7 +1212,7 @@ class API { } try { - requestedObjects = await this.wsApi.database.getFullAccounts(requestedObjects, true); + requestedObjects = await this.engine.database.getFullAccounts(requestedObjects, true); for (let i = 0; i < length; i += 1) { @@ -1285,7 +1285,7 @@ class API { } try { - const requestedObject = await this.wsApi.database.getAccountByName(accountName); + const requestedObject = await this.engine.database.getAccountByName(accountName); if (!requestedObject) { return requestedObject; @@ -1364,7 +1364,7 @@ class API { let requestedObjects; try { - requestedObjects = await this.wsApi.database.lookupAccountNames(requestedObjectsKeys); + requestedObjects = await this.engine.database.lookupAccountNames(requestedObjectsKeys); for (let i = 0; i < length; i += 1) { if (resultArray[i]) continue; @@ -1409,7 +1409,7 @@ class API { throw new Error(`Limit should be a integer and must not exceed ${API_CONFIG.LOOKUP_ACCOUNTS_MAX_LIMIT}`); } - return this.wsApi.database.lookupAccounts(lowerBoundName, limit); + return this.engine.database.lookupAccounts(lowerBoundName, limit); } /** @@ -1418,7 +1418,7 @@ class API { * @return {Promise} */ getAccountCount() { - return this.wsApi.database.getAccountCount(); + return this.engine.database.getAccountCount(); } /** @@ -1483,7 +1483,7 @@ class API { if (!isArray(balanceIds)) throw new Error('Balance ids should be an array'); if (!balanceIds.every((id) => isBalanceId(id))) throw new Error('Balance ids should contain valid balance ids'); - return this.wsApi.database.getVestedBalances(balanceIds); + return this.engine.database.getVestedBalances(balanceIds); } /** @@ -1495,7 +1495,7 @@ class API { async getVestingBalances(accountId) { if (!isAccountId(accountId)) throw new Error('Account id is invalid'); - return this.wsApi.database.getVestingBalances(accountId); + return this.engine.database.getVestingBalances(accountId); } /** @@ -1539,7 +1539,7 @@ class API { try { - requestedObjects = await this.wsApi.database.getAssets(requestedObjects); + requestedObjects = await this.engine.database.getAssets(requestedObjects); for (let i = 0; i < length; i += 1) { @@ -1584,7 +1584,7 @@ class API { throw new Error(`Limit should be a integer and must not exceed ${API_CONFIG.LIST_ASSETS_MAX_LIMIT}`); } - return this.wsApi.database.listAssets(lowerBoundSymbol, limit); + return this.engine.database.listAssets(lowerBoundSymbol, limit); } /** @@ -1632,7 +1632,7 @@ class API { try { - requestedObjects = await this.wsApi.database.lookupAssetSymbols(requestedObjects); + requestedObjects = await this.engine.database.lookupAssetSymbols(requestedObjects); } catch (error) { throw error; } @@ -1671,7 +1671,7 @@ class API { async getMarginPositions(accountId) { if (!isAccountId(accountId)) throw new Error('Account id is invalid'); - return this.wsApi.database.getMarginPositions(accountId); + return this.engine.database.getMarginPositions(accountId); } /** @@ -1686,7 +1686,7 @@ class API { if (!isAssetName(baseAssetName)) throw new Error('Base asset name is invalid'); if (!isAssetName(quoteAssetName)) throw new Error('Quote asset name is invalid'); - return this.wsApi.database.getTicker(baseAssetName, quoteAssetName); + return this.engine.database.getTicker(baseAssetName, quoteAssetName); } /** @@ -1701,7 +1701,7 @@ class API { if (!isAssetName(baseAssetName)) throw new Error('Base asset name is invalid'); if (!isAssetName(quoteAssetName)) throw new Error('Quote asset name is invalid'); - return this.wsApi.database.get24Volume(baseAssetName, quoteAssetName); + return this.engine.database.get24Volume(baseAssetName, quoteAssetName); } /** @@ -1730,7 +1730,7 @@ class API { throw new Error(`Limit should be capped at ${API_CONFIG.GET_TRADE_HISTORY_MAX_LIMIT}`); } - return this.wsApi.database.getTradeHistory(baseAssetName, quoteAssetName, start, stop, limit); + return this.engine.database.getTradeHistory(baseAssetName, quoteAssetName, start, stop, limit); } /** @@ -1809,7 +1809,7 @@ class API { throw new Error(`Limit should be capped at ${API_CONFIG.COMMITTEE_MEMBER_ACCOUNTS_MAX_LIMIT}`); } - return this.wsApi.database.lookupCommitteeMemberAccounts(lowerBoundName, limit); + return this.engine.database.lookupCommitteeMemberAccounts(lowerBoundName, limit); } /** @@ -1822,7 +1822,7 @@ class API { async getTransactionHex(tr) { const raw = transaction.toRaw(tr); // transaction is signed - return this.wsApi.database.getTransactionHex(raw); + return this.engine.database.getTransactionHex(raw); } /** @@ -1840,7 +1840,7 @@ class API { throw new Error('Available keys should contain valid public keys'); } - return this.wsApi.database.getRequiredSignatures(raw, availableKeys); + return this.engine.database.getRequiredSignatures(raw, availableKeys); } /** @@ -1852,7 +1852,7 @@ class API { */ async getPotentialSignatures(tr) { const raw = transaction.toRaw(tr); - return this.wsApi.database.getPotentialSignatures(raw); + return this.engine.database.getPotentialSignatures(raw); } /** @@ -1864,7 +1864,7 @@ class API { */ async verifyAuthority(tr) { const raw = transaction.toRaw(tr); - return this.wsApi.database.verifyAuthority(raw); + return this.engine.database.verifyAuthority(raw); } /** @@ -1882,7 +1882,7 @@ class API { if (!isArray(signers)) throw new Error('Signers ids should be an array'); if (!signers.every((key) => isPublicKey(key))) throw new Error('Signers should contain valid public keys'); - return this.wsApi.database.verifyAccountAuthority(accountNameOrId, signers); + return this.engine.database.verifyAccountAuthority(accountNameOrId, signers); } /** @@ -1895,7 +1895,7 @@ class API { async validateTransaction(tr) { const raw = signedTransaction.toRaw(tr); // signed transaction - return this.wsApi.database.validateTransaction(raw); + return this.engine.database.validateTransaction(raw); } /** @@ -1913,7 +1913,7 @@ class API { */ async getRequiredFees(operations, assetId = ECHO_ASSET_ID) { if (!isArray(operations)) return Promise.reject(new Error('Operations should be an array')); - return this.wsApi.database.getRequiredFees(operations.map((op) => operation.toRaw(op, true)), assetId); + return this.engine.database.getRequiredFees(operations.map((op) => operation.toRaw(op, true)), assetId); } /** @@ -1928,7 +1928,7 @@ class API { throw new Error('AccountNameOrId is invalid'); } - return this.wsApi.database.getProposedTransactions(accountNameOrId); + return this.engine.database.getProposedTransactions(accountNameOrId); } /** @@ -1972,7 +1972,7 @@ class API { const cb = (logs) => { resolve(logs[0].map(([, log]) => log)); }; - this.wsApi.database.getContractLogs(cb, { + this.engine.database.getContractLogs(cb, { contracts: opts.contracts, topics, from_block: BigNumber.isBigNumber(opts.fromBlock) ? opts.fromBlock.toNumber() : opts.fromBlock, @@ -2035,7 +2035,7 @@ class API { if (!isInt64(asset.amount)) throw new Error('Asset amount is not int64'); if (!isAssetId(asset.asset_id)) throw new Error('Invalid asset id'); if (!/^([\da-fA-F]{2})*$/.test(code)) throw new Error('Bytecode is invalid'); - return this.wsApi.database.callContractNoChangingState(contractId, caller, asset, code); + return this.engine.database.callContractNoChangingState(contractId, caller, asset, code); } /** @@ -2067,7 +2067,7 @@ class API { if (!isContractId(contractId)) throw new Error('ContractId is invalid'); if (!isBoolean(force)) throw new Error('Force should be a boolean'); - return this.wsApi.database.getContractBalances(contractId); + return this.engine.database.getContractBalances(contractId); } /** @@ -2080,7 +2080,7 @@ class API { async getContractPoolWhitelist(contractId) { if (!isContractId(contractId)) throw new Error('ContractId is invalid'); - return this.wsApi.database.getContractPoolWhitelist(contractId); + return this.engine.database.getContractPoolWhitelist(contractId); } /** @@ -2093,7 +2093,7 @@ class API { async getContractPoolBalance(contractId) { if (!isContractId(contractId)) throw new Error('ContractId is invalid'); - return this.wsApi.database.getContractPoolBalance(contractId); + return this.engine.database.getContractPoolBalance(contractId); } /** @@ -2106,7 +2106,7 @@ class API { async getRecentTransactionById(transactionId) { if (!isRipemd160(transactionId)) throw new Error('Transaction id should be a 20 bytes hex string'); - return this.wsApi.database.getRecentTransactionById(transactionId); + return this.engine.database.getRecentTransactionById(transactionId); } /** @@ -2130,7 +2130,7 @@ class API { broadcastTransactionWithCallback(signedTransactionObject, wasBroadcastedCallback) { return new Promise(async (resolve, reject) => { try { - await this.wsApi.network.broadcastTransactionWithCallback( + await this.engine.network.broadcastTransactionWithCallback( (res) => resolve(res), signedTransactionObject, ); @@ -2155,12 +2155,12 @@ class API { if (!isAccountName(name)) throw new Error('Name is invalid'); if (!isPublicKey(activeKey)) throw new Error('Active public key is invalid'); if (!isEchoRandKey(echoRandKey)) throw new Error('Echo rand key is invalid'); - const registrationTask = await this.wsApi.registration.requestRegistrationTask(); + const registrationTask = await this.engine.registration.requestRegistrationTask(); const { block_id: blockId, rand_num: randNum, difficulty } = registrationTask; const nonce = await solveRegistrationTask(blockId, randNum, difficulty, this.registrationOptions); return new Promise(async (resolve, reject) => { try { - await this.wsApi.registration.submitRegistrationSolution( + await this.engine.registration.submitRegistrationSolution( (res) => resolve(res), name, activeKey, @@ -2202,7 +2202,7 @@ class API { } if (!isOperationHistoryId(start)) throw new Error('Start parameter is invalid'); - return this.wsApi.history.getAccountHistory(accountId, stop, limit, start); + return this.engine.history.getAccountHistory(accountId, stop, limit, start); } /** @@ -2232,7 +2232,7 @@ class API { } if (!isUInt64(start)) throw new Error('Start parameter should be non negative number'); - return this.wsApi.history.getRelativeAccountHistory(accountId, stop, limit, start); + return this.engine.history.getRelativeAccountHistory(accountId, stop, limit, start); } /** @@ -2263,7 +2263,7 @@ class API { if (!isUInt64(limit) || limit > API_CONFIG.ACCOUNT_HISTORY_OPERATIONS_MAX_LIMIT) { throw new Error(`Limit should be capped at ${API_CONFIG.ACCOUNT_HISTORY_OPERATIONS_MAX_LIMIT}`); } - return this.wsApi.history + return this.engine.history .getAccountHistoryOperations(accountId, operationId, start, stop, limit); } @@ -2291,7 +2291,7 @@ class API { } if (!isOperationHistoryId(start)) throw new Error('Start parameter is invalid'); - return this.wsApi.history.getContractHistory( + return this.engine.history.getContractHistory( contractId, stop, limit, @@ -2366,7 +2366,7 @@ class API { return Promise.reject(new Error('Invalid transaction')); } - return this.wsApi.network.broadcastTransaction(tr); + return this.engine.network.broadcastTransaction(tr); } /** @@ -2396,7 +2396,7 @@ class API { return Promise.reject(new Error('Invalid block')); } - return this.wsApi.network.broadcastBlock(block); + return this.engine.network.broadcastBlock(block); } /** @@ -2423,7 +2423,7 @@ class API { return Promise.reject(new Error('Invalid limit accounts number')); } - return this.wsApi.asset.getAssetHolders(assetId, start, limit); + return this.engine.asset.getAssetHolders(assetId, start, limit); } /** @@ -2439,7 +2439,7 @@ class API { return Promise.reject(new Error('Invalid Asset ID')); } - return this.wsApi.asset.getAssetHoldersCount(assetId); + return this.engine.asset.getAssetHoldersCount(assetId); } /** @@ -2450,7 +2450,7 @@ class API { * [ { asset_id: '1.3.0', count: 8 } ] */ getAllAssetHolders() { - return this.wsApi.asset.getAllAssetHolders(); + return this.engine.asset.getAllAssetHolders(); } /** @@ -2461,7 +2461,7 @@ class API { getBalanceObjects(keys) { if (!isArray(keys)) return Promise.reject(new Error('Invalid keys')); - return this.wsApi.database.getBalanceObjects(keys); + return this.engine.database.getBalanceObjects(keys); } /** @@ -2470,7 +2470,7 @@ class API { * @returns {Promise} */ getBlockRewards(blockNum) { - return this.wsApi.database.getBlockRewards(basic.integers.uint32.toRaw(blockNum)); + return this.engine.database.getBlockRewards(basic.integers.uint32.toRaw(blockNum)); } /** @@ -2481,7 +2481,7 @@ class API { getBlockVirtualOperations(blockNum) { if (!isUInt64(blockNum)) return Promise.reject(new Error('BlockNumber should be a non negative integer')); - return this.wsApi.database.getBlockVirtualOperations(blockNum); + return this.engine.database.getBlockVirtualOperations(blockNum); } /** @@ -2492,7 +2492,7 @@ class API { getFrozenBalances(accountId) { if (!isAccountId(accountId)) return Promise.reject(new Error('Account id is invalid')); - return this.wsApi.database.getFrozenBalances(accountId); + return this.engine.database.getFrozenBalances(accountId); } /** @@ -2519,7 +2519,7 @@ class API { * @return {*} */ getAccountByAddress(address) { - return this.wsApi.database.getAccountByAddress(address); + return this.engine.database.getAccountByAddress(address); } /** @@ -2576,7 +2576,7 @@ class API { getBtcDepositScript(btcAddressId) { if (!isBtcAddressId(btcAddressId)) return Promise.reject(new Error('Btc address id is invalid')); - return this.wsApi.database.getBtcDepositScript(btcAddressId); + return this.engine.database.getBtcDepositScript(btcAddressId); } /* @@ -2585,7 +2585,7 @@ class API { * @return {Promise} */ requestRegistrationTask() { - return this.wsApi.registration.requestRegistrationTask(); + return this.engine.registration.requestRegistrationTask(); } /** @@ -2604,7 +2604,7 @@ class API { submitRegistrationSolution(name, activeKey, echorandKey, evmAddress, nounce, randNum, wasBroadcastedCallback) { return new Promise(async (resolve, reject) => { try { - await this.wsApi.registration.submitRegistrationSolution((res) => + await this.engine.registration.submitRegistrationSolution((res) => resolve(res), name, activeKey, echorandKey, evmAddress, nounce, randNum); } catch (error) { reject(error); @@ -2626,7 +2626,7 @@ class API { return Promise.reject(new Error('CommitteeMemberId should be valid committee id')); } - return this.wsApi.database.getCommitteeFrozenBalance(committeeMemberId); + return this.engine.database.getCommitteeFrozenBalance(committeeMemberId); } /** @@ -2635,20 +2635,20 @@ class API { * @return {*} */ getRegistrar() { - return this.wsApi.registration.getRegistrar(); + return this.engine.registration.getRegistrar(); } /** * @method getConnectedPeers - * @return {ReturnType} + * @return {ReturnType} */ - getConnectedPeers() { return this.wsApi.networkNode.getConnectedPeers(); } + getConnectedPeers() { return this.engine.networkNode.getConnectedPeers(); } /** * @method getPotentialPeers - * @return {Promise} + * @return {Promise} */ - getPotentialPeers() { return this.wsApi.networkNode.getPotentialPeers(); } + getPotentialPeers() { return this.engine.networkNode.getPotentialPeers(); } setOptions() { } diff --git a/src/echo/ws-api/asset-api.js b/src/echo/apis/asset-api.js similarity index 100% rename from src/echo/ws-api/asset-api.js rename to src/echo/apis/asset-api.js diff --git a/src/echo/ws/echo-api.js b/src/echo/apis/base-api.js similarity index 61% rename from src/echo/ws/echo-api.js rename to src/echo/apis/base-api.js index dbd334c5..6d9493cb 100644 --- a/src/echo/ws/echo-api.js +++ b/src/echo/apis/base-api.js @@ -3,22 +3,21 @@ import { ConnectionType } from '../providers'; /** @typedef {import("../providers").WSProvider} WSProvider */ /** @typedef {import("../providers").HttpProvider} HttpProvider */ -class EchoApi { +export default class BaseEchoApi { /** * * @param {HttpProvider | WSProvider} provider - * @param {String} apiName + * @param {string} apiName */ constructor(provider, apiName) { this.provider = provider; this.apiName = apiName; - /** @type {number | undefined} */ - this.apiId = undefined; + /** @type {number | null} */ + this.apiId = null; } /** - * * @returns {Promise} */ async init() { @@ -30,20 +29,20 @@ class EchoApi { /** * execute API method with params - * @param {String} method name - * @param {Array} params + * @param {string} method name + * @param {any[]} params * @returns {Promise} */ exec(method, params) { + if (this.apiId === null) { + const errMessage = [ + `${this.apiName} API is not available`, + 'try to specify this in connection option called "apis"', + ].join(', '); + return Promise.reject(new Error(errMessage)); + } if (this.provider.connectionType === ConnectionType.HTTP) return this.provider.call(method, params); - if (this.apiId !== undefined) return this.provider.call(this.apiId, method, params); - const errMessage = [ - `${this.apiName} API is not available`, - 'try to specify this in connection option called "apis"', - ].join(', '); - return Promise.reject(new Error(errMessage)); + return this.provider.call(this.apiId, method, params); } } - -export default EchoApi; diff --git a/src/echo/ws-api/database-api.js b/src/echo/apis/database-api.js similarity index 70% rename from src/echo/ws-api/database-api.js rename to src/echo/apis/database-api.js index cd7d4c47..5b559512 100644 --- a/src/echo/ws-api/database-api.js +++ b/src/echo/apis/database-api.js @@ -1,14 +1,18 @@ +import { CHAIN_API } from '../../constants/ws-constants'; +import BaseEchoApi from './base-api'; + +/** @typedef {import("../providers").WSProvider} WSProvider */ +/** @typedef {import("../providers").HttpProvider} HttpProvider */ /** @typedef {"" | "eth" | "btc"} SidechainType */ -class DatabaseAPI { +class DatabaseAPI extends BaseEchoApi { /** - * @constructor - * - * @param {EchoApi} db + * @constructor + * @param {} provider */ - constructor(db) { - this.db = db; + constructor(provider) { + super(provider, CHAIN_API.DATABASE_API); } /** @@ -17,7 +21,7 @@ class DatabaseAPI { * @return {Promise} */ getObjects(objectIds) { - return this.db.exec('get_objects', [objectIds]); + return this.exec('get_objects', [objectIds]); } /** @@ -25,7 +29,7 @@ class DatabaseAPI { * @returns {Promise} */ checkERC20Token(contractId) { - return this.db.exec('check_erc20_token', [contractId]); + return this.exec('check_erc20_token', [contractId]); } /** @@ -36,7 +40,7 @@ class DatabaseAPI { * @return {Promise} */ setSubscribeCallback(callback, notifyRemoveCreate) { - return this.db.exec('set_subscribe_callback', [callback, notifyRemoveCreate]); + return this.exec('set_subscribe_callback', [callback, notifyRemoveCreate]); } /** @@ -46,7 +50,7 @@ class DatabaseAPI { * @return {Promise} */ setPendingTransactionCallback(callback) { - return this.db.exec('set_pending_transaction_callback', [callback]); + return this.exec('set_pending_transaction_callback', [callback]); } /** @@ -56,7 +60,7 @@ class DatabaseAPI { * @return {Promise} */ setBlockAppliedCallback(callback) { - return this.db.exec('set_block_applied_callback', [callback]); + return this.exec('set_block_applied_callback', [callback]); } /** @@ -65,7 +69,7 @@ class DatabaseAPI { * @return {Promise} */ cancelAllSubscriptions() { - return this.db.exec('cancel_all_subscriptions', []); + return this.exec('cancel_all_subscriptions', []); } /** @@ -75,7 +79,7 @@ class DatabaseAPI { * @return {Promise} */ getBlockHeader(blockNum) { - return this.db.exec('get_block_header', [blockNum]); + return this.exec('get_block_header', [blockNum]); } /** @@ -85,7 +89,7 @@ class DatabaseAPI { * @return {Promise} */ getBlock(blockNum) { - return this.db.exec('get_block', [blockNum]); + return this.exec('get_block', [blockNum]); } /** @@ -96,7 +100,7 @@ class DatabaseAPI { * @return {Promise} */ getTransaction(blockNum, transactionIndex) { - return this.db.exec('get_transaction', [blockNum, transactionIndex]); + return this.exec('get_transaction', [blockNum, transactionIndex]); } /** @@ -105,7 +109,7 @@ class DatabaseAPI { * @return {Promise} */ getChainProperties() { - return this.db.exec('get_chain_properties', []); + return this.exec('get_chain_properties', []); } /** @@ -114,7 +118,7 @@ class DatabaseAPI { * @return {Promise} */ getGlobalProperties() { - return this.db.exec('get_global_properties', []); + return this.exec('get_global_properties', []); } /** @@ -123,7 +127,7 @@ class DatabaseAPI { * @return {Promise} */ getConfig() { - return this.db.exec('get_config', []); + return this.exec('get_config', []); } /** @@ -132,7 +136,7 @@ class DatabaseAPI { * @return {Promise} */ getChainId() { - return this.db.exec('get_chain_id', []); + return this.exec('get_chain_id', []); } /** @@ -141,7 +145,7 @@ class DatabaseAPI { * @return {Promise} */ getDynamicGlobalProperties() { - return this.db.exec('get_dynamic_global_properties', []); + return this.exec('get_dynamic_global_properties', []); } /** @@ -151,7 +155,7 @@ class DatabaseAPI { * @return {Promise} */ getKeyReferences(keys) { - return this.db.exec('get_key_references', [keys]); + return this.exec('get_key_references', [keys]); } /** @@ -161,7 +165,7 @@ class DatabaseAPI { * @return {Promise} */ getAccounts(accountIds) { - return this.db.exec('get_accounts', [accountIds]); + return this.exec('get_accounts', [accountIds]); } /** @@ -172,7 +176,7 @@ class DatabaseAPI { * @return {Promise} */ getFullAccounts(accountNamesOrIds, subscribe) { - return this.db.exec('get_full_accounts', [accountNamesOrIds, subscribe]); + return this.exec('get_full_accounts', [accountNamesOrIds, subscribe]); } /** @@ -182,7 +186,7 @@ class DatabaseAPI { * @return {Promise} */ getAccountByName(accountName) { - return this.db.exec('get_account_by_name', [accountName]); + return this.exec('get_account_by_name', [accountName]); } /** @@ -192,7 +196,7 @@ class DatabaseAPI { * @returns {Promise} */ getAccountDeposits(account, type) { - return this.db.exec('get_account_deposits', [account, type]); + return this.exec('get_account_deposits', [account, type]); } /** @@ -202,7 +206,7 @@ class DatabaseAPI { * @return {Promise} */ getAccountReferences(accountId) { - return this.db.exec('get_account_references', [accountId]); + return this.exec('get_account_references', [accountId]); } /** @@ -212,7 +216,7 @@ class DatabaseAPI { * @returns {Promise} */ getAccountWithdrawals(account, type) { - return this.db.exec('get_account_withdrawals', [account, type]); + return this.exec('get_account_withdrawals', [account, type]); } /** @@ -222,7 +226,7 @@ class DatabaseAPI { * @return {Promise} */ lookupAccountNames(accountNames) { - return this.db.exec('lookup_account_names', [accountNames]); + return this.exec('lookup_account_names', [accountNames]); } /** @@ -233,7 +237,7 @@ class DatabaseAPI { * @return {Promise} */ lookupAccounts(lowerBoundName, limit) { - return this.db.exec('lookup_accounts', [lowerBoundName, limit]); + return this.exec('lookup_accounts', [lowerBoundName, limit]); } /** @@ -242,7 +246,7 @@ class DatabaseAPI { * @return {Promise} */ getAccountCount() { - return this.db.exec('get_account_count', []); + return this.exec('get_account_count', []); } /** @@ -253,7 +257,7 @@ class DatabaseAPI { * @return {Promise} */ getAccountBalances(accountId, assetIds) { - return this.db.exec('get_account_balances', [accountId, assetIds]); + return this.exec('get_account_balances', [accountId, assetIds]); } /** @@ -264,7 +268,7 @@ class DatabaseAPI { * @return {Promise} */ getNamedAccountBalances(accountName, assetIds) { - return this.db.exec('get_named_account_balances', [accountName, assetIds]); + return this.exec('get_named_account_balances', [accountName, assetIds]); } /** @@ -274,7 +278,7 @@ class DatabaseAPI { * @return {Promise} */ getVestedBalances(objectIds) { - return this.db.exec('get_vested_balances', [objectIds]); + return this.exec('get_vested_balances', [objectIds]); } /** @@ -284,7 +288,7 @@ class DatabaseAPI { * @return {Promise} */ getVestingBalances(accountId) { - return this.db.exec('get_vesting_balances', [accountId]); + return this.exec('get_vesting_balances', [accountId]); } /** @@ -294,7 +298,7 @@ class DatabaseAPI { * @return {Promise} */ getAssets(assetIds) { - return this.db.exec('get_assets', [assetIds]); + return this.exec('get_assets', [assetIds]); } /** @@ -305,7 +309,7 @@ class DatabaseAPI { * @return {Promise} */ listAssets(lowerBoundSymbol, limit) { - return this.db.exec('list_assets', [lowerBoundSymbol, limit]); + return this.exec('list_assets', [lowerBoundSymbol, limit]); } /** @@ -315,7 +319,7 @@ class DatabaseAPI { * @return {Promise} */ lookupAssetSymbols(symbolsOrIds) { - return this.db.exec('lookup_asset_symbols', [symbolsOrIds]); + return this.exec('lookup_asset_symbols', [symbolsOrIds]); } /** @@ -325,7 +329,7 @@ class DatabaseAPI { * @return {Promise} */ getMarginPositions(accountId) { - return this.db.exec('get_margin_positions', [accountId]); + return this.exec('get_margin_positions', [accountId]); } /** @@ -337,7 +341,7 @@ class DatabaseAPI { * @return {Promise} */ getTicker(baseAssetName, quoteAssetName) { - return this.db.exec('get_ticker', [baseAssetName, quoteAssetName]); + return this.exec('get_ticker', [baseAssetName, quoteAssetName]); } /** @@ -349,7 +353,7 @@ class DatabaseAPI { * @return {Promise} */ get24Volume(baseAssetName, quoteAssetName) { - return this.db.exec('get_24_volume', [baseAssetName, quoteAssetName]); + return this.exec('get_24_volume', [baseAssetName, quoteAssetName]); } /** @@ -364,7 +368,7 @@ class DatabaseAPI { * @return {Promise} */ getTradeHistory(baseAssetName, quoteAssetName, start, stop, limit = 100) { - return this.db.exec('get_trade_history', [baseAssetName, quoteAssetName, start, stop, limit]); + return this.exec('get_trade_history', [baseAssetName, quoteAssetName, start, stop, limit]); } /** @@ -375,7 +379,7 @@ class DatabaseAPI { * @return {Promise} */ getCommitteeMembers(committeeMemberIds) { - return this.db.exec('get_committee_members', [committeeMemberIds]); + return this.exec('get_committee_members', [committeeMemberIds]); } /** @@ -386,7 +390,7 @@ class DatabaseAPI { * @return {Promise} */ getCommitteeMemberByAccount(accountId) { - return this.db.exec('get_committee_member_by_account', [accountId]); + return this.exec('get_committee_member_by_account', [accountId]); } /** @@ -398,7 +402,7 @@ class DatabaseAPI { * @return {Promise} */ lookupCommitteeMemberAccounts(lowerBoundName, limit) { - return this.db.exec('lookup_committee_member_accounts', [lowerBoundName, limit]); + return this.exec('lookup_committee_member_accounts', [lowerBoundName, limit]); } /** @@ -410,7 +414,7 @@ class DatabaseAPI { */ getTransactionHex(transaction) { // transaction is signed - return this.db.exec('get_transaction_hex', [transaction]); + return this.exec('get_transaction_hex', [transaction]); } /** @@ -422,7 +426,7 @@ class DatabaseAPI { * @return {Promise} */ getRequiredSignatures(transaction, availableKeys) { - return this.db.exec('get_required_signatures', [transaction, availableKeys]); + return this.exec('get_required_signatures', [transaction, availableKeys]); } /** @@ -433,7 +437,7 @@ class DatabaseAPI { * @return {Promise} */ getPotentialSignatures(transaction) { - return this.db.exec('get_potential_signatures', [transaction]); + return this.exec('get_potential_signatures', [transaction]); } /** @@ -444,7 +448,7 @@ class DatabaseAPI { * @return {Promise} */ verifyAuthority(transaction) { - return this.db.exec('verify_authority', [transaction]); + return this.exec('verify_authority', [transaction]); } /** @@ -457,7 +461,7 @@ class DatabaseAPI { */ verifyAccountAuthority(accountNameOrId, signers) { // signers - set of public keys - return this.db.exec('verify_account_authority', [accountNameOrId, signers]); + return this.exec('verify_account_authority', [accountNameOrId, signers]); } /** @@ -469,7 +473,7 @@ class DatabaseAPI { */ validateTransaction(transaction) { // signed transaction - return this.db.exec('validate_transaction', [transaction]); + return this.exec('validate_transaction', [transaction]); } /** @@ -481,7 +485,7 @@ class DatabaseAPI { * @return {Promise} */ getRequiredFees(operations, assetId) { - return this.db.exec('get_required_fees', [operations, assetId]); + return this.exec('get_required_fees', [operations, assetId]); } /** @@ -492,7 +496,7 @@ class DatabaseAPI { * @return {Promise} */ getProposedTransactions(accountNameOrId) { - return this.db.exec('get_proposed_transactions', [accountNameOrId]); + return this.exec('get_proposed_transactions', [accountNameOrId]); } /** @@ -506,7 +510,7 @@ class DatabaseAPI { * @returns {Promise} */ getContractLogs(callback, opts) { - return this.db.exec('get_contract_logs', [callback, opts]); + return this.exec('get_contract_logs', [callback, opts]); } /** @@ -518,7 +522,7 @@ class DatabaseAPI { * @return {Promise} */ subscribeContractLogs(callback, contractTopicsMap) { - return this.db.exec('subscribe_contract_logs', [callback, contractTopicsMap]); + return this.exec('subscribe_contract_logs', [callback, contractTopicsMap]); } /** @@ -529,7 +533,7 @@ class DatabaseAPI { * @return {Promise} */ getContractResult(resultContractId) { - return this.db.exec('get_contract_result', [resultContractId]); + return this.exec('get_contract_result', [resultContractId]); } /** @@ -540,7 +544,7 @@ class DatabaseAPI { * @return {Promise} */ getContract(contractId) { - return this.db.exec('get_contract', [contractId]); + return this.exec('get_contract', [contractId]); } /** @@ -552,7 +556,7 @@ class DatabaseAPI { * @return {Promise} */ callContractNoChangingState(contractId, caller, asset, code) { - return this.db.exec('call_contract_no_changing_state', [contractId, caller, asset, code]); + return this.exec('call_contract_no_changing_state', [contractId, caller, asset, code]); } /** @@ -563,7 +567,7 @@ class DatabaseAPI { * @return {Promise} */ getContracts(contractIds) { - return this.db.exec('get_contracts', [contractIds]); + return this.exec('get_contracts', [contractIds]); } /** @@ -574,7 +578,7 @@ class DatabaseAPI { * @return {Promise} */ getContractBalances(contractId) { - return this.db.exec('get_contract_balances', [contractId]); + return this.exec('get_contract_balances', [contractId]); } /** @@ -585,7 +589,7 @@ class DatabaseAPI { * @return {Promise} */ getContractPoolWhitelist(contractId) { - return this.db.exec('get_contract_pool_whitelist', [contractId]); + return this.exec('get_contract_pool_whitelist', [contractId]); } /** @@ -596,7 +600,7 @@ class DatabaseAPI { * @return {Promise} */ subscribeContracts(contractIds) { - return this.db.exec('subscribe_contracts', [contractIds]); + return this.exec('subscribe_contracts', [contractIds]); } /** @@ -607,7 +611,7 @@ class DatabaseAPI { * @return {Promise} */ getContractPoolBalance(contractId) { - return this.db.exec('get_contract_pool_balance', [contractId]); + return this.exec('get_contract_pool_balance', [contractId]); } /** @@ -618,7 +622,7 @@ class DatabaseAPI { * @return {Promise} */ getRecentTransactionById(transactionId) { - return this.db.exec('get_recent_transaction_by_id', [transactionId]); + return this.exec('get_recent_transaction_by_id', [transactionId]); } /** @@ -629,7 +633,7 @@ class DatabaseAPI { * @return {Promise} */ getBalanceObjects(keys) { - return this.db.exec('get_balance_objects', [keys]); + return this.exec('get_balance_objects', [keys]); } /** @@ -638,7 +642,7 @@ class DatabaseAPI { * @returns {Promise} */ getBlockRewards(blockNum) { - return this.db.exec('get_block_rewards', [blockNum]); + return this.exec('get_block_rewards', [blockNum]); } /** @@ -649,7 +653,7 @@ class DatabaseAPI { * @return {Promise} */ getBlockVirtualOperations(blockNum) { - return this.db.exec('get_block_virtual_ops', [blockNum]); + return this.exec('get_block_virtual_ops', [blockNum]); } /** @@ -659,7 +663,7 @@ class DatabaseAPI { * @return {Promise} */ getFrozenBalances(accountId) { - return this.db.exec('get_frozen_balances', [accountId]); + return this.exec('get_frozen_balances', [accountId]); } /** @@ -669,7 +673,7 @@ class DatabaseAPI { * @return {Promise} */ getBtcAddress(accountId) { - return this.db.exec('get_btc_address', [accountId]); + return this.exec('get_btc_address', [accountId]); } /** @@ -679,7 +683,7 @@ class DatabaseAPI { * @return {Promise} */ getBtcDepositScript(btcDepositId) { - return this.db.exec('get_btc_deposit_script', [btcDepositId]); + return this.exec('get_btc_deposit_script', [btcDepositId]); } /** @@ -689,7 +693,7 @@ class DatabaseAPI { * @return {Promise} */ getCommitteeFrozenBalance(committeeMemberId) { - return this.db.exec('get_committee_frozen_balance', [committeeMemberId]); + return this.exec('get_committee_frozen_balance', [committeeMemberId]); } /** @@ -701,7 +705,7 @@ class DatabaseAPI { * @return {Promise} */ getAccountAddresses(id, from, limit) { - return this.db.exec('get_account_addresses', [id, from, limit]); + return this.exec('get_account_addresses', [id, from, limit]); } /** @@ -711,7 +715,7 @@ class DatabaseAPI { * @return {Promise} */ getEthAddress(id) { - return this.db.exec('get_eth_address', [id]); + return this.exec('get_eth_address', [id]); } /** @@ -721,7 +725,7 @@ class DatabaseAPI { * @return {Promise} */ getAccountByAddress(address) { - return this.db.exec('get_account_by_address', [address]); + return this.exec('get_account_by_address', [address]); } } diff --git a/src/echo/ws-api/echorand-api.js b/src/echo/apis/echorand-api.js similarity index 100% rename from src/echo/ws-api/echorand-api.js rename to src/echo/apis/echorand-api.js diff --git a/src/echo/ws-api/history-api.js b/src/echo/apis/history-api.js similarity index 100% rename from src/echo/ws-api/history-api.js rename to src/echo/apis/history-api.js diff --git a/src/echo/apis/index.js b/src/echo/apis/index.js new file mode 100644 index 00000000..5ac2b220 --- /dev/null +++ b/src/echo/apis/index.js @@ -0,0 +1,9 @@ +export { default as AssetApi } from './asset-api'; +export { default as DatabaseApi } from './database-api'; +export { default as EchoRandApi } from './echorand-api'; +export { default as HistoryApi } from './history-api'; +export { default as LoginApi } from './login-api'; +export { default as NetworkApi } from './network-api'; +export { default as NetworkNodeApi } from './network-node-api'; +export { default as RegistrationApi } from './registration-api'; +export { default as WalletApi } from './wallet-api'; diff --git a/src/echo/ws-api/login-api.js b/src/echo/apis/login-api.js similarity index 100% rename from src/echo/ws-api/login-api.js rename to src/echo/apis/login-api.js diff --git a/src/echo/ws-api/network-api.js b/src/echo/apis/network-api.js similarity index 100% rename from src/echo/ws-api/network-api.js rename to src/echo/apis/network-api.js diff --git a/src/echo/ws-api/network-node-api.js b/src/echo/apis/network-node-api.js similarity index 100% rename from src/echo/ws-api/network-node-api.js rename to src/echo/apis/network-node-api.js diff --git a/src/echo/ws-api/registration-api.js b/src/echo/apis/registration-api.js similarity index 100% rename from src/echo/ws-api/registration-api.js rename to src/echo/apis/registration-api.js diff --git a/src/echo/ws-api/wallet-api.js b/src/echo/apis/wallet-api.js similarity index 99% rename from src/echo/ws-api/wallet-api.js rename to src/echo/apis/wallet-api.js index df3a72b4..c6a63340 100644 --- a/src/echo/ws-api/wallet-api.js +++ b/src/echo/apis/wallet-api.js @@ -1,6 +1,6 @@ import * as serializers from '../../serializers'; import { API_CONFIG } from '../../constants'; -import ReconnectionWebSocket from '../ws/reconnection-websocket'; +import WsProvider from '../providers/WsProvider'; import { isAccountId, isAccountIdOrName, @@ -78,12 +78,12 @@ const { class WalletAPI { - constructor() { this.wsRpc = new ReconnectionWebSocket(); } + constructor() { this.wsRpc = new WsProvider(); } /** * Init params and connect to chain. * @param {string} url remote node address - * @param {Parameters1} connectionOptions connection params. + * @param {Parameters1} connectionOptions connection params. * @returns {Promise} */ async connect(url, connectionOptions) { await this.wsRpc.connect(url, connectionOptions); } diff --git a/src/echo/engine.js b/src/echo/engine.js new file mode 100644 index 00000000..6945246d --- /dev/null +++ b/src/echo/engine.js @@ -0,0 +1,30 @@ +import { CHAIN_API } from '../constants/ws-constants'; +import * as Apis from './apis'; + +/** @typedef {import("./providers").WsProvider} WsProvider */ +/** @typedef {import("./providers").HttpProvider} HttpProvider */ + +export default class EchoApiEngine { + + /** + * @param {string[]} apis + * @param {WsProvider | HttpProvider} provider + */ + constructor(apis, provider) { + this.provider = provider; + this[CHAIN_API.DATABASE_API] = new Apis.DatabaseApi(this.provider); + this[CHAIN_API.ASSET_API] = new Apis.AssetApi(this.provider); + this[CHAIN_API.NETWORK_BROADCAST_API] = new Apis.NetworkApi(this.provider); + this[CHAIN_API.HISTORY_API] = new Apis.HistoryApi(this.provider); + this[CHAIN_API.REGISTRATION_API] = new Apis.RegistrationApi(this.provider); + this[CHAIN_API.LOGIN_API] = new Apis.LoginApi(this.provider); + this[CHAIN_API.NETWORK_NODE_API] = new Apis.NetworkNodeApi(this.provider); + this[CHAIN_API.ECHORAND_API] = new Apis.EchoRandApi(this.provider); + this.apis = [...apis]; + } + + init() { + return Promise.all(this.apis.map((apiName) => this[apiName].init())); + } + +} diff --git a/src/echo/index.js b/src/echo/index.js index eb17f249..e24cebc4 100644 --- a/src/echo/index.js +++ b/src/echo/index.js @@ -1,12 +1,11 @@ -import WS from './ws'; -import WSAPI from './ws-api'; - import Cache from './cache'; import API from './api'; import Subscriber from './subscriber'; import Transaction from './transaction'; -import { STATUS } from '../constants/ws-constants'; -import WalletAPI from './ws-api/wallet-api'; +import { STATUS, DEFAULT_CHAIN_APIS } from '../constants/ws-constants'; +import { WalletApi } from './apis'; +import EchoApiEngine from './engine'; +import { ConnectionType, WsProvider, HttpProvider } from './providers'; /** @typedef {{ batch?: number, timeout?: number }} RegistrationOptions */ @@ -15,15 +14,17 @@ import WalletAPI from './ws-api/wallet-api'; class Echo { constructor() { - this._ws = new WS(); - this.subscriber = new Subscriber(this._ws); + /** @type {EchoApiEngine | null} */ + this.engine = null; this._isInitModules = false; this.initEchoApi = this.initEchoApi.bind(this); - this.walletApi = new WalletAPI(); + this.walletApi = new WalletApi(); } get isConnected() { - return this._ws._connected; + if (this.engine === null) return false; + if (this.engine.provider.connectionType === ConnectionType.HTTP) return true; + return this.engine.provider.connected; } /** @@ -38,11 +39,10 @@ class Echo { * @private */ async _connectToNode(address, options) { - await this._ws.connect(address, options); - - if (this._isInitModules) { - return; - } + const provider = address.startsWith('ws') ? new WsProvider() : new HttpProvider(address); + if (provider.connectionType === ConnectionType.WS) await provider.connect(address, options); + this.engine = new EchoApiEngine(options.apis || DEFAULT_CHAIN_APIS, provider); + if (this._isInitModules) return; await this._initModules(options); @@ -51,6 +51,7 @@ class Echo { } this.cache.setOptions(options); + this.subscriber = new Subscriber(this.engine); this.subscriber.setOptions(options); } @@ -59,40 +60,31 @@ class Echo { * @param {Options} options */ async connect(address, options = {}) { - if (this._ws._connected) { - throw new Error('Connected'); - } - - try { - await Promise.all([ - ...address ? [this._connectToNode(address, options)] : [], - ...options.wallet ? [this.walletApi.connect(options.wallet, options)] : [], - ]); - } catch (e) { - throw e; - } - + if (this.isConnected) throw new Error('Connected'); + await Promise.all([ + ...address ? [this._connectToNode(address, options)] : [], + ...options.wallet ? [this.walletApi.connect(options.wallet, options)] : [], + ]); } /** @param {Options} options */ async _initModules(options) { this._isInitModules = true; - this._wsApi = new WSAPI(this._ws); - this.cache = new Cache(options.cache); - this.api = new API(this.cache, this._wsApi, options.registration); - await this.subscriber.init(this.cache, this._wsApi, this.api); - this._ws.on(STATUS.OPEN, this.initEchoApi); + this.api = new API(this.cache, this.engine, options.registration); + await this.engine.init(); + // await this.subscriber.init(this.cache, this.engine, this.api); + // this._ws.on(STATUS.OPEN, this.initEchoApi); } async initEchoApi() { await this._ws.initEchoApi(); - await this.subscriber.init(this.cache, this._wsApi, this.api); + // await this.subscriber.init(this.cache, this.engine, this.api); } syncCacheWithStore(store) { - if (this._ws._connected) { + if (this.isConnected) { this.cache.setStore({ store }); } this.store = store; @@ -102,7 +94,6 @@ class Echo { this._ws.removeListener(STATUS.OPEN, this.initEchoApi); await this._ws.reconnect(); await this.initEchoApi(); - this._ws.on(STATUS.OPEN, this.initEchoApi); } async disconnect() { diff --git a/src/echo/providers.js b/src/echo/providers.js deleted file mode 100644 index 2673d845..00000000 --- a/src/echo/providers.js +++ /dev/null @@ -1,42 +0,0 @@ -import axios from 'axios'; -import ReconnectionWebSocket from './ws/reconnection-websocket'; - -export const ConnectionType = { - WS: 'ws', - HTTP: 'http', -}; - -export class WSProvider { - - get connectionType() { return ConnectionType.WS; } - - constructor() { - this._ws = new ReconnectionWebSocket(); - } - - async connect(url, options) { - this.url = url; - await this._ws.connect(url, options); - } - - call(apiId, method, params) { - return this._ws.call([apiId, method, params]); - } - -} - -export class HttpProvider { - - get connectionType() { return ConnectionType.HTTP; } - - constructor(url) { - this.url = url; - } - - call(method, params) { - return axios.post(this.url, { - jsonrpc: '2.0', id: 0, method, params, - }); - } - -} diff --git a/src/echo/providers/HTTPProvider.js b/src/echo/providers/HttpProvider.js similarity index 100% rename from src/echo/providers/HTTPProvider.js rename to src/echo/providers/HttpProvider.js diff --git a/src/echo/providers/WSProvider.js b/src/echo/providers/WsProvider.js similarity index 97% rename from src/echo/providers/WSProvider.js rename to src/echo/providers/WsProvider.js index 4ecb7933..cfc0960d 100644 --- a/src/echo/providers/WSProvider.js +++ b/src/echo/providers/WsProvider.js @@ -12,8 +12,9 @@ import { import { isVoid } from '../../utils/validators'; import * as ConnectionType from './connection-types'; -export default class WSProvider { +export default class WsProvider { + get connected() { return this.ws && this.ws.readyState === WebSocket.OPEN; } get connectionType() { return ConnectionType.WS; } constructor() { @@ -50,7 +51,7 @@ export default class WSProvider { * @returns {Promise} */ async connect(url, options = {}) { - if (this.ws && this.ws.readyState === WebSocket.OPEN) await this.close(); + if (this.connected) await this.close(); this._options = { connectionTimeout: isVoid(options.connectionTimeout) ? CONNECTION_TIMEOUT : options.connectionTimeout, maxRetries: isVoid(options.maxRetries) ? MAX_RETRIES : options.maxRetries, @@ -436,10 +437,10 @@ export default class WSProvider { this.ws = null; if (ws) { - ws.onopen = () => { }; - ws.onclose = () => { }; - ws.onerror = () => { }; - ws.onmessage = () => { }; + ws.onopen = () => {}; + ws.onclose = () => {}; + ws.onerror = () => {}; + ws.onmessage = () => {}; ws.close(); } diff --git a/src/echo/providers/index.js b/src/echo/providers/index.js new file mode 100644 index 00000000..cd86c30c --- /dev/null +++ b/src/echo/providers/index.js @@ -0,0 +1,6 @@ +import * as ConnectionType from './connection-types'; + +export { default as HttpProvider } from './HttpProvider'; +export { default as WsProvider } from './WsProvider'; + +export { ConnectionType }; diff --git a/src/echo/ws-api/index.js b/src/echo/ws-api/index.js deleted file mode 100644 index 3464c85e..00000000 --- a/src/echo/ws-api/index.js +++ /dev/null @@ -1,33 +0,0 @@ -import DatabaseAPI from './database-api'; -import AssetAPI from './asset-api'; -import NetworkAPI from './network-api'; -import HistoryAPI from './history-api'; -import RegistrationAPI from './registration-api'; -import LoginAPI from './login-api'; -import NetworkNodeAPI from './network-node-api'; -import EchorandAPI from './echorand-api'; - - -class WSAPI { - - /** - * @constructor - * - * @param {WS} ws - */ - constructor(ws) { - this.ws = ws; - - this.database = new DatabaseAPI(this.ws.dbApi()); - this.asset = new AssetAPI(this.ws.assetApi()); - this.network = new NetworkAPI(this.ws.networkApi()); - this.history = new HistoryAPI(this.ws.historyApi()); - this.registration = new RegistrationAPI(this.ws.registrationApi()); - this.login = new LoginAPI(this.ws.loginApi()); - this.networkNode = new NetworkNodeAPI(this.ws.networkNodeApi()); - this.echorand = new EchorandAPI(this.ws.echorandApi()); - } - -} - -export default WSAPI; diff --git a/src/echo/ws/reconnection-websocket.js b/src/echo/ws/reconnection-websocket.js deleted file mode 100644 index baab9871..00000000 --- a/src/echo/ws/reconnection-websocket.js +++ /dev/null @@ -1,495 +0,0 @@ -/* eslint-disable max-len,no-empty */ -import WebSocket from 'isomorphic-ws'; - -import { - CONNECTION_TIMEOUT, - MAX_RETRIES, - PING_TIMEOUT, - PING_DELAY, - DEBUG, - CONNECTION_CLOSED_ERROR_MESSAGE, -} from '../../constants/ws-constants'; - -import { isVoid } from '../../utils/validators'; - -class ReconnectionWebSocket { - - constructor() { - this.onOpen = null; - this.onClose = null; - this.onError = null; - - this._currentRetry = 0; - this._pingDelayId = null; - this._options = {}; - - this._cbId = 0; - this._responseCbId = 0; - this._cbs = {}; - this._subs = []; - this._unsub = {}; - } - - /** - * init params and connect to chain - * @param {String} url - remote node address, - * should be (http|https|ws|wws)://(domain|ipv4|ipv6):port(?)/resource(?)?param=param(?). - * @param {Object} options - connection params. - * @param {Number} options.connectionTimeout - delay in ms between reconnection requests, default call delay before reject it. - * @param {Number} options.maxRetries - max count retries before close socket. - * @param {Number} options.pingTimeout - delay time in ms between ping request and socket disconnect. - * @param {Number} options.pingDelay - delay between last recived message and start checking connection. - * @param {Boolean} options.debug - debug mode status. - * @returns {Promise} - */ - async connect( - url, - options = {}, - ) { - if (this.ws && this.ws.readyState === WebSocket.OPEN) { - try { - await this.close(); - } catch (error) { - throw error; - } - } - - this._options = { - connectionTimeout: isVoid(options.connectionTimeout) ? CONNECTION_TIMEOUT : options.connectionTimeout, - maxRetries: isVoid(options.maxRetries) ? MAX_RETRIES : options.maxRetries, - pingTimeout: isVoid(options.pingTimeout) ? PING_TIMEOUT : options.pingTimeout, - pingDelay: isVoid(options.pingDelay) ? PING_DELAY : options.pingDelay, - debug: isVoid(options.debug) ? DEBUG : options.debug, - }; - - this.url = url; - this._isFirstConnection = true; - this._currentRetry = 0; - this._forceClosePromise = null; - this._reconnectionTimeoutId = null; - - this._cbId = 0; - this._responseCbId = 0; - this._cbs = {}; - this._cbLogs = []; - this._subs = []; - this._unsub = {}; - - return this._connect(); - } - - /** - * inner connection method - * @returns {Promise} - */ - _connect() { - - this._debugLog('[ReconnectionWebSocket] >---- retry _connect'); - - this._currentRetry += 1; - return new Promise((resolve, reject) => { - let ws = null; - try { - ws = new WebSocket(this.url); - } catch (error) { - ws = null; - if (this._isFirstConnection) { - this._isFirstConnection = false; - return reject(error); - } - } - - ws.onopen = () => { - - this._currentRetry = 0; - - if (this._isFirstConnection) { - this._isFirstConnection = false; - resolve(); - } - - if (this.onOpen) this.onOpen(); - - this._setPingDelay(); - - this._debugLog('[ReconnectionWebSocket] >---- event -----> ONOPEN'); - return true; - }; - - ws.onmessage = (message) => { - - if (ws !== this.ws) { - return false; - } - - this._responseHandler(JSON.parse(message.data)); - - this._debugLog('[ReconnectionWebSocket] >---- event -----> ONMESSAGE'); - - this._setPingDelay(); - - return true; - }; - - ws.onclose = () => { - - if (ws !== this.ws) { - return false; - } - - if (this._isFirstConnection) { - this._isFirstConnection = false; - reject(new Error('Could\'t reach server or bad internet access')); - return false; - } - - this._forceClose(); - - return true; - - }; - - ws.onerror = (error) => { - - if (ws !== this.ws) { - return false; - } - - if (this.onError) this.onError(error); - - this._debugLog('[ReconnectionWebSocket] >---- event -----> ONERROR'); - - return true; - }; - - this.ws = ws; - - return ws; - }); - } - - /** - * connect to socket, can't be used after close - * @returns {Promise} - */ - async reconnect() { - if (!this.ws) { - throw new Error('Socket not exist.'); - } - - this._debugLog('[ReconnectionWebSocket] >---- event -----> FORCE RECONNECTING'); - await this.connect(this.url, this._options); - } - - /** - * set debug option - * @param {Boolean} status - */ - setDebugOption(status) { - this._options.debug = Boolean(status); - } - - /** - * call a method with params via RPC - * @param {Array} params - * @param {Number} timeout - timeout before reject - * @returns {Promise} - */ - call(params, timeout = this._options.connectionTimeout) { - if (!this.ws) { - return Promise.reject(new Error('Websocket is closed')); - } - - if (this.ws.readyState !== WebSocket.OPEN) { - return Promise.reject(new Error(`Websocket state error: ${this.ws.readyState}`)); - } - - const method = params[1]; - this._debugLog(`[ReconnectionWebSocket] >---- call -----> "id":${this._cbId + 1}`, JSON.stringify(params)); - - this._cbId += 1; - - if ( - method === 'set_subscribe_callback' || - method === 'broadcast_transaction_with_callback' || - method === 'set_pending_transaction_callback' || - method === 'set_block_applied_callback' || - method === 'set_echorand_message_callback' || - method === 'subscribe_contract_logs' || - method === 'submit_registration_solution' || - method === 'get_contract_logs' - ) { - // Store callback in subs map - this._subs[this._cbId] = { - callback: params[2][0], - }; - - // Replace callback with the callback id - params[2][0] = this._cbId; - - if (method === 'get_contract_logs') { - this._cbLogs.push(this._cbId); - } - } - - if (method === 'unsubscribe_from_accounts') { - if (typeof params[2][0] !== 'function') { - throw new Error('First parameter of unsub must be the original callback'); - } - - const unSubCb = params[2].splice(0, 1)[0]; - - this._subs.forEach((id) => { - if (id.callback === unSubCb) { - this._unsub[this._cbId] = id; - } - }); - } - - const request = { - method: 'call', - params, - }; - request.id = this._cbId; - - return new Promise((resolve, reject) => { - - const timeoutId = setTimeout(() => { - reject(new Error(`RPC call time is over Id: ${request.id}`)); - - this._removePendingRequest(request.id); - }, timeout); - - this._cbs[this._cbId] = { - time: new Date(), - resolve, - reject, - timeoutId, - }; - - this.ws.send(JSON.stringify(request)); - }); - - } - - /** - * message handler - * @param response - */ - _responseHandler(response) { - this._debugLog('[ReconnectionWebSocket] <---- reply ----<', JSON.stringify(response)); - - let sub = false; - let callback = null; - - if (response.method === 'notice') { - sub = true; - response = { - ...response, - id: response.params[0], - }; - } - - if (!sub) { - callback = this._cbs[response.id]; - this._responseCbId = response.id; - } else if (this._subs[response.id].callback instanceof Array) { - [callback] = this._subs[response.id].callback; - } else if (typeof this._subs[response.id].callback === 'function') { - // eslint-disable-next-line prefer-destructuring - callback = this._subs[response.id].callback; - } - - if (callback && !sub) { - const { timeoutId } = callback; - if (timeoutId) clearTimeout(timeoutId); - if (response.error) { - callback.reject(response.error); - } else { - callback.resolve(response.result); - } - - this._removeSuccessfulRequest(response.id); - - } else if (callback && sub) { - callback(response.params[1]); - if (this._cbLogs.includes(response.id)) { - delete this._subs[response.id]; - const indexCb = this._cbLogs.indexOf(response.id); - this._cbLogs.splice(indexCb); - } - - } else { - this._debugLog('[ReconnectionWebSocket] >---- warning ----> Unknown websocket response', response); - } - } - - /** - * get access to chain - * @param {String} user - * @param {String} password - * @param {Number} timeout - timeout before reject - * @returns {Promise} - */ - login(user, password, timeout = this._options.pingTimeout) { - return this.call([1, 'login', [user, password]], timeout); - } - - /** - * update ping delay timeout - * @private - */ - _setPingDelay() { - this._clearPingDelay(); - this._pingDelayId = setTimeout(() => this._ping(), this._options.pingDelay); - } - - /** - * clear reconnection timeout - * @private - */ - _clearReconnectionTimeout() { - if (this._reconnectionTimeoutId) { - clearTimeout(this._reconnectionTimeoutId); - this._reconnectionTimeoutId = null; - } - } - - /** - * clear ping delay timeout - * @private - */ - _clearPingDelay() { - if (this._pingDelayId) { - clearTimeout(this._pingDelayId); - this._pingDelayId = null; - } - } - - /** - * clear waiting calls - * @private - */ - _clearWaitingCallPromises() { - const err = new Error(CONNECTION_CLOSED_ERROR_MESSAGE); - - for (let cbId = this._responseCbId + 1; cbId <= this._cbId; cbId += 1) { - if (this._cbs[cbId]) this._cbs[cbId].reject(err); - } - } - - /** - * reset calls id - * @private - */ - _resetId() { - this._cbId = 0; - } - - /** - * make call for check connection - * @private - */ - async _ping() { - try { - await this.login(); - } catch (_) { - if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return; - this._forceClose(); - } - } - - /** - * show debug logs - * @private - */ - _debugLog(...messages) { - if (!this._options.debug) return; - console.log(...messages); - } - - /** - * remove pending request from map - * @private - */ - _removePendingRequest(id) { - delete this._cbs[id]; - delete this._subs[id]; - delete this._unsub[id]; - } - - /** - * remove successful request from map - * @private - */ - _removeSuccessfulRequest(id) { - delete this._cbs[id]; - - if (this._unsub[id]) { - delete this._subs[this._unsub[id]]; - delete this._unsub[id]; - } - } - - _forceClose() { - - this._debugLog('[ReconnectionWebSocket] >---- _forceClose '); - - const { ws } = this; - this.ws = null; - - if (ws) { - ws.onopen = () => { }; - ws.onclose = () => { }; - ws.onerror = () => { }; - ws.onmessage = () => { }; - ws.close(); - } - - this._clearWaitingCallPromises(); - this._clearPingDelay(); - this._clearReconnectionTimeout(); - this._resetId(); - - if (this.onClose && this._currentRetry === 0) this.onClose(); - - this._debugLog('[ReconnectionWebSocket] >---- event -----> ONCLOSE'); - - if (this._forceClosePromise) { - this._forceClosePromise(); - this._forceClosePromise = null; - return true; - } - - if (this._currentRetry >= this._options.maxRetries) { - return true; - } - - this._reconnectionTimeoutId = setTimeout(async () => { - try { - await this._connect(); - } catch (_) { - // - } - }, this._options.connectionTimeout); - - return true; - } - /** - * - * @returns {Promise} - */ - close() { - if (!this.ws || this.ws.readyState === WebSocket.CLOSING || this.ws.readyState === WebSocket.CLOSED) { - return Promise.reject(new Error('Socket already close')); - } - - return new Promise((resolve) => { - this._forceClosePromise = resolve; - this._forceClose(); - }); - } - -} - -export default ReconnectionWebSocket; diff --git a/src/serializers/protocol/asset.js b/src/serializers/protocol/asset.js index b5623d20..296b6982 100644 --- a/src/serializers/protocol/asset.js +++ b/src/serializers/protocol/asset.js @@ -28,7 +28,7 @@ export const assetCreateOperationPropsSerializer = struct({ fee: asset, issuer: accountId, symbol: stringSerializer, - precision: uint32, + precision: uint8, common_options: assetOptionsSerializer, bitasset_options: optional(bitassetOptionsSerializer), extensions, diff --git a/test/api.test.js b/test/api.test.js index d2e32d89..833b85c8 100644 --- a/test/api.test.js +++ b/test/api.test.js @@ -11,7 +11,7 @@ import { url, accountId } from './_test-data'; import { deepStrictEqual } from 'assert'; import { shouldReject } from './_test-utils'; -describe('API', () => { +describe.only('API', () => { describe('API CONNECTION', () => { describe('when apis are provided', () => { const apis = [CHAIN_API.DATABASE_API, CHAIN_API.ASSET_API]; diff --git a/types/echo/echo-api.d.ts b/types/echo/echo-api.d.ts index 57ce96ec..6d1812ca 100644 --- a/types/echo/echo-api.d.ts +++ b/types/echo/echo-api.d.ts @@ -1,6 +1,7 @@ import { HttpProvider, WsProvider } from "./providers"; export default class EchoApi { + public readonly apiId: number | null; public readonly apiName: string; public readonly provider: HttpProvider | WsProvider; constructor(provider: HttpProvider | WsProvider, apiName: string); diff --git a/types/echo/engine.d.ts b/types/echo/engine.d.ts index 3abb9281..43f6522f 100644 --- a/types/echo/engine.d.ts +++ b/types/echo/engine.d.ts @@ -6,6 +6,6 @@ export default class EchoApiEngine { public readonly availableApis: readonly ChainApi[]; public readonly api: Readonly<{ [apiName in ChainApi]: EchoApi }>; public readonly provider: HttpProvider | WsProvider; - constructor(apis: readonly ChainApi[]); + constructor(apis: readonly ChainApi[], provider: HttpProvider | WsProvider); public init(): Promise; } From 1b73c8345e4e494d1db07c71948f33d5d6973d22 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Fri, 10 Apr 2020 18:05:11 +0300 Subject: [PATCH 49/62] [ECHOJS-250] Done --- src/echo/api.js | 7 ++++--- src/echo/apis/asset-api.js | 24 +++++++++++++++--------- src/echo/apis/base-api.js | 6 ++++-- src/echo/apis/database-api.js | 4 ++-- src/echo/apis/echorand-api.js | 21 ++++++++++++++------- src/echo/apis/history-api.js | 24 +++++++++++++++--------- src/echo/apis/login-api.js | 14 +++++++++++--- src/echo/apis/network-api.js | 26 ++++++++++++++++---------- src/echo/apis/network-node-api.js | 22 ++++++++++++++-------- src/echo/apis/registration-api.js | 25 +++++++++++++++---------- src/echo/index.js | 16 ++++++++-------- 11 files changed, 118 insertions(+), 71 deletions(-) diff --git a/src/echo/api.js b/src/echo/api.js index 7905a2b8..6bd50d49 100644 --- a/src/echo/api.js +++ b/src/echo/api.js @@ -40,6 +40,7 @@ import { solveRegistrationTask, validateRegistrationOptions } from '../utils/pow import { ECHO_ASSET_ID, DYNAMIC_GLOBAL_OBJECT_ID, API_CONFIG, CACHE_MAPS } from '../constants'; import { transaction, signedTransaction, operation, basic } from '../serializers'; import { PublicKey } from '../crypto'; +import { CHAIN_API } from '../constants/ws-constants'; /** @typedef {import("./ws-api/database-api").SidechainType} SidechainType */ @@ -2130,7 +2131,7 @@ class API { broadcastTransactionWithCallback(signedTransactionObject, wasBroadcastedCallback) { return new Promise(async (resolve, reject) => { try { - await this.engine.network.broadcastTransactionWithCallback( + await this.engine[CHAIN_API.NETWORK_BROADCAST_API].broadcastTransactionWithCallback( (res) => resolve(res), signedTransactionObject, ); @@ -2366,7 +2367,7 @@ class API { return Promise.reject(new Error('Invalid transaction')); } - return this.engine.network.broadcastTransaction(tr); + return this.engine[CHAIN_API.NETWORK_BROADCAST_API].broadcastTransaction(tr); } /** @@ -2396,7 +2397,7 @@ class API { return Promise.reject(new Error('Invalid block')); } - return this.engine.network.broadcastBlock(block); + return this.engine[CHAIN_API.NETWORK_BROADCAST_API].broadcastBlock(block); } /** diff --git a/src/echo/apis/asset-api.js b/src/echo/apis/asset-api.js index 2c2b7d74..bd6dde33 100644 --- a/src/echo/apis/asset-api.js +++ b/src/echo/apis/asset-api.js @@ -1,12 +1,18 @@ -class AssetAPI { +import { CHAIN_API } from '../../constants/ws-constants'; +import BaseEchoApi from './base-api'; + +/** @typedef {import("../providers").WsProvider} WsProvider */ +/** @typedef {import("../providers").HttpProvider} HttpProvider */ +/** @typedef {"" | "eth" | "btc"} SidechainType */ + +class AssetAPI extends BaseEchoApi { /** - * @constructor - * - * @param {EchoApi} db [asset api] + * @constructor + * @param {WsProvider | HttpProvider} provider */ - constructor(db) { - this.db = db; + constructor(provider) { + super(provider, CHAIN_API.ASSET_API); } /** @@ -21,7 +27,7 @@ class AssetAPI { * [ { name: 'init0', account_id: '1.2.6', amount: '100000039900000' } ] */ getAssetHolders(assetId, start, limit) { - return this.db.exec('get_asset_holders', [assetId, start, limit]); + return this.exec('get_asset_holders', [assetId, start, limit]); } /** @@ -33,7 +39,7 @@ class AssetAPI { * @return {Promise.} result - 8 */ getAssetHoldersCount(assetId) { - return this.db.exec('get_asset_holders_count', [assetId]); + return this.exec('get_asset_holders_count', [assetId]); } /** @@ -44,7 +50,7 @@ class AssetAPI { * [ { asset_id: '1.3.0', count: 8 } ] */ getAllAssetHolders() { - return this.db.exec('get_all_asset_holders', []); + return this.exec('get_all_asset_holders', []); } } diff --git a/src/echo/apis/base-api.js b/src/echo/apis/base-api.js index 6d9493cb..e0348c6c 100644 --- a/src/echo/apis/base-api.js +++ b/src/echo/apis/base-api.js @@ -1,4 +1,5 @@ import { ConnectionType } from '../providers'; +import { CHAIN_API } from '../../constants/ws-constants'; /** @typedef {import("../providers").WSProvider} WSProvider */ /** @typedef {import("../providers").HttpProvider} HttpProvider */ @@ -22,7 +23,8 @@ export default class BaseEchoApi { */ async init() { if (this.provider.connectionType === ConnectionType.WS) { - this.apiId = await this.provider.call(1, this.apiName, []); + if (this.apiName === CHAIN_API.LOGIN_API) this.apiId = 1; + else this.apiId = await this.provider.call([1, this.apiName, []]); } else this.apiId = 0; return this; } @@ -42,7 +44,7 @@ export default class BaseEchoApi { return Promise.reject(new Error(errMessage)); } if (this.provider.connectionType === ConnectionType.HTTP) return this.provider.call(method, params); - return this.provider.call(this.apiId, method, params); + return this.provider.call([this.apiId, method, params]); } } diff --git a/src/echo/apis/database-api.js b/src/echo/apis/database-api.js index 5b559512..854bf1ee 100644 --- a/src/echo/apis/database-api.js +++ b/src/echo/apis/database-api.js @@ -1,7 +1,7 @@ import { CHAIN_API } from '../../constants/ws-constants'; import BaseEchoApi from './base-api'; -/** @typedef {import("../providers").WSProvider} WSProvider */ +/** @typedef {import("../providers").WsProvider} WsProvider */ /** @typedef {import("../providers").HttpProvider} HttpProvider */ /** @typedef {"" | "eth" | "btc"} SidechainType */ @@ -9,7 +9,7 @@ class DatabaseAPI extends BaseEchoApi { /** * @constructor - * @param {} provider + * @param {WsProvider | HttpProvider} provider */ constructor(provider) { super(provider, CHAIN_API.DATABASE_API); diff --git a/src/echo/apis/echorand-api.js b/src/echo/apis/echorand-api.js index ec0cc221..743996e7 100644 --- a/src/echo/apis/echorand-api.js +++ b/src/echo/apis/echorand-api.js @@ -1,11 +1,18 @@ -class EchorandAPI { +import { CHAIN_API } from '../../constants/ws-constants'; +import BaseEchoApi from './base-api'; + +/** @typedef {import("../providers").WsProvider} WsProvider */ +/** @typedef {import("../providers").HttpProvider} HttpProvider */ +/** @typedef {"" | "eth" | "btc"} SidechainType */ + +class EchorandAPI extends BaseEchoApi { /** - * @constructor - * @param {EchoApi} db [history api] - */ - constructor(db) { - this.db = db; + * @constructor + * @param {WsProvider | HttpProvider} provider + */ + constructor(provider) { + super(provider, CHAIN_API.ECHORAND_API); } /** @@ -16,7 +23,7 @@ class EchorandAPI { * @return {Promise.} */ setEchorandMessageCallback(callback) { - return this.db.exec('set_echorand_message_callback', [callback]); + return this.exec('set_echorand_message_callback', [callback]); } } diff --git a/src/echo/apis/history-api.js b/src/echo/apis/history-api.js index 865d1821..ccf3e35e 100644 --- a/src/echo/apis/history-api.js +++ b/src/echo/apis/history-api.js @@ -1,13 +1,19 @@ import { START_OPERATION_ID } from '../../constants'; +import { CHAIN_API } from '../../constants/ws-constants'; +import BaseEchoApi from './base-api'; -class HistoryAPI { +/** @typedef {import("../providers").WsProvider} WsProvider */ +/** @typedef {import("../providers").HttpProvider} HttpProvider */ +/** @typedef {"" | "eth" | "btc"} SidechainType */ + +class HistoryAPI extends BaseEchoApi { /** - * @constructor - * @param {EchoApi} db [history api] + * @constructor + * @param {WsProvider | HttpProvider} provider */ - constructor(db) { - this.db = db; + constructor(provider) { + super(provider, CHAIN_API.HISTORY_API); } /** @@ -22,7 +28,7 @@ class HistoryAPI { * @return {Promise} */ getAccountHistory(accountId, stop = START_OPERATION_ID, limit = 100, start = START_OPERATION_ID) { - return this.db.exec('get_account_history', [accountId, stop, limit, start]); + return this.exec('get_account_history', [accountId, stop, limit, start]); } /** @@ -38,7 +44,7 @@ class HistoryAPI { * @return {Promise} */ getRelativeAccountHistory(accountId, stop = 0, limit = 100, start = 0) { - return this.db.exec('get_relative_account_history', [accountId, stop, limit, start]); + return this.exec('get_relative_account_history', [accountId, stop, limit, start]); } /** @@ -57,7 +63,7 @@ class HistoryAPI { accountId, operationId, start = START_OPERATION_ID, stop = START_OPERATION_ID, limit = 100, ) { - return this.db.exec('get_account_history_operations', [accountId, operationId, start, stop, limit]); + return this.exec('get_account_history_operations', [accountId, operationId, start, stop, limit]); } /** @@ -75,7 +81,7 @@ class HistoryAPI { contractId, stop = START_OPERATION_ID, limit = 100, start = START_OPERATION_ID, ) { - return this.db.exec('get_contract_history', [contractId, stop, limit, start]); + return this.exec('get_contract_history', [contractId, stop, limit, start]); } } diff --git a/src/echo/apis/login-api.js b/src/echo/apis/login-api.js index eab741f3..4ccb72ca 100644 --- a/src/echo/apis/login-api.js +++ b/src/echo/apis/login-api.js @@ -1,7 +1,15 @@ -class LoginAPI { +import { CHAIN_API } from '../../constants/ws-constants'; +import BaseEchoApi from './base-api'; - constructor(login) { - this.login = login; +/** @typedef {import("../providers").WsProvider} WsProvider */ +/** @typedef {import("../providers").HttpProvider} HttpProvider */ +/** @typedef {"" | "eth" | "btc"} SidechainType */ + +class LoginAPI extends BaseEchoApi { + + /** @param {WsProvider | HttpProvider} provider */ + constructor(provider) { + super(provider, CHAIN_API.LOGIN_API); } } diff --git a/src/echo/apis/network-api.js b/src/echo/apis/network-api.js index c192f694..20d04beb 100644 --- a/src/echo/apis/network-api.js +++ b/src/echo/apis/network-api.js @@ -1,12 +1,18 @@ -class NetworkAPI { +import { CHAIN_API } from '../../constants/ws-constants'; +import BaseEchoApi from './base-api'; + +/** @typedef {import("../providers").WsProvider} WsProvider */ +/** @typedef {import("../providers").HttpProvider} HttpProvider */ +/** @typedef {"" | "eth" | "btc"} SidechainType */ + +class NetworkAPI extends BaseEchoApi { /** - * @constructor - * - * @param {EchoApi} db [network api] + * @constructor + * @param {WsProvider | HttpProvider} provider */ - constructor(db) { - this.db = db; + constructor(provider) { + super(provider, CHAIN_API.NETWORK_BROADCAST_API); } /** @@ -24,7 +30,7 @@ class NetworkAPI { * @return {Promise} */ broadcastTransaction(signedTransaction) { - return this.db.exec('broadcast_transaction', [signedTransaction]); + return this.exec('broadcast_transaction', [signedTransaction]); } /** @@ -48,7 +54,7 @@ class NetworkAPI { * @return {Promise} */ broadcastBlock(signedBlock) { - return this.db.exec('broadcast_block', [signedBlock]); + return this.exec('broadcast_block', [signedBlock]); } /** @@ -66,7 +72,7 @@ class NetworkAPI { * @return {Promise} */ broadcastTransactionSynchronous(signedTransaction) { - return this.db.exec('broadcast_transaction_synchronous', [signedTransaction]); + return this.exec('broadcast_transaction_synchronous', [signedTransaction]); } /** @@ -86,7 +92,7 @@ class NetworkAPI { * @return {Promise} */ broadcastTransactionWithCallback(callback, signedTransaction) { - return this.db.exec('broadcast_transaction_with_callback', [callback, signedTransaction]); + return this.exec('broadcast_transaction_with_callback', [callback, signedTransaction]); } } diff --git a/src/echo/apis/network-node-api.js b/src/echo/apis/network-node-api.js index c4c43576..cf8b6622 100644 --- a/src/echo/apis/network-node-api.js +++ b/src/echo/apis/network-node-api.js @@ -1,3 +1,10 @@ +import { CHAIN_API } from '../../constants/ws-constants'; +import BaseEchoApi from './base-api'; + +/** @typedef {import("../providers").WsProvider} WsProvider */ +/** @typedef {import("../providers").HttpProvider} HttpProvider */ +/** @typedef {"" | "eth" | "btc"} SidechainType */ + /** @typedef { import("../../constants/net/peer-database").e_POTENTIAL_PEER_LAST_CONNECTION_DISPOSITION } e_POTENTIAL_PEER_LAST_CONNECTION_DISPOSITION */ @@ -41,28 +48,27 @@ * @property {unknown} [last_error] */ -class NetworkNodeAPI { +class NetworkNodeAPI extends BaseEchoApi { /** - * @constructor - * - * @param {EchoApi} db [network node api] + * @constructor + * @param {WsProvider | HttpProvider} provider */ - constructor(db) { - this.db = db; + constructor(provider) { + super(provider, CHAIN_API.NETWORK_NODE_API); } /** * @method getConnectedPeers * @return {Promise>} */ - getConnectedPeers() { return this.db.exec('get_connected_peers', []); } + getConnectedPeers() { return this.exec('get_connected_peers', []); } /** * @method getPotentialPeers * @return {Promise} */ - getPotentialPeers() { return this.db.exec('get_potential_peers', []); } + getPotentialPeers() { return this.exec('get_potential_peers', []); } } diff --git a/src/echo/apis/registration-api.js b/src/echo/apis/registration-api.js index dc341974..71b707de 100644 --- a/src/echo/apis/registration-api.js +++ b/src/echo/apis/registration-api.js @@ -1,13 +1,18 @@ -/* eslint-disable max-len */ -class RegistrationAPI { +import { CHAIN_API } from '../../constants/ws-constants'; +import BaseEchoApi from './base-api'; + +/** @typedef {import("../providers").WsProvider} WsProvider */ +/** @typedef {import("../providers").HttpProvider} HttpProvider */ +/** @typedef {"" | "eth" | "btc"} SidechainType */ + +class RegistrationAPI extends BaseEchoApi { /** - * @constructor - * - * @param {EchoApi} db [register api] + * @constructor + * @param {WsProvider | HttpProvider} provider */ - constructor(db) { - this.db = db; + constructor(provider) { + super(provider, CHAIN_API.REGISTRATION_API); } /** @@ -16,7 +21,7 @@ class RegistrationAPI { * @return {Promise.<{block_id: String, rand_num: string, difficulty: number}>} */ requestRegistrationTask() { - return this.db.exec('request_registration_task', []); + return this.exec('request_registration_task', []); } /** @@ -33,7 +38,7 @@ class RegistrationAPI { * @return {Promise} */ submitRegistrationSolution(callback, name, activeKey, echorandKey, evmAddress, nonce, randNum) { - return this.db.exec('submit_registration_solution', [ + return this.exec('submit_registration_solution', [ callback, name, activeKey, @@ -50,7 +55,7 @@ class RegistrationAPI { * @return {Promise} */ getRegistrar() { - return this.db.exec('get_registrar', []); + return this.exec('get_registrar', []); } } diff --git a/src/echo/index.js b/src/echo/index.js index e24cebc4..3207d040 100644 --- a/src/echo/index.js +++ b/src/echo/index.js @@ -1,6 +1,6 @@ import Cache from './cache'; import API from './api'; -import Subscriber from './subscriber'; +// import Subscriber from './subscriber'; import Transaction from './transaction'; import { STATUS, DEFAULT_CHAIN_APIS } from '../constants/ws-constants'; import { WalletApi } from './apis'; @@ -31,7 +31,7 @@ class Echo { * @readonly * @type {Set} */ - get apis() { return new Set(this._ws.apis); } + get apis() { return new Set(this.engine.apis); } /** * @param {string} address @@ -51,8 +51,8 @@ class Echo { } this.cache.setOptions(options); - this.subscriber = new Subscriber(this.engine); - this.subscriber.setOptions(options); + // this.subscriber = new Subscriber(this.engine); + // this.subscriber.setOptions(options); } /** @@ -97,13 +97,13 @@ class Echo { } async disconnect() { - this.subscriber.callCbOnDisconnect(); - this.subscriber.reset(); + // this.subscriber.callCbOnDisconnect(); + // this.subscriber.reset(); this.cache.reset(); - await this._ws.close(); + if (this.engine.provider.connectionType === ConnectionType.WS) await this.engine.provider.close(); this.onOpen = null; this._isInitModules = false; - this._ws.removeListener(STATUS.OPEN, this.initEchoApi); + // this._ws.removeListener(STATUS.OPEN, this.initEchoApi); } /** @returns {Transaction} */ From 7714390cc334a4ad497bd4be4ebc249c13188234 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Fri, 10 Apr 2020 18:06:21 +0300 Subject: [PATCH 50/62] [ECHOJS-248] WIP --- test/api.test.js | 142 ++++++++++++++++---------------- test/main.test.js | 16 ++-- test/preparation/preparation.js | 2 +- 3 files changed, 81 insertions(+), 79 deletions(-) diff --git a/test/api.test.js b/test/api.test.js index 833b85c8..856daeab 100644 --- a/test/api.test.js +++ b/test/api.test.js @@ -1,6 +1,4 @@ import { expect } from 'chai'; -import WS from '../src/echo/ws'; -import WSAPI from '../src/echo/ws-api'; import Cache from '../src/echo/cache'; import API from '../src/echo/api'; @@ -10,6 +8,8 @@ import { DEFAULT_CHAIN_APIS, CHAIN_API } from '../src/constants/ws-constants'; import { url, accountId } from './_test-data'; import { deepStrictEqual } from 'assert'; import { shouldReject } from './_test-utils'; +import { WsProvider } from '../src/echo/providers'; +import EchoApiEngine from '../src/echo/engine'; describe.only('API', () => { describe('API CONNECTION', () => { @@ -164,7 +164,7 @@ describe.only('API', () => { }); describe('database', () => { - const ws = new WS(); + const wsProvider = new WsProvider(); beforeEach(async () => { await ws.connect(url, { debug: false, @@ -179,9 +179,9 @@ describe.only('API', () => { describe('#getChainProperties()', () => { it('should get chain properties', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const chainProperties = await api.getChainProperties(); @@ -202,9 +202,9 @@ describe.only('API', () => { describe('#getGlobalProperties()', () => { it('should get global properties', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const globalProperties = await api.getGlobalProperties(); @@ -225,9 +225,9 @@ describe.only('API', () => { describe('#getConfig()', () => { it('should get config properties', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const config = await api.getConfig(); @@ -248,9 +248,9 @@ describe.only('API', () => { describe('#getChainId()', () => { it('should get chain id', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const chainId = await api.getChainId(); expect(chainId) @@ -266,9 +266,9 @@ describe.only('API', () => { describe('#getDynamicGlobalProperties()', () => { it('should get dynamic global properties', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const dynamicGlobalProperties = await api.getDynamicGlobalProperties(); @@ -291,9 +291,9 @@ describe.only('API', () => { describe('#getBlock()', () => { it('should get block and save it to cache', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const blockNumber = 2; const block = await api.getBlock(blockNumber); @@ -311,9 +311,9 @@ describe.only('API', () => { describe.skip('#getTransaction()', () => { it('should get transaction and save it to cache', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const blockNumber = 205378; const transactionIndex = 0; const transaction = await api.getTransaction(blockNumber, transactionIndex); @@ -332,9 +332,9 @@ describe.only('API', () => { describe('#getAccounts()', () => { it('should get accounts and save it to cache', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const accountId1 = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ACCOUNT}.5`; const accountId2 = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ACCOUNT}.6`; const accounts = await api.getAccounts([accountId1, accountId2]); @@ -373,9 +373,9 @@ describe.only('API', () => { describe('#getFullAccounts()', () => { it('should get accounts and save it to cache', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const accountId1 = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ACCOUNT}.5`; const accountId2 = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ACCOUNT}.6`; @@ -422,9 +422,9 @@ describe.only('API', () => { describe('#getAccountCount()', () => { it('should get account count', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const accountCount = await api.getAccountCount(); @@ -441,9 +441,9 @@ describe.only('API', () => { describe('#lookupAssetSymbols()', () => { it('should get asset by symbol and save it in multi caches', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const assetKey = 'ECHO'; const assetId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ASSET}.0`; @@ -478,9 +478,9 @@ describe.only('API', () => { describe('#getAssets()', () => { it('should get assets by id and save it in multi caches', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const assetId1 = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ASSET}.0`; @@ -509,9 +509,9 @@ describe.only('API', () => { describe('#getObjects()', () => { it('should get objects by id and save it in multi caches', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const accountId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ACCOUNT}.2`; const assetId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ASSET}.0`; @@ -563,9 +563,9 @@ describe.only('API', () => { describe('#getObjects()', () => { it('should get objects by id and save it in multi caches', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const accountId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ACCOUNT}.2`; const assetId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ASSET}.0`; @@ -617,9 +617,9 @@ describe.only('API', () => { describe('#getCommitteeMembers()', () => { it('should get committee member by id and save it in multi caches', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const committeeMember = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.COMMITTEE_MEMBER}.1`; @@ -648,9 +648,9 @@ describe.only('API', () => { describe('#getAccountByName()', () => { it('should get account by name and save it in multi caches', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const accountName = 'relaxed-committee-account'; @@ -682,9 +682,9 @@ describe.only('API', () => { describe('#lookupAccounts()', () => { it('should get account by name and limit', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const lowerBoundName = 't'; @@ -702,9 +702,9 @@ describe.only('API', () => { describe('#listAssets()', () => { it('should get assets by name and limit', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const lowerBoundSymbol = 'E'; @@ -722,9 +722,9 @@ describe.only('API', () => { describe('#getBlockHeader()', () => { it('should get block header by block number', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const blockNumber = 2; const blockHeader = await api.getBlockHeader(blockNumber); @@ -743,9 +743,9 @@ describe.only('API', () => { describe.skip('#getFullContract()', () => { it('should get contract', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const contractId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.CONTRACT}.0`; const contract = await api.getFullContract(contractId); @@ -764,9 +764,9 @@ describe.only('API', () => { describe.skip('#getContracts()', () => { it('should get contracts', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const contractId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.CONTRACT}.0`; const contracts = await api.getContracts([contractId]); @@ -784,9 +784,9 @@ describe.only('API', () => { describe('#requestRegistrationTask', () => { it('should get registration task', async() => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const task = await api.requestRegistrationTask(); @@ -803,9 +803,9 @@ describe.only('API', () => { describe('#getCommitteeMembers()', () => { it('should get committee by id and save to cache', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const id = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.COMMITTEE_MEMBER}.1`; @@ -848,9 +848,9 @@ describe.only('API', () => { describe('#getCommitteeMemberByAccount()', () => { it('should get committee by account id and save to cache', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const accountId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ACCOUNT}.6`; @@ -893,9 +893,9 @@ describe.only('API', () => { describe('#getCommitteeFrozenBalance()', () =>{ it('should get committee frozen balance by committee member id', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const committeeMemberId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.COMMITTEE_MEMBER}.1`; @@ -925,9 +925,9 @@ describe.only('API', () => { describe('#getBtcAddress()', () => { it('should get btc address by account id', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const accountId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ACCOUNT}.6`; @@ -951,9 +951,9 @@ describe.only('API', () => { describe.skip('#getBtcDepositScript()', () => { it('should get null because script with this deposit id does not exist', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const btcAddressId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.BTC_ADDRESS}.1`; @@ -972,19 +972,21 @@ describe.only('API', () => { }); describe('history', () => { - const ws = new WS(); + const wsProvider = new WsProvider(); beforeEach(async () => { - await ws.connect(url, { apis: ['database', 'network_broadcast', 'history', 'registration', 'asset', 'login'] }); + await wsProvider.connect(url, { + apis: ['database', 'network_broadcast', 'history', 'registration', 'asset', 'login'], + }); }); afterEach(async () => { - await ws.close(); + await wsProvider.close(); }); describe('#getAccountHistory()', () => { it('should get account history', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const accountId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ACCOUNT}.2`; @@ -1002,9 +1004,9 @@ describe.only('API', () => { describe('#getRelativeAccountHistory()', () => { it('should get relative account history', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const accountId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ACCOUNT}.0`; const start = 0; @@ -1025,9 +1027,9 @@ describe.only('API', () => { describe('#getAccountHistoryOperations()', () => { it('should get account history operations', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const accountId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ACCOUNT}.0`; const operationId = 0; @@ -1049,9 +1051,9 @@ describe.only('API', () => { describe.skip('#getContractHistory()', () => { it('should get contract history', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const contractId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.CONTRACT}.1`; const start = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.OPERATION_HISTORY}.0`; @@ -1072,9 +1074,9 @@ describe.only('API', () => { describe('#getRegistrar()', () => { it('should get registrarId', async () => { try { - const wsApi = new WSAPI(ws); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); const cache = new Cache(); - const api = new API(cache, wsApi); + const api = new API(cache, engine); const registrar = await api.getRegistrar(); expect(registrar) diff --git a/test/main.test.js b/test/main.test.js index 36d6e64f..1c23968e 100644 --- a/test/main.test.js +++ b/test/main.test.js @@ -1,12 +1,12 @@ import "@babel/polyfill"; -import { expect } from 'chai'; -import WS from '../src/echo/ws' -import WSAPI from '../src/echo/ws-api' -import Cache from '../src/echo/cache' -import API from '../src/echo/api' - -import { url } from './_test-data'; -import { ACCOUNT, ASSET, } from '../src/constants/object-types'; +// import { expect } from 'chai'; +// import WS from '../src/echo/ws' +// import WSAPI from '../src/echo/ws-api' +// import Cache from '../src/echo/cache' +// import API from '../src/echo/api' + +// import { url } from './_test-data'; +// import { ACCOUNT, ASSET, } from '../src/constants/object-types'; // describe('API', () => { // const ws = new WS(); diff --git a/test/preparation/preparation.js b/test/preparation/preparation.js index 3f043ca0..3837e929 100644 --- a/test/preparation/preparation.js +++ b/test/preparation/preparation.js @@ -7,7 +7,7 @@ const prepare = async () => { maxRetries: 5, pingTimeout: 3000, pingDelay: 10000, - debug: false, + debug: true, apis: constants.WS_CONSTANTS.CHAIN_APIS, }); const balanceObject = await echo.api.getObject(`1.${constants.PROTOCOL_OBJECT_TYPE_ID.BALANCE}.0`); From ca54bb270ae932f9f4dbe140fdfc7939fb7f36d8 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 13 Apr 2020 15:44:04 +0300 Subject: [PATCH 51/62] [ECHOJS-250] [ECHOJS-251] Done --- src/echo/api.js | 14 +- src/echo/index.js | 52 +- src/echo/providers/WsProvider.js | 515 +++---------------- src/echo/providers/reconnection-websocket.js | 489 ++++++++++++++++++ src/echo/subscriber.js | 34 +- src/echo/ws/index.js | 244 --------- test/api.test.js | 50 +- test/subscriber.test.js | 2 +- 8 files changed, 675 insertions(+), 725 deletions(-) create mode 100644 src/echo/providers/reconnection-websocket.js delete mode 100644 src/echo/ws/index.js diff --git a/src/echo/api.js b/src/echo/api.js index 6bd50d49..506cbcaf 100644 --- a/src/echo/api.js +++ b/src/echo/api.js @@ -2639,18 +2639,8 @@ class API { return this.engine.registration.getRegistrar(); } - /** - * @method getConnectedPeers - * @return {ReturnType} - */ - getConnectedPeers() { return this.engine.networkNode.getConnectedPeers(); } - - /** - * @method getPotentialPeers - * @return {Promise} - */ - getPotentialPeers() { return this.engine.networkNode.getPotentialPeers(); } - + getConnectedPeers() { return this.engine[CHAIN_API.NETWORK_NODE_API].getConnectedPeers(); } + getPotentialPeers() { return this.engine[CHAIN_API.NETWORK_NODE_API].getPotentialPeers(); } setOptions() { } } diff --git a/src/echo/index.js b/src/echo/index.js index 3207d040..f93b64a4 100644 --- a/src/echo/index.js +++ b/src/echo/index.js @@ -1,11 +1,13 @@ +/* global window */ import Cache from './cache'; import API from './api'; -// import Subscriber from './subscriber'; +import Subscriber from './subscriber'; import Transaction from './transaction'; import { STATUS, DEFAULT_CHAIN_APIS } from '../constants/ws-constants'; import { WalletApi } from './apis'; import EchoApiEngine from './engine'; import { ConnectionType, WsProvider, HttpProvider } from './providers'; +import { validateUrl, validateOptionsError } from '../utils/validators'; /** @typedef {{ batch?: number, timeout?: number }} RegistrationOptions */ @@ -19,6 +21,7 @@ class Echo { this._isInitModules = false; this.initEchoApi = this.initEchoApi.bind(this); this.walletApi = new WalletApi(); + this.subscriber = new Subscriber(); } get isConnected() { @@ -39,11 +42,23 @@ class Echo { * @private */ async _connectToNode(address, options) { + if (!validateUrl(address)) throw new Error(`Invalid address ${address}`); + if ( + typeof window !== 'undefined' && + window.location && + window.location.protocol === 'https:' && + !address.startsWith('wss://') && + !address.startsWith('https://') + ) { + throw new Error('Secure domains require wss/https connection'); + } + const optionError = validateOptionsError(options); + if (optionError) throw new Error(optionError); const provider = address.startsWith('ws') ? new WsProvider() : new HttpProvider(address); if (provider.connectionType === ConnectionType.WS) await provider.connect(address, options); this.engine = new EchoApiEngine(options.apis || DEFAULT_CHAIN_APIS, provider); if (this._isInitModules) return; - + this.subscriber.setOptions(options); await this._initModules(options); if (!options.store && this.store) { @@ -51,8 +66,6 @@ class Echo { } this.cache.setOptions(options); - // this.subscriber = new Subscriber(this.engine); - // this.subscriber.setOptions(options); } /** @@ -73,14 +86,17 @@ class Echo { this.cache = new Cache(options.cache); this.api = new API(this.cache, this.engine, options.registration); - await this.engine.init(); - // await this.subscriber.init(this.cache, this.engine, this.api); - // this._ws.on(STATUS.OPEN, this.initEchoApi); + await this.initEchoApi(); + if (this.engine.provider.connectionType === ConnectionType.WS) { + this.engine.provider.on(STATUS.OPEN, this.initEchoApi); + } } async initEchoApi() { - await this._ws.initEchoApi(); - // await this.subscriber.init(this.cache, this.engine, this.api); + await this.engine.init(); + if (this.engine.provider.connectionType === ConnectionType.WS) { + await this.subscriber.init(this.cache, this.engine, this.api); + } } syncCacheWithStore(store) { @@ -91,19 +107,27 @@ class Echo { } async reconnect() { - this._ws.removeListener(STATUS.OPEN, this.initEchoApi); - await this._ws.reconnect(); + if (this.engine === null) throw new Error('Not connected'); + if (this.engine.provider.connectionType === ConnectionType.HTTP) return; + this.engine.provider.removeListener(STATUS.OPEN, this.initEchoApi); + await this.engine.provider.reconnect(); await this.initEchoApi(); + this.engine.provider.on(STATUS.OPEN, this.initEchoApi); } async disconnect() { - // this.subscriber.callCbOnDisconnect(); - // this.subscriber.reset(); + if (this.engine === null) throw new Error('Not connected'); + if (this.engine.provider.connectionType === ConnectionType.WS) { + this.subscriber.callCbOnDisconnect(); + this.subscriber.reset(); + } this.cache.reset(); if (this.engine.provider.connectionType === ConnectionType.WS) await this.engine.provider.close(); this.onOpen = null; this._isInitModules = false; - // this._ws.removeListener(STATUS.OPEN, this.initEchoApi); + if (this.engine.provider.connectionType === ConnectionType.WS) { + this.engine.provider.removeListener(STATUS.OPEN, this.initEchoApi); + } } /** @returns {Transaction} */ diff --git a/src/echo/providers/WsProvider.js b/src/echo/providers/WsProvider.js index cfc0960d..b8307a60 100644 --- a/src/echo/providers/WsProvider.js +++ b/src/echo/providers/WsProvider.js @@ -1,491 +1,140 @@ -import WebSocket from 'isomorphic-ws'; - -import { - CONNECTION_TIMEOUT, - MAX_RETRIES, - PING_TIMEOUT, - PING_DELAY, - DEBUG, - CONNECTION_CLOSED_ERROR_MESSAGE, -} from '../../constants/ws-constants'; - -import { isVoid } from '../../utils/validators'; +import { EventEmitter } from 'events'; import * as ConnectionType from './connection-types'; +import ReconnectionWebSocket from './reconnection-websocket'; +import { DEFAULT_CHAIN_APIS, STATUS } from '../../constants/ws-constants'; -export default class WsProvider { +export default class WsProvider extends EventEmitter { - get connected() { return this.ws && this.ws.readyState === WebSocket.OPEN; } + get connected() { return this._ws_rpc.connected; } get connectionType() { return ConnectionType.WS; } constructor() { - this.onOpen = null; - this.onClose = null; - this.onError = null; - - this._currentRetry = 0; - this._pingDelayId = null; - this._options = {}; - - this._cbId = 0; - this._responseCbId = 0; - this._cbs = {}; - this._subs = []; - this._unsub = {}; - } - - /** - * init params and connect to chain - * - * @param {string} url remote node address, - * should be (http|https|ws|wws)://(domain|ipv4|ipv6):port(?)/resource(?)?param=param(?). - * - * @param {Object} options connection params. - * - * @param {number} options.connectionTimeout - * delay in ms between reconnection requests, default call delay before reject it. - * - * @param {number} options.maxRetries - max count retries before close socket. - * @param {number} options.pingTimeout - delay time in ms between ping request and socket disconnect. - * @param {number} options.pingDelay - delay between last recived message and start checking connection. - * @param {boolean} options.debug - debug mode status. - * @returns {Promise} - */ - async connect(url, options = {}) { - if (this.connected) await this.close(); - this._options = { - connectionTimeout: isVoid(options.connectionTimeout) ? CONNECTION_TIMEOUT : options.connectionTimeout, - maxRetries: isVoid(options.maxRetries) ? MAX_RETRIES : options.maxRetries, - pingTimeout: isVoid(options.pingTimeout) ? PING_TIMEOUT : options.pingTimeout, - pingDelay: isVoid(options.pingDelay) ? PING_DELAY : options.pingDelay, - debug: isVoid(options.debug) ? DEBUG : options.debug, - }; + super(); - this.url = url; - this._isFirstConnection = true; - this._currentRetry = 0; - this._forceClosePromise = null; - this._reconnectionTimeoutId = null; + this._ws_rpc = new ReconnectionWebSocket(); - this._cbId = 0; - this._responseCbId = 0; - this._cbs = {}; - this._cbLogs = []; - this._subs = []; - this._unsub = {}; + this._connected = false; + this._isFirstTime = true; - return this._connect(); + this.onOpenCb = null; + this.onCloseCb = null; + this.onErrorCb = null; } /** - * inner connection method - * @returns {Promise} + * On open callback */ - _connect() { - - this._debugLog('[ReconnectionWebSocket] >---- retry _connect'); - - this._currentRetry += 1; - return new Promise((resolve, reject) => { - let ws = null; - try { - ws = new WebSocket(this.url); - } catch (error) { - ws = null; - if (this._isFirstConnection) { - this._isFirstConnection = false; - return reject(error); - } - } - - ws.onopen = () => { - - this._currentRetry = 0; - - if (this._isFirstConnection) { - this._isFirstConnection = false; - resolve(); - } - - if (this.onOpen) this.onOpen(); - - this._setPingDelay(); - - this._debugLog('[ReconnectionWebSocket] >---- event -----> ONOPEN'); - return true; - }; - - ws.onmessage = (message) => { - - if (ws !== this.ws) { - return false; - } - - this._responseHandler(JSON.parse(message.data)); - - this._debugLog('[ReconnectionWebSocket] >---- event -----> ONMESSAGE'); - - this._setPingDelay(); - - return true; - }; - - ws.onclose = () => { - - if (ws !== this.ws) { - return false; - } - - if (this._isFirstConnection) { - this._isFirstConnection = false; - reject(new Error('Could\'t reach server or bad internet access')); - return false; - } - - this._forceClose(); - - return true; - - }; + _onOpen() { + if (!this._ws_rpc) return; - ws.onerror = (error) => { + this._connected = true; - if (ws !== this.ws) { - return false; - } - - if (this.onError) this.onError(error); - - this._debugLog('[ReconnectionWebSocket] >---- event -----> ONERROR'); - - return true; - }; + if (this._isFirstTime) { + this._isFirstTime = false; + } - this.ws = ws; + if (this.onOpenCb) this.onOpenCb('open'); + this.emit(STATUS.OPEN); - return ws; - }); } /** - * connect to socket, can't be used after close - * @returns {Promise} + * On close callback */ - async reconnect() { - if (!this.ws) { - throw new Error('Socket not exist.'); - } + _onClose() { + if (this._isFirstTime) this._isFirstTime = false; + this._connected = false; + if (this.onCloseCb) this.onCloseCb('close'); - this._debugLog('[ReconnectionWebSocket] >---- event -----> FORCE RECONNECTING'); - await this.connect(this.url, this._options); + this.emit(STATUS.CLOSE); } /** - * set debug option - * @param {Boolean} status + * On error callback + * @param error */ - setDebugOption(status) { - this._options.debug = Boolean(status); + _onError(error) { + if (this.onErrorCb) this.onErrorCb('error', error); + this.emit(STATUS.ERROR); } /** - * call a method with params via RPC - * @param {Array} params - * @param {Number} timeout - timeout before reject + * init params and connect to chain + * @param {String} url - remote node address, + * should be (http|https|ws|wws)://(domain|ipv4|ipv6):port(?)/resource(?)?param=param(?). + * @param {Object} options - connection params. + * @param {Number} options.connectionTimeout - delay in ms between reconnection requests, + * default call delay before reject it. + * @param {Number} options.maxRetries - max count retries before close socket. + * @param {Number} options.pingTimeout - delay time in ms between ping request + * and socket disconnect. + * @param {Number} options.pingDelay - delay between last recived message and start checking connection. + * @param {Boolean} options.debug - debug mode status. * @returns {Promise} */ - call(params, timeout = this._options.connectionTimeout) { - if (!this.ws) { - return Promise.reject(new Error('Websocket is closed')); - } - - if (this.ws.readyState !== WebSocket.OPEN) { - return Promise.reject(new Error(`Websocket state error: ${this.ws.readyState}`)); - } - - const method = params[1]; - this._debugLog(`[ReconnectionWebSocket] >---- call -----> "id":${this._cbId + 1}`, JSON.stringify(params)); - - this._cbId += 1; - - if ( - method === 'set_subscribe_callback' || - method === 'broadcast_transaction_with_callback' || - method === 'set_pending_transaction_callback' || - method === 'set_block_applied_callback' || - method === 'set_echorand_message_callback' || - method === 'subscribe_contract_logs' || - method === 'submit_registration_solution' || - method === 'get_contract_logs' - ) { - // Store callback in subs map - this._subs[this._cbId] = { - callback: params[2][0], - }; - - // Replace callback with the callback id - params[2][0] = this._cbId; - - if (method === 'get_contract_logs') { - this._cbLogs.push(this._cbId); - } - } - - if (method === 'unsubscribe_from_accounts') { - if (typeof params[2][0] !== 'function') { - throw new Error('First parameter of unsub must be the original callback'); - } - - const unSubCb = params[2].splice(0, 1)[0]; - - this._subs.forEach((id) => { - if (id.callback === unSubCb) { - this._unsub[this._cbId] = id; - } - }); - } + async connect(url, options = {}) { + this.url = url; - const request = { - method: 'call', - params, + this.options = { + connectionTimeout: options.connectionTimeout, + maxRetries: options.maxRetries, + pingTimeout: options.pingTimeout, + pingDelay: options.pingDelay, + debug: options.debug, }; - request.id = this._cbId; - - return new Promise((resolve, reject) => { - const timeoutId = setTimeout(() => { - reject(new Error(`RPC call time is over Id: ${request.id}`)); + this.apis = options.apis || DEFAULT_CHAIN_APIS; + this._connected = false; + this._isFirstTime = true; - this._removePendingRequest(request.id); - }, timeout); + if (options.onOpen && typeof options.onOpen === 'function') this.onOpenCb = options.onOpen; + if (options.onClose && typeof options.onClose === 'function') this.onCloseCb = options.onClose; + if (options.onError && typeof options.onError === 'function') this.onErrorCb = options.onError; - this._cbs[this._cbId] = { - time: new Date(), - resolve, - reject, - timeoutId, - }; + if (!this._ws_rpc) this._ws_rpc = new ReconnectionWebSocket(); - this.ws.send(JSON.stringify(request)); - }); + this._ws_rpc.onOpen = () => this._onOpen(); + this._ws_rpc.onClose = () => this._onClose(); + this._ws_rpc.onError = () => this._onError(); + await this._ws_rpc.connect(url, this.options); } - /** - * message handler - * @param response - */ - _responseHandler(response) { - this._debugLog('[ReconnectionWebSocket] <---- reply ----<', JSON.stringify(response)); - - let sub = false; - let callback = null; - - if (response.method === 'notice') { - sub = true; - response = { - ...response, - id: response.params[0], - }; - } - - if (!sub) { - callback = this._cbs[response.id]; - this._responseCbId = response.id; - } else if (this._subs[response.id].callback instanceof Array) { - [callback] = this._subs[response.id].callback; - } else if (typeof this._subs[response.id].callback === 'function') { - // eslint-disable-next-line prefer-destructuring - callback = this._subs[response.id].callback; - } - - if (callback && !sub) { - const { timeoutId } = callback; - if (timeoutId) clearTimeout(timeoutId); - if (response.error) { - callback.reject(response.error); - } else { - callback.resolve(response.result); - } - - this._removeSuccessfulRequest(response.id); - - } else if (callback && sub) { - callback(response.params[1]); - if (this._cbLogs.includes(response.id)) { - delete this._subs[response.id]; - const indexCb = this._cbLogs.indexOf(response.id); - this._cbLogs.splice(indexCb); - } - - } else { - this._debugLog('[ReconnectionWebSocket] >---- warning ----> Unknown websocket response', response); - } + call(params, timeout = this.options.connectionTimeout) { + return this._ws_rpc.call(params, timeout); } /** - * get access to chain - * @param {String} user - * @param {String} password - * @param {Number} timeout - timeout before reject + * Reconnect to chain, can't be used after close * @returns {Promise} */ - login(user, password, timeout = this._options.pingTimeout) { - return this.call([1, 'login', [user, password]], timeout); - } - - /** - * update ping delay timeout - * @private - */ - _setPingDelay() { - this._clearPingDelay(); - this._pingDelayId = setTimeout(() => this._ping(), this._options.pingDelay); - } - - /** - * clear reconnection timeout - * @private - */ - _clearReconnectionTimeout() { - if (this._reconnectionTimeoutId) { - clearTimeout(this._reconnectionTimeoutId); - this._reconnectionTimeoutId = null; - } - } - - /** - * clear ping delay timeout - * @private - */ - _clearPingDelay() { - if (this._pingDelayId) { - clearTimeout(this._pingDelayId); - this._pingDelayId = null; - } - } - - /** - * clear waiting calls - * @private - */ - _clearWaitingCallPromises() { - const err = new Error(CONNECTION_CLOSED_ERROR_MESSAGE); - - for (let cbId = this._responseCbId + 1; cbId <= this._cbId; cbId += 1) { - if (this._cbs[cbId]) this._cbs[cbId].reject(err); - } - } - - /** - * reset calls id - * @private - */ - _resetId() { - this._cbId = 0; - } - - /** - * make call for check connection - * @private - */ - async _ping() { - try { - await this.login(); - } catch (_) { - if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return; - this._forceClose(); - } - } - - /** - * show debug logs - * @private - */ - _debugLog(...messages) { - if (!this._options.debug) return; - console.log(...messages); - } + async reconnect() { + if (!this._ws_rpc) throw new Error('Socket close.'); - /** - * remove pending request from map - * @private - */ - _removePendingRequest(id) { - delete this._cbs[id]; - delete this._subs[id]; - delete this._unsub[id]; + const reconnectResult = await this._ws_rpc.reconnect(); + return reconnectResult; } /** - * remove successful request from map - * @private + * Close socket, delete subscribers + * @returns {Promise} */ - _removeSuccessfulRequest(id) { - delete this._cbs[id]; - - if (this._unsub[id]) { - delete this._subs[this._unsub[id]]; - delete this._unsub[id]; - } - } - - _forceClose() { - - this._debugLog('[ReconnectionWebSocket] >---- _forceClose '); - - const { ws } = this; - this.ws = null; - - if (ws) { - ws.onopen = () => {}; - ws.onclose = () => {}; - ws.onerror = () => {}; - ws.onmessage = () => {}; - ws.close(); - } - - this._clearWaitingCallPromises(); - this._clearPingDelay(); - this._clearReconnectionTimeout(); - this._resetId(); - - if (this.onClose && this._currentRetry === 0) this.onClose(); - - this._debugLog('[ReconnectionWebSocket] >---- event -----> ONCLOSE'); - - if (this._forceClosePromise) { - this._forceClosePromise(); - this._forceClosePromise = null; - return true; - } - - if (this._currentRetry >= this._options.maxRetries) { - return true; - } - - this._reconnectionTimeoutId = setTimeout(async () => { + async close() { + if (this._ws_rpc && this._ws_rpc.ws) { try { - await this._connect(); - } catch (_) { - // + await this._ws_rpc.close(); + } catch (error) { + throw error; } - }, this._options.connectionTimeout); - - return true; + } } + /** - * - * @returns {Promise} + * Set debug option + * @param {Boolean} status */ - close() { - if (!this.ws || this.ws.readyState === WebSocket.CLOSING || this.ws.readyState === WebSocket.CLOSED) { - return Promise.reject(new Error('Socket already close')); - } - - return new Promise((resolve) => { - this._forceClosePromise = resolve; - this._forceClose(); - }); + setDebugOption(status) { + this._ws_rpc.setDebugOption(status); } } diff --git a/src/echo/providers/reconnection-websocket.js b/src/echo/providers/reconnection-websocket.js new file mode 100644 index 00000000..e231be19 --- /dev/null +++ b/src/echo/providers/reconnection-websocket.js @@ -0,0 +1,489 @@ +import WebSocket from 'isomorphic-ws'; + +import { + CONNECTION_TIMEOUT, + MAX_RETRIES, + PING_TIMEOUT, + PING_DELAY, + DEBUG, + CONNECTION_CLOSED_ERROR_MESSAGE, +} from '../../constants/ws-constants'; + +import { isVoid } from '../../utils/validators'; + +export default class ReconnectionWebSocket { + + get connected() { return this.ws && this.ws.readyState === WebSocket.OPEN; } + + constructor() { + this.onOpen = null; + this.onClose = null; + this.onError = null; + + this._currentRetry = 0; + this._pingDelayId = null; + this._options = {}; + + this._cbId = 0; + this._responseCbId = 0; + this._cbs = {}; + this._subs = []; + this._unsub = {}; + } + + /** + * init params and connect to chain + * + * @param {string} url remote node address, + * should be (http|https|ws|wws)://(domain|ipv4|ipv6):port(?)/resource(?)?param=param(?). + * + * @param {Object} options connection params. + * + * @param {number} options.connectionTimeout + * delay in ms between reconnection requests, default call delay before reject it. + * + * @param {number} options.maxRetries - max count retries before close socket. + * @param {number} options.pingTimeout - delay time in ms between ping request and socket disconnect. + * @param {number} options.pingDelay - delay between last recived message and start checking connection. + * @param {boolean} options.debug - debug mode status. + * @returns {Promise} + */ + async connect(url, options = {}) { + if (this.connected) await this.close(); + this._options = { + connectionTimeout: isVoid(options.connectionTimeout) ? CONNECTION_TIMEOUT : options.connectionTimeout, + maxRetries: isVoid(options.maxRetries) ? MAX_RETRIES : options.maxRetries, + pingTimeout: isVoid(options.pingTimeout) ? PING_TIMEOUT : options.pingTimeout, + pingDelay: isVoid(options.pingDelay) ? PING_DELAY : options.pingDelay, + debug: isVoid(options.debug) ? DEBUG : options.debug, + }; + + this.url = url; + this._isFirstConnection = true; + this._currentRetry = 0; + this._forceClosePromise = null; + this._reconnectionTimeoutId = null; + + this._cbId = 0; + this._responseCbId = 0; + this._cbs = {}; + this._cbLogs = []; + this._subs = []; + this._unsub = {}; + + return this._connect(); + } + + /** + * inner connection method + * @returns {Promise} + */ + _connect() { + + this._debugLog('[ReconnectionWebSocket] >---- retry _connect'); + + this._currentRetry += 1; + return new Promise((resolve, reject) => { + let ws = null; + try { + ws = new WebSocket(this.url); + } catch (error) { + ws = null; + if (this._isFirstConnection) { + this._isFirstConnection = false; + return reject(error); + } + } + + ws.onopen = () => { + + this._currentRetry = 0; + + if (this._isFirstConnection) { + this._isFirstConnection = false; + resolve(); + } + + if (this.onOpen) this.onOpen(); + + this._setPingDelay(); + + this._debugLog('[ReconnectionWebSocket] >---- event -----> ONOPEN'); + return true; + }; + + ws.onmessage = (message) => { + + if (ws !== this.ws) { + return false; + } + + this._responseHandler(JSON.parse(message.data)); + + this._debugLog('[ReconnectionWebSocket] >---- event -----> ONMESSAGE'); + + this._setPingDelay(); + + return true; + }; + + ws.onclose = () => { + + if (ws !== this.ws) { + return false; + } + + if (this._isFirstConnection) { + this._isFirstConnection = false; + reject(new Error('Could\'t reach server or bad internet access')); + return false; + } + + this._forceClose(); + + return true; + + }; + + ws.onerror = (error) => { + + if (ws !== this.ws) { + return false; + } + + if (this.onError) this.onError(error); + + this._debugLog('[ReconnectionWebSocket] >---- event -----> ONERROR'); + + return true; + }; + + this.ws = ws; + + return ws; + }); + } + + /** + * connect to socket, can't be used after close + * @returns {Promise} + */ + async reconnect() { + if (!this.ws) { + throw new Error('Socket not exist.'); + } + + this._debugLog('[ReconnectionWebSocket] >---- event -----> FORCE RECONNECTING'); + await this.connect(this.url, this._options); + } + + /** + * set debug option + * @param {Boolean} status + */ + setDebugOption(status) { + this._options.debug = Boolean(status); + } + + /** + * call a method with params via RPC + * @param {Array} params + * @param {Number} timeout - timeout before reject + * @returns {Promise} + */ + call(params, timeout = this._options.connectionTimeout) { + if (!this.ws) { + return Promise.reject(new Error('Websocket is closed')); + } + + if (this.ws.readyState !== WebSocket.OPEN) { + return Promise.reject(new Error(`Websocket state error: ${this.ws.readyState}`)); + } + + const method = params[1]; + this._debugLog(`[ReconnectionWebSocket] >---- call -----> "id":${this._cbId + 1}`, JSON.stringify(params)); + + this._cbId += 1; + + if ( + method === 'set_subscribe_callback' || + method === 'broadcast_transaction_with_callback' || + method === 'set_pending_transaction_callback' || + method === 'set_block_applied_callback' || + method === 'set_echorand_message_callback' || + method === 'subscribe_contract_logs' || + method === 'submit_registration_solution' || + method === 'get_contract_logs' + ) { + // Store callback in subs map + this._subs[this._cbId] = { + callback: params[2][0], + }; + + // Replace callback with the callback id + params[2][0] = this._cbId; + + if (method === 'get_contract_logs') { + this._cbLogs.push(this._cbId); + } + } + + if (method === 'unsubscribe_from_accounts') { + if (typeof params[2][0] !== 'function') { + throw new Error('First parameter of unsub must be the original callback'); + } + + const unSubCb = params[2].splice(0, 1)[0]; + + this._subs.forEach((id) => { + if (id.callback === unSubCb) { + this._unsub[this._cbId] = id; + } + }); + } + + const request = { + method: 'call', + params, + }; + request.id = this._cbId; + + return new Promise((resolve, reject) => { + + const timeoutId = setTimeout(() => { + reject(new Error(`RPC call time is over Id: ${request.id}`)); + + this._removePendingRequest(request.id); + }, timeout); + + this._cbs[this._cbId] = { + time: new Date(), + resolve, + reject, + timeoutId, + }; + + this.ws.send(JSON.stringify(request)); + }); + + } + + /** + * message handler + * @param response + */ + _responseHandler(response) { + this._debugLog('[ReconnectionWebSocket] <---- reply ----<', JSON.stringify(response)); + + let sub = false; + let callback = null; + + if (response.method === 'notice') { + sub = true; + response = { + ...response, + id: response.params[0], + }; + } + + if (!sub) { + callback = this._cbs[response.id]; + this._responseCbId = response.id; + } else if (this._subs[response.id].callback instanceof Array) { + [callback] = this._subs[response.id].callback; + } else if (typeof this._subs[response.id].callback === 'function') { + // eslint-disable-next-line prefer-destructuring + callback = this._subs[response.id].callback; + } + + if (callback && !sub) { + const { timeoutId } = callback; + if (timeoutId) clearTimeout(timeoutId); + if (response.error) { + callback.reject(response.error); + } else { + callback.resolve(response.result); + } + + this._removeSuccessfulRequest(response.id); + + } else if (callback && sub) { + callback(response.params[1]); + if (this._cbLogs.includes(response.id)) { + delete this._subs[response.id]; + const indexCb = this._cbLogs.indexOf(response.id); + this._cbLogs.splice(indexCb); + } + + } else { + this._debugLog('[ReconnectionWebSocket] >---- warning ----> Unknown websocket response', response); + } + } + + /** + * get access to chain + * @param {String} user + * @param {String} password + * @param {Number} timeout - timeout before reject + * @returns {Promise} + */ + login(user, password, timeout = this._options.pingTimeout) { + return this.call([1, 'login', [user, password]], timeout); + } + + /** + * update ping delay timeout + * @private + */ + _setPingDelay() { + this._clearPingDelay(); + this._pingDelayId = setTimeout(() => this._ping(), this._options.pingDelay); + } + + /** + * clear reconnection timeout + * @private + */ + _clearReconnectionTimeout() { + if (this._reconnectionTimeoutId) { + clearTimeout(this._reconnectionTimeoutId); + this._reconnectionTimeoutId = null; + } + } + + /** + * clear ping delay timeout + * @private + */ + _clearPingDelay() { + if (this._pingDelayId) { + clearTimeout(this._pingDelayId); + this._pingDelayId = null; + } + } + + /** + * clear waiting calls + * @private + */ + _clearWaitingCallPromises() { + const err = new Error(CONNECTION_CLOSED_ERROR_MESSAGE); + + for (let cbId = this._responseCbId + 1; cbId <= this._cbId; cbId += 1) { + if (this._cbs[cbId]) this._cbs[cbId].reject(err); + } + } + + /** + * reset calls id + * @private + */ + _resetId() { + this._cbId = 0; + } + + /** + * make call for check connection + * @private + */ + async _ping() { + try { + await this.login(); + } catch (_) { + if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return; + this._forceClose(); + } + } + + /** + * show debug logs + * @private + */ + _debugLog(...messages) { + if (!this._options.debug) return; + console.log(...messages); + } + + /** + * remove pending request from map + * @private + */ + _removePendingRequest(id) { + delete this._cbs[id]; + delete this._subs[id]; + delete this._unsub[id]; + } + + /** + * remove successful request from map + * @private + */ + _removeSuccessfulRequest(id) { + delete this._cbs[id]; + + if (this._unsub[id]) { + delete this._subs[this._unsub[id]]; + delete this._unsub[id]; + } + } + + _forceClose() { + + this._debugLog('[ReconnectionWebSocket] >---- _forceClose '); + + const { ws } = this; + this.ws = null; + + if (ws) { + ws.onopen = () => {}; + ws.onclose = () => {}; + ws.onerror = () => {}; + ws.onmessage = () => {}; + ws.close(); + } + + this._clearWaitingCallPromises(); + this._clearPingDelay(); + this._clearReconnectionTimeout(); + this._resetId(); + + if (this.onClose && this._currentRetry === 0) this.onClose(); + + this._debugLog('[ReconnectionWebSocket] >---- event -----> ONCLOSE'); + + if (this._forceClosePromise) { + this._forceClosePromise(); + this._forceClosePromise = null; + return true; + } + + if (this._currentRetry >= this._options.maxRetries) { + return true; + } + + this._reconnectionTimeoutId = setTimeout(async () => { + try { + await this._connect(); + } catch (_) { + // + } + }, this._options.connectionTimeout); + + return true; + } + /** + * + * @returns {Promise} + */ + close() { + if (!this.ws || this.ws.readyState === WebSocket.CLOSING || this.ws.readyState === WebSocket.CLOSED) { + return Promise.reject(new Error('Socket already close')); + } + + return new Promise((resolve) => { + this._forceClosePromise = resolve; + this._forceClose(); + }); + } + +} diff --git a/src/echo/subscriber.js b/src/echo/subscriber.js index 77be9da7..0a7d64b4 100644 --- a/src/echo/subscriber.js +++ b/src/echo/subscriber.js @@ -37,16 +37,17 @@ import { import { handleConnectionClosedError } from '../utils/helpers'; import { IMPLEMENTATION_OBJECT_TYPE_ID } from '../constants/chain-types'; +import { ConnectionType } from './providers'; + +/** @typedef {import("./engine").default} EchoApiEngine */ class Subscriber extends EventEmitter { /** * @constructor - * @param {ws} ws */ - constructor(ws) { + constructor() { super(); - this._ws = ws; this.subscriptions = { account: false, @@ -56,24 +57,29 @@ class Subscriber extends EventEmitter { }; this._clearSubscribers(); - this._ws.on(STATUS.CLOSE, () => this.callCbOnDisconnect()); } /** * @method init * @param {Cache} cache - * @param {WSAPI} wsApi + * @param {EchoApiEngine} engine * @param {API} api * * @return {Promise.} */ - async init(cache, wsApi, api) { + async init(cache, engine, api) { + + this._engine = engine; + if (engine.provider.connectionType !== ConnectionType.WS) { + throw new Error('Subscriber can only be created for ws connection'); + } + this._engine.provider.on(STATUS.CLOSE, () => this.callCbOnDisconnect()); this.cache = cache; - this._wsApi = wsApi; + this._wsApi = engine; this._api = api; - const databaseApiAvailable = this._ws.apis.includes(CHAIN_API.DATABASE_API); + const databaseApiAvailable = this._engine.apis.includes(CHAIN_API.DATABASE_API); if (databaseApiAvailable) await this._wsApi.database.setSubscribeCallback(this._onRespond.bind(this), true); this.callCbOnConnect(); if (!databaseApiAvailable) { @@ -119,11 +125,11 @@ class Subscriber extends EventEmitter { }; this.subscribers.connect.forEach((cb) => { - this._ws.removeListener(STATUS.OPEN, cb); + this._engine.provider.removeListener(STATUS.OPEN, cb); }); this.subscribers.disconnect.forEach((cb) => { - this._ws.removeListener(STATUS.CLOSE, cb); + this._engine.provider.removeListener(STATUS.CLOSE, cb); }); this._clearSubscribers(); @@ -829,10 +835,14 @@ class Subscriber extends EventEmitter { } if (status === 'connect') { - this._ws.removeListener(STATUS.OPEN, callback); + if (this._engine.provider.connectionType === ConnectionType.WS) { + this._engine.provider.removeListener(STATUS.OPEN, callback); + } this.subscribers.connect = this.subscribers.connect.filter((c) => c !== callback); } else { - this._ws.removeListener(STATUS.CLOSE, callback); + if (this._engine.provider.connectionType === ConnectionType.WS) { + this._engine.provider.removeListener(STATUS.CLOSE, callback); + } this.subscribers.disconnect = this.subscribers.disconnect.filter((c) => c !== callback); } diff --git a/src/echo/ws/index.js b/src/echo/ws/index.js deleted file mode 100644 index 6c492a4f..00000000 --- a/src/echo/ws/index.js +++ /dev/null @@ -1,244 +0,0 @@ -/* global window */ -import EventEmitter from 'events'; - -import ReconnectionWebSocket from './reconnection-websocket'; -import EchoApi from './echo-api'; -import { validateUrl, validateOptionsError } from '../../utils/validators'; -import { CHAIN_APIS, DEFAULT_CHAIN_APIS, STATUS } from '../../constants/ws-constants'; - -class WS extends EventEmitter { - - constructor() { - super(); - - this._ws_rpc = new ReconnectionWebSocket(); - - this._connected = false; - this._isFirstTime = true; - - this.onOpenCb = null; - this.onCloseCb = null; - this.onErrorCb = null; - - this._database = null; - this._network_broadcast = null; - this._history = null; - this._registration = null; - this._asset = null; - this._login = null; - } - - async initEchoApi() { - const initPromises = []; - - this.apis.forEach((api) => { - if (api === 'login') initPromises.push((this._login.api_id = 1)); - else initPromises.push(this[`_${api}`].init()); - }); - - try { - await Promise.all(initPromises); - await this._ws_rpc.login('', ''); - } catch (e) { - console.error('[WS] >---- error -----> ONOPEN', e); - await this.close(); - } - } - - /** - * On open callback - */ - _onOpen() { - if (!this._ws_rpc) return; - - this._connected = true; - - if (this._isFirstTime) { - this._isFirstTime = false; - } - - if (this.onOpenCb) this.onOpenCb('open'); - this.emit(STATUS.OPEN); - - } - - /** - * On close callback - */ - _onClose() { - if (this._isFirstTime) this._isFirstTime = false; - this._connected = false; - if (this.onCloseCb) this.onCloseCb('close'); - - this.emit(STATUS.CLOSE); - } - - /** - * On error callback - * @param error - */ - _onError(error) { - if (this.onErrorCb) this.onErrorCb('error', error); - this.emit(STATUS.ERROR); - } - - /** - * init params and connect to chain - * @param {String} url - remote node address, - * should be (http|https|ws|wws)://(domain|ipv4|ipv6):port(?)/resource(?)?param=param(?). - * @param {Object} options - connection params. - * @param {Number} options.connectionTimeout - delay in ms between reconnection requests, - * default call delay before reject it. - * @param {Number} options.maxRetries - max count retries before close socket. - * @param {Number} options.pingTimeout - delay time in ms between ping request - * and socket disconnect. - * @param {Number} options.pingDelay - delay between last recived message and start checking connection. - * @param {Boolean} options.debug - debug mode status. - * @returns {Promise} - */ - async connect(url, options = {}) { - if (!validateUrl(url)) throw new Error(`Invalid address ${url}`); - - if ( - typeof window !== 'undefined' && - window.location && - window.location.protocol === 'https:' && - url.indexOf('wss://') < 0 - ) { - throw new Error('Secure domains require wss connection'); - } - - const optionError = validateOptionsError(options); - - if (optionError) throw new Error(optionError); - - this.url = url; - - this.options = { - connectionTimeout: options.connectionTimeout, - maxRetries: options.maxRetries, - pingTimeout: options.pingTimeout, - pingDelay: options.pingDelay, - debug: options.debug, - }; - - this.apis = options.apis || DEFAULT_CHAIN_APIS; - this._connected = false; - this._isFirstTime = true; - - if (options.onOpen && typeof options.onOpen === 'function') this.onOpenCb = options.onOpen; - if (options.onClose && typeof options.onClose === 'function') this.onCloseCb = options.onClose; - if (options.onError && typeof options.onError === 'function') this.onErrorCb = options.onError; - - if (!this._ws_rpc) this._ws_rpc = new ReconnectionWebSocket(); - - this._ws_rpc.onOpen = () => this._onOpen(); - this._ws_rpc.onClose = () => this._onClose(); - this._ws_rpc.onError = () => this._onError(); - - CHAIN_APIS.forEach((api) => { this[`_${api}`] = new EchoApi(this._ws_rpc, api); }); - - await this._ws_rpc.connect(url, this.options); - await this.initEchoApi(); - } - - /** - * Reconnect to chain, can't be used after close - * @returns {Promise} - */ - async reconnect() { - if (!this._ws_rpc) throw new Error('Socket close.'); - - const reconnectResult = await this._ws_rpc.reconnect(); - return reconnectResult; - } - - /** - * Close socket, delete subscribers - * @returns {Promise} - */ - async close() { - if (this._ws_rpc && this._ws_rpc.ws) { - try { - await this._ws_rpc.close(); - } catch (error) { - throw error; - } - } - } - - /** - * Set debug option - * @param {Boolean} status - */ - setDebugOption(status) { - this._ws_rpc.setDebugOption(status); - } - - /** - * database API - * @returns {EchoApi} - */ - dbApi() { - return this._database; - } - - /** - * network API - * @returns {EchoApi} - */ - networkApi() { - return this._network_broadcast; - } - - /** - * history API - * @returns {EchoApi} - */ - historyApi() { - return this._history; - } - - /** - * registration API - * @returns {EchoApi} - */ - registrationApi() { - return this._registration; - } - - /** - * asset API - * @returns {EchoApi} - */ - assetApi() { - return this._asset; - } - - /** - * login API - * @returns {EchoApi} - */ - loginApi() { - return this._login; - } - - /** - * network node API - * @returns {EchoApi} - */ - networkNodeApi() { - return this._network_node; - } - - /** - * echorand API - * @returns {EchoApi} - */ - echorandApi() { - return this._echorand; - } - -} - -export default WS; diff --git a/test/api.test.js b/test/api.test.js index 856daeab..97764704 100644 --- a/test/api.test.js +++ b/test/api.test.js @@ -11,7 +11,7 @@ import { shouldReject } from './_test-utils'; import { WsProvider } from '../src/echo/providers'; import EchoApiEngine from '../src/echo/engine'; -describe.only('API', () => { +describe('API', () => { describe('API CONNECTION', () => { describe('when apis are provided', () => { const apis = [CHAIN_API.DATABASE_API, CHAIN_API.ASSET_API]; @@ -166,13 +166,13 @@ describe.only('API', () => { describe('database', () => { const wsProvider = new WsProvider(); beforeEach(async () => { - await ws.connect(url, { + await wsProvider.connect(url, { debug: false, apis: constants.WS_CONSTANTS.CHAIN_APIS }); }); afterEach(async () => { - await ws.close(); + await wsProvider.close(); }); describe('configs', () => { @@ -180,6 +180,7 @@ describe.only('API', () => { it('should get chain properties', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -203,6 +204,7 @@ describe.only('API', () => { it('should get global properties', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -226,6 +228,7 @@ describe.only('API', () => { it('should get config properties', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -249,6 +252,7 @@ describe.only('API', () => { it('should get chain id', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -267,6 +271,7 @@ describe.only('API', () => { it('should get dynamic global properties', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -292,6 +297,7 @@ describe.only('API', () => { it('should get block and save it to cache', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); const blockNumber = 2; @@ -312,6 +318,7 @@ describe.only('API', () => { it('should get transaction and save it to cache', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); const blockNumber = 205378; @@ -333,6 +340,7 @@ describe.only('API', () => { it('should get accounts and save it to cache', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); const accountId1 = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ACCOUNT}.5`; @@ -373,7 +381,8 @@ describe.only('API', () => { describe('#getFullAccounts()', () => { it('should get accounts and save it to cache', async () => { try { - const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API, CHAIN_API.HISTORY_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); const accountId1 = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ACCOUNT}.5`; @@ -423,6 +432,7 @@ describe.only('API', () => { it('should get account count', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -442,6 +452,7 @@ describe.only('API', () => { it('should get asset by symbol and save it in multi caches', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -479,6 +490,7 @@ describe.only('API', () => { it('should get assets by id and save it in multi caches', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -510,6 +522,7 @@ describe.only('API', () => { it('should get objects by id and save it in multi caches', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -564,6 +577,7 @@ describe.only('API', () => { it('should get objects by id and save it in multi caches', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -618,6 +632,7 @@ describe.only('API', () => { it('should get committee member by id and save it in multi caches', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -649,6 +664,7 @@ describe.only('API', () => { it('should get account by name and save it in multi caches', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -683,6 +699,7 @@ describe.only('API', () => { it('should get account by name and limit', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -703,6 +720,7 @@ describe.only('API', () => { it('should get assets by name and limit', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -723,6 +741,7 @@ describe.only('API', () => { it('should get block header by block number', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -744,6 +763,7 @@ describe.only('API', () => { it('should get contract', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -765,6 +785,7 @@ describe.only('API', () => { it('should get contracts', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -784,7 +805,8 @@ describe.only('API', () => { describe('#requestRegistrationTask', () => { it('should get registration task', async() => { try { - const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API, CHAIN_API.REGISTRATION_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -804,6 +826,7 @@ describe.only('API', () => { it('should get committee by id and save to cache', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -849,6 +872,7 @@ describe.only('API', () => { it('should get committee by account id and save to cache', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -894,6 +918,7 @@ describe.only('API', () => { it('should get committee frozen balance by committee member id', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -926,6 +951,7 @@ describe.only('API', () => { it('should get btc address by account id', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -952,6 +978,7 @@ describe.only('API', () => { it('should get null because script with this deposit id does not exist', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -984,7 +1011,8 @@ describe.only('API', () => { describe('#getAccountHistory()', () => { it('should get account history', async () => { try { - const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API, CHAIN_API.HISTORY_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -1004,7 +1032,8 @@ describe.only('API', () => { describe('#getRelativeAccountHistory()', () => { it('should get relative account history', async () => { try { - const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API, CHAIN_API.HISTORY_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -1027,7 +1056,8 @@ describe.only('API', () => { describe('#getAccountHistoryOperations()', () => { it('should get account history operations', async () => { try { - const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API, CHAIN_API.HISTORY_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -1052,6 +1082,7 @@ describe.only('API', () => { it('should get contract history', async () => { try { const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); @@ -1074,7 +1105,8 @@ describe.only('API', () => { describe('#getRegistrar()', () => { it('should get registrarId', async () => { try { - const engine = new EchoApiEngine([CHAIN_API.DATABASE_API], wsProvider); + const engine = new EchoApiEngine([CHAIN_API.DATABASE_API, CHAIN_API.REGISTRATION_API], wsProvider); + await engine.init(); const cache = new Cache(); const api = new API(cache, engine); diff --git a/test/subscriber.test.js b/test/subscriber.test.js index 5a0df56e..53547e7c 100644 --- a/test/subscriber.test.js +++ b/test/subscriber.test.js @@ -456,6 +456,6 @@ describe('SUBSCRIBER', () => { }); after(async () => { - await echo.disconnect(); + if (echo.isConnected) await echo.disconnect(); }); }); From ffc5ab7cc7d74f8d949e6adfa1e26e61c09e6d88 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 13 Apr 2020 16:18:37 +0300 Subject: [PATCH 52/62] Resolve conflicts with EEX-773 --- src/echo/api.js | 6 +++--- test/preparation/preparation.js | 2 +- test/wallet-api.test.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/echo/api.js b/src/echo/api.js index 729fa242..16e11293 100644 --- a/src/echo/api.js +++ b/src/echo/api.js @@ -1990,7 +1990,7 @@ class API { * @returns {Promise} */ async subscribeContractLogs(callback, opts = {}) { - return this.wsApi.database.subscribeContractLogs((result) => { + return this.engine.database.subscribeContractLogs((result) => { assert.ok(Array.isArray(result)); assert.strictEqual(result.length, 1); callback(result[0]); @@ -1999,7 +1999,7 @@ class API { /** @param {UInt64} subscribeId */ async unsubscribeContractLogs(subscribeId) { - return this.wsApi.database.unsubscribeContractLogs(basic.integers.uint64.toRaw(subscribeId)); + return this.engine.database.unsubscribeContractLogs(basic.integers.uint64.toRaw(subscribeId)); } /** @@ -2333,7 +2333,7 @@ class API { const limit = options.limit === undefined ? 100 : basic.integers.uint32.toRaw(options.limit); const start = options.stop === undefined ? 0 : basic.integers.uint64.toRaw(options.start); if (limit > 100) throw new Error('Limit is greater than 100'); - return this.wsApi.history.getRelativeContractHistory(contract, stop, limit, start); + return this.engine.history.getRelativeContractHistory(contract, stop, limit, start); } /** diff --git a/test/preparation/preparation.js b/test/preparation/preparation.js index 3837e929..3f043ca0 100644 --- a/test/preparation/preparation.js +++ b/test/preparation/preparation.js @@ -7,7 +7,7 @@ const prepare = async () => { maxRetries: 5, pingTimeout: 3000, pingDelay: 10000, - debug: true, + debug: false, apis: constants.WS_CONSTANTS.CHAIN_APIS, }); const balanceObject = await echo.api.getObject(`1.${constants.PROTOCOL_OBJECT_TYPE_ID.BALANCE}.0`); diff --git a/test/wallet-api.test.js b/test/wallet-api.test.js index 4b0f7958..172b0e9a 100644 --- a/test/wallet-api.test.js +++ b/test/wallet-api.test.js @@ -19,7 +19,7 @@ import { TRANSFER } from '../src/constants/operations-ids'; import PrivateKey from '../src/crypto/private-key'; import { bytecode } from './operations/_contract.test'; -describe('WALLET API', () => { +describe.skip('WALLET API', () => { const shouldDoBroadcastToNetwork = false; const brainKey = 'some key12'; From bce4d9ba75e6f85dbb589a9c97037f0c7c5ea350 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 13 Apr 2020 19:56:39 +0300 Subject: [PATCH 53/62] Fix wallet-api --- src/echo/apis/wallet-api.js | 238 ++++++++++++++++++------------------ test/wallet-api.test.js | 2 +- 2 files changed, 120 insertions(+), 120 deletions(-) diff --git a/src/echo/apis/wallet-api.js b/src/echo/apis/wallet-api.js index d70b309d..e1f02066 100644 --- a/src/echo/apis/wallet-api.js +++ b/src/echo/apis/wallet-api.js @@ -80,7 +80,7 @@ const { class WalletAPI { - constructor() { this.wsRpc = new WsProvider(); } + constructor() { this.wsProvider = new WsProvider(); } /** * Init params and connect to chain. @@ -88,13 +88,13 @@ class WalletAPI { * @param {Parameters1} connectionOptions connection params. * @returns {Promise} */ - async connect(url, connectionOptions) { await this.wsRpc.connect(url, connectionOptions); } + async connect(url, connectionOptions) { await this.wsProvider.connect(url, connectionOptions); } /** * Exit from current wallet. * @returns {Promise} */ - exit() { return this.wsRpc.call([0, 'exit', []]); } + exit() { return this.wsProvider.call([0, 'exit', []]); } /** * Returns a list of all commands supported by the wallet API. @@ -102,7 +102,7 @@ class WalletAPI { * For more detailed help on a single command, use `get_help()` * @returns {Promise} a multi-line string suitable for displaying on a terminal */ - help() { return this.wsRpc.call([0, 'help', []]); } + help() { return this.wsProvider.call([0, 'help', []]); } /** * Returns detailed help on a single API command. @@ -111,7 +111,7 @@ class WalletAPI { */ helpMethod(method) { if (!isMethodExists(method)) return Promise.reject(new Error('This method does not exists')); - return this.wsRpc.call([0, 'help_method', [string.toRaw(method)]]); + return this.wsProvider.call([0, 'help_method', [string.toRaw(method)]]); } /** @@ -119,46 +119,46 @@ class WalletAPI { * current active witnesses and committee members. * @returns {Promise} runtime info about the blockchain */ - info() { return this.wsRpc.call([0, 'info', []]); } + info() { return this.wsProvider.call([0, 'info', []]); } /** * Returns info such as client version, git version of graphene/fc, version of boost, openssl. * @returns {Promise} compile time info and client and dependencies versions */ - about() { return this.wsRpc.call([0, 'about', []]); } + about() { return this.wsProvider.call([0, 'about', []]); } /** * Add nodes to the network * @param {string} nodes nodes for adding * @returns {Promise} */ - networkAddNodes(nodes) { return this.wsRpc.call([0, 'network_add_nodes', [vector(string).toRaw(nodes)]]); } + networkAddNodes(nodes) { return this.wsProvider.call([0, 'network_add_nodes', [vector(string).toRaw(nodes)]]); } /** * Get peers connected to network. * @returns {Promise} peers connected to network */ - networkGetConnectedPeers() { return this.wsRpc.call([0, 'network_get_connected_peers', []]); } + networkGetConnectedPeers() { return this.wsProvider.call([0, 'network_get_connected_peers', []]); } /** * Checks whether the wallet has just been created and has not yet had a password set. * Calling `set_password` will transition the wallet to the locked state. * @returns {Promise} true if the wallet is new */ - isNew() { return this.wsRpc.call([0, 'is_new', []]); } + isNew() { return this.wsProvider.call([0, 'is_new', []]); } /** * Checks whether the wallet is locked (is unable to use its private keys). * This state can be changed by calling `lock()` or `unlock()`. * @returns {Promise} true if the wallet is locked */ - isLocked() { return this.wsRpc.call([0, 'is_locked', []]); } + isLocked() { return this.wsProvider.call([0, 'is_locked', []]); } /** * Locks the wallet immediately. * @returns {Promise} */ - lock() { return this.wsRpc.call([0, 'lock', []]); } + lock() { return this.wsProvider.call([0, 'lock', []]); } /** * Unlocks the wallet. @@ -167,7 +167,7 @@ class WalletAPI { * in the wallet it should be input interactively * @returns {Promise} */ - unlock(password) { return this.wsRpc.call([0, 'unlock', [string.toRaw(password)]]); } + unlock(password) { return this.wsProvider.call([0, 'unlock', [string.toRaw(password)]]); } /** * Sets a new password on the wallet. @@ -175,20 +175,20 @@ class WalletAPI { * @param {string} password the password, should be input automatically in the wallet * @returns {Promise} */ - setPassword(password) { return this.wsRpc.call([0, 'set_password', [string.toRaw(password)]]); } + setPassword(password) { return this.wsProvider.call([0, 'set_password', [string.toRaw(password)]]); } /** * Create new EdDSA keypair encoded in base58. * @returns {Promise<[string, string]>} new private and public key */ - createEddsaKeypair() { return this.wsRpc.call([0, 'create_eddsa_keypair', []]); } + createEddsaKeypair() { return this.wsProvider.call([0, 'create_eddsa_keypair', []]); } /** * Dumps all private keys owned by the wallet. * The keys are printed in WIF format. You can import these keys into another wallet using `import_key()` * @returns {Promise<[string, string][]>} a map containing the private keys, indexed by their public key */ - dumpPrivateKeys() { return this.wsRpc.call([0, 'dump_private_keys', []]); } + dumpPrivateKeys() { return this.wsProvider.call([0, 'dump_private_keys', []]); } /** * Imports the private key for an existing account. @@ -202,7 +202,7 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'import_key', [string.toRaw(accountNameOrId), privateKey.toRaw(privateKeyWif)]]); + return this.wsProvider.call([0, 'import_key', [string.toRaw(accountNameOrId), privateKey.toRaw(privateKeyWif)]]); } /** @@ -212,7 +212,7 @@ class WalletAPI { * @returns {[string, boolean][]} a map containing the accounts found and whether imported */ importAccounts(filename, password) { - return this.wsRpc.call([0, 'import_accounts', [string.toRaw(filename), string.toRaw(password)]]); + return this.wsProvider.call([0, 'import_accounts', [string.toRaw(filename), string.toRaw(password)]]); } /** @@ -233,7 +233,7 @@ class WalletAPI { if (!isAccountName(destAccountName)) { return Promise.reject(new Error('destAccount name should be string and valid')); } - return this.wsRpc.call([0, 'import_account_keys', [ + return this.wsProvider.call([0, 'import_account_keys', [ string.toRaw(filename), string.toRaw(password), string.toRaw(srcAccountName), @@ -253,7 +253,7 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'import_balance', [ + return this.wsProvider.call([0, 'import_balance', [ string.toRaw(accountNameOrId), bool.toRaw(shouldDoBroadcastToNetwork), vector(privateKey).toRaw(wifKeys), @@ -267,7 +267,7 @@ class WalletAPI { * (and, with effort, memorize). * @returns {Promise} a suggested brain_key */ - suggestBrainKey() { return this.wsRpc.call([0, 'suggest_brain_key', []]); } + suggestBrainKey() { return this.wsProvider.call([0, 'suggest_brain_key', []]); } /** * Derive any number of *possible* owner keys from a given brain key. @@ -280,7 +280,7 @@ class WalletAPI { */ deriveKeysFromBrainKey(brainKey, numberOfDesiredKeys) { if (numberOfDesiredKeys < 1) return Promise.reject(new Error('Number should be positive integer')); - return this.wsRpc.call([0, 'derive_keys_from_brain_key', [ + return this.wsProvider.call([0, 'derive_keys_from_brain_key', [ string.toRaw(brainKey), int64.toRaw(numberOfDesiredKeys), ]]); @@ -293,7 +293,7 @@ class WalletAPI { * @returns {Promise} Whether a public key is known */ isPublicKeyRegistered(accountPublicKey) { - return this.wsRpc.call([0, 'is_public_key_registered', [publicKey.toRaw(accountPublicKey)]]); + return this.wsProvider.call([0, 'is_public_key_registered', [publicKey.toRaw(accountPublicKey)]]); } /** @@ -301,7 +301,7 @@ class WalletAPI { * @param {any} tr the singed transaction * @returns {Promise} transaction id string */ - getTransactionId(tr) { return this.wsRpc.call([0, 'get_transaction_id', [signedTransaction.toRaw(tr)]]); } + getTransactionId(tr) { return this.wsProvider.call([0, 'get_transaction_id', [signedTransaction.toRaw(tr)]]); } /** * Get the WIF private key corresponding to a public key. The private key must already be in the wallet. @@ -309,7 +309,7 @@ class WalletAPI { * @returns {Promise} private key of this account */ getPrivateKey(accountPublicKey) { - return this.wsRpc.call([0, 'get_private_key', [publicKey.toRaw(accountPublicKey)]]); + return this.wsProvider.call([0, 'get_private_key', [publicKey.toRaw(accountPublicKey)]]); } /** @@ -321,7 +321,7 @@ class WalletAPI { * If `wallet_filename` is empty, it reloads the existing wallet file * @returns {Promise} true if the specified wallet is loaded */ - loadWalletFile(walletFilename) { return this.wsRpc.call([0, 'load_wallet_file', [string.toRaw(walletFilename)]]); } + loadWalletFile(walletFilename) { return this.wsProvider.call([0, 'load_wallet_file', [string.toRaw(walletFilename)]]); } /** * Transforms a brain key to reduce the chance of errors when re-entering the key from memory. @@ -330,7 +330,7 @@ class WalletAPI { * @param {string} brainKey the brain key as supplied by the user * @returns {Promise} the brain key in its normalized form */ - normalizeBrainKey(brainKey) { return this.wsRpc.call([0, 'normalize_brain_key', [string.toRaw(brainKey)]]); } + normalizeBrainKey(brainKey) { return this.wsProvider.call([0, 'normalize_brain_key', [string.toRaw(brainKey)]]); } /** * Saves the current wallet to the given filename. @@ -342,14 +342,14 @@ class WalletAPI { * If `wallet_filename` is empty, save to the current filename * @returns {Promise} */ - saveWalletFile(walletFilename) { return this.wsRpc.call([0, 'save_wallet_file', [string.toRaw(walletFilename)]]); } + saveWalletFile(walletFilename) { return this.wsProvider.call([0, 'save_wallet_file', [string.toRaw(walletFilename)]]); } /** * Lists all accounts controlled by this wallet. * This returns a list of the full account objects for all accounts whose private keys we possess. * @returns {Promise} a list of account objects */ - listMyAccounts() { return this.wsRpc.call([0, 'list_my_accounts', []]); } + listMyAccounts() { return this.wsProvider.call([0, 'list_my_accounts', []]); } /** * Lists all accounts registered in the blockchain. @@ -367,7 +367,7 @@ class WalletAPI { if (!limit > API_CONFIG.LIST_ACCOUNTS_MAX_LIMIT) { return Promise.reject(new Error(`Limit should be capped at ${API_CONFIG.LIST_ACCOUNTS_MAX_LIMIT}`)); } - return this.wsRpc.call([0, 'list_accounts', [string.toRaw(lowerbound), uint32.toRaw(limit)]]); + return this.wsProvider.call([0, 'list_accounts', [string.toRaw(lowerbound), uint32.toRaw(limit)]]); } /** @@ -379,7 +379,7 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'list_account_balances', [string.toRaw(accountNameOrId)]]); + return this.wsProvider.call([0, 'list_account_balances', [string.toRaw(accountNameOrId)]]); } /** @@ -387,7 +387,7 @@ class WalletAPI { * @param {string} idOfAccount id the id of either an account or a contract * @returns {Promise} a list of the given account/contract balances */ - listIdBalances(idOfAccount) { return this.wsRpc.call([0, 'list_id_balances', [accountId.toRaw(idOfAccount)]]); } + listIdBalances(idOfAccount) { return this.wsProvider.call([0, 'list_id_balances', [accountId.toRaw(idOfAccount)]]); } /** * Registers a third party's account on the blockckain. @@ -408,7 +408,7 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'register_account', [ + return this.wsProvider.call([0, 'register_account', [ string.toRaw(name), publicKey.toRaw(activeKey), string.toRaw(accountNameOrId), @@ -434,7 +434,7 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'create_account_with_brain_key', [ + return this.wsProvider.call([0, 'create_account_with_brain_key', [ string.toRaw(brainKey), string.toRaw(accountName), string.toRaw(accountNameOrId), @@ -468,7 +468,7 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) throw new Error('Accounts id or name should be string and valid'); if (!isContractCode(contractCode)) throw new Error('Byte code should be string and valid'); amount = validateAmount(amount); - return this.wsRpc.call([0, 'create_contract', [ + return this.wsProvider.call([0, 'create_contract', [ string.toRaw(accountNameOrId), string.toRaw(contractCode), string.toRaw(amount), @@ -500,7 +500,7 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) throw new Error('Accounts id or name should be string and valid'); if (!isContractCode(contractCode)) throw new Error('Byte code should be string and valid'); amount = validateAmount(amount); - return this.wsRpc.call([0, 'call_contract', [ + return this.wsProvider.call([0, 'call_contract', [ string.toRaw(accountNameOrId), contractId.toRaw(idOfContract), string.toRaw(contractCode), @@ -522,7 +522,7 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'contract_fund_fee_pool', [ + return this.wsProvider.call([0, 'contract_fund_fee_pool', [ string.toRaw(accountNameOrId), contractId.toRaw(idOfContract), uint64.toRaw(amount), @@ -539,7 +539,7 @@ class WalletAPI { if (!isContractResultId(contractResultId)) { return Promise.reject(new Error('Contract resultId should be string and valid')); } - return this.wsRpc.call([0, 'get_contract_result', [string.toRaw(contractResultId)]]); + return this.wsProvider.call([0, 'get_contract_result', [string.toRaw(contractResultId)]]); } /** @@ -551,7 +551,7 @@ class WalletAPI { * @returns {Promise} a list of accounts mapping account names to account ids */ async getContractHistory(_contractId, limit) { - return this.wsRpc.call([0, 'get_contract_history', [contractId.toRaw(_contractId), uint32.toRaw(limit)]]); + return this.wsProvider.call([0, 'get_contract_history', [contractId.toRaw(_contractId), uint32.toRaw(limit)]]); } /** @@ -563,7 +563,7 @@ class WalletAPI { * @returns {Promise} a list of operation history objects */ async getRelativeContractHistory(_contractId, stop, limit, start) { - return this.wsRpc.call([0, 'get_relative_contract_history', [ + return this.wsProvider.call([0, 'get_relative_contract_history', [ contractId.toRaw(_contractId), uint32.toRaw(stop), uint32.toRaw(limit), @@ -591,7 +591,7 @@ class WalletAPI { if (!isAssetIdOrName(assetIdOrName)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsRpc.call([0, 'transfer', [ + return this.wsProvider.call([0, 'transfer', [ string.toRaw(fromAccountNameOrId), string.toRaw(toAccountNameOrId), string.toRaw(amount), @@ -620,7 +620,7 @@ class WalletAPI { if (!isAssetIdOrName(assetIdOrName)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsRpc.call([0, 'transfer2', [ + return this.wsProvider.call([0, 'transfer2', [ string.toRaw(fromAccountNameOrId), string.toRaw(toAccountNameOrId), string.toRaw(amount), @@ -654,7 +654,7 @@ class WalletAPI { if (!isAccountIdOrName(accountToList)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'whitelist_account', [ + return this.wsProvider.call([0, 'whitelist_account', [ string.toRaw(authorizingAccount), string.toRaw(accountToList), accountListing.toRaw(newListingStatus), @@ -671,7 +671,7 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'get_vesting_balances', [string.toRaw(accountNameOrId)]]); + return this.wsProvider.call([0, 'get_vesting_balances', [string.toRaw(accountNameOrId)]]); } /** @@ -690,7 +690,7 @@ class WalletAPI { if (!isValidAmount(amount)) { return Promise.reject(new Error('Invalid amount')); } - return this.wsRpc.call([0, 'withdraw_vesting', [ + return this.wsProvider.call([0, 'withdraw_vesting', [ string.toRaw(witnessAccountNameOrId), string.toRaw(amount), string.toRaw(assetSymbol), @@ -707,7 +707,7 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'get_account', [string.toRaw(accountNameOrId)]]); + return this.wsProvider.call([0, 'get_account', [string.toRaw(accountNameOrId)]]); } /** @@ -717,7 +717,7 @@ class WalletAPI { */ getAccountId(accountName) { if (!isAccountName(accountName)) return Promise.reject(new Error('Account name should be string and valid')); - return this.wsRpc.call([0, 'get_account_id', [string.toRaw(accountName)]]); + return this.wsProvider.call([0, 'get_account_id', [string.toRaw(accountName)]]); } /** @@ -734,7 +734,7 @@ class WalletAPI { if (!limit > API_CONFIG.ACCOUNT_HISTORY_MAX_LIMIT) { return Promise.reject(new Error(`Limit should be capped at ${API_CONFIG.ACCOUNT_HISTORY_MAX_LIMIT}`)); } - return this.wsRpc.call([0, 'get_account_history', [string.toRaw(accountIdOrName), int64.toRaw(limit)]]); + return this.wsProvider.call([0, 'get_account_history', [string.toRaw(accountIdOrName), int64.toRaw(limit)]]); } /** @@ -757,7 +757,7 @@ class WalletAPI { if (!limit > API_CONFIG.RELATIVE_ACCOUNT_HISTORY_MAX_LIMIT) { return Promise.reject(new Error(`Limit should be less ${API_CONFIG.RELATIVE_ACCOUNT_HISTORY_MAX_LIMIT}`)); } - return this.wsRpc.call([0, 'get_relative_account_history', [ + return this.wsProvider.call([0, 'get_relative_account_history', [ string.toRaw(accountIdOrName), uint64.toRaw(stop), int64.toRaw(limit), uint64.toRaw(start), @@ -770,7 +770,7 @@ class WalletAPI { * @returns {Promise} the contract object */ getContractObject(idOfContract) { - return this.wsRpc.call([0, 'get_contract_object', [contractId.toRaw(idOfContract)]]); + return this.wsProvider.call([0, 'get_contract_object', [contractId.toRaw(idOfContract)]]); } /** @@ -778,7 +778,7 @@ class WalletAPI { * @param {string} idOfContract id of the contract * @returns {Promise} the contract information */ - getContract(idOfContract) { return this.wsRpc.call([0, 'get_contract', [contractId.toRaw(idOfContract)]]); } + getContract(idOfContract) { return this.wsProvider.call([0, 'get_contract', [contractId.toRaw(idOfContract)]]); } /** * Whitelist or blacklist contract pool. @@ -805,7 +805,7 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'whitelist_contract_pool', [ + return this.wsProvider.call([0, 'whitelist_contract_pool', [ string.toRaw(accountIdOrName), contractId.toRaw(idOfContract), vector(accountId).toRaw(addToWhitelist), @@ -832,7 +832,7 @@ class WalletAPI { if (!isContractCode(codeOfTheContract)) { return Promise.reject(new Error('Byte code should be string and valid')); } - return this.wsRpc.call([0, 'call_contract_no_changing_state', [ + return this.wsProvider.call([0, 'call_contract_no_changing_state', [ contractId.toRaw(idOfContract), string.toRaw(caller), string.toRaw(amount), @@ -847,7 +847,7 @@ class WalletAPI { * @returns {Promise} contract's feepool balance */ getContractPoolBalance(idOfContract) { - return this.wsRpc.call([0, 'get_contract_pool_balance', [contractId.toRaw(idOfContract)]]); + return this.wsProvider.call([0, 'get_contract_pool_balance', [contractId.toRaw(idOfContract)]]); } /** @@ -856,7 +856,7 @@ class WalletAPI { * @returns {Promise} whitelist and blacklist of contract pool object */ getContractPoolWhitelist(idOfContract) { - return this.wsRpc.call([0, 'get_contract_pool_whitelist', [contractId.toRaw(idOfContract)]]); + return this.wsProvider.call([0, 'get_contract_pool_whitelist', [contractId.toRaw(idOfContract)]]); } /** @@ -864,7 +864,7 @@ class WalletAPI { * @param {string} idOfAccount the id of the account to provide information about * @returns {Promise} the public eth address data stored in the blockchain */ - getEthAddress(idOfAccount) { return this.wsRpc.call([0, 'get_eth_address', [accountId.toRaw(idOfAccount)]]); } + getEthAddress(idOfAccount) { return this.wsProvider.call([0, 'get_eth_address', [accountId.toRaw(idOfAccount)]]); } /** * Returns all approved deposits, for the given account id. @@ -873,7 +873,7 @@ class WalletAPI { * @returns {Promise} the all public deposits data stored in the blockchain */ getAccountDeposits(idOfAccount, type) { - return this.wsRpc.call([0, 'get_account_deposits', [accountId.toRaw(idOfAccount), type]]); + return this.wsProvider.call([0, 'get_account_deposits', [accountId.toRaw(idOfAccount), type]]); } /** @@ -899,7 +899,7 @@ class WalletAPI { } if (!isNotEmptyString(tokenName)) return Promise.reject(new Error('Name should be string and valid')); if (!isNotEmptyString(tokenSymbol)) return Promise.reject(new Error('Name should be string and valid')); - return this.wsRpc.call([0, 'register_erc20_token', [ + return this.wsProvider.call([0, 'register_erc20_token', [ string.toRaw(accountIdOrName), ethAddress.toRaw(ethereumTokenAddress), string.toRaw(tokenName), @@ -915,7 +915,7 @@ class WalletAPI { * @returns {Promise} the public erc20 token data stored in the blockchain */ getErc20Token(ethereumTokenAddress) { - return this.wsRpc.call([0, 'get_erc20_token', [ethAddress.toRaw(ethereumTokenAddress)]]); + return this.wsProvider.call([0, 'get_erc20_token', [ethAddress.toRaw(ethereumTokenAddress)]]); } /** @@ -924,7 +924,7 @@ class WalletAPI { * @returns {Promise} true if erc20 token data stored in the blockchain, else false */ checkErc20Token(idOfContract) { - return this.wsRpc.call([0, 'check_erc20_token', [contractId.toRaw(idOfContract)]]); + return this.wsProvider.call([0, 'check_erc20_token', [contractId.toRaw(idOfContract)]]); } /** @@ -933,7 +933,7 @@ class WalletAPI { * @returns {Promise} the all public erc20 deposits data stored in the blockchain */ getErc20AccountDeposits(idOfAccount) { - return this.wsRpc.call([0, 'get_erc20_account_deposits', [accountId.toRaw(idOfAccount)]]); + return this.wsProvider.call([0, 'get_erc20_account_deposits', [accountId.toRaw(idOfAccount)]]); } /** @@ -942,7 +942,7 @@ class WalletAPI { * @returns {Promise} the all public erc20 withdrawals data stored in the blockchain */ getErc20AccountWithdrawals(idOfAccount) { - return this.wsRpc.call([0, 'get_erc20_account_withdrawals', [accountId.toRaw(idOfAccount)]]); + return this.wsProvider.call([0, 'get_erc20_account_withdrawals', [accountId.toRaw(idOfAccount)]]); } /** @@ -958,7 +958,7 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'withdraw_erc20_token', [ + return this.wsProvider.call([0, 'withdraw_erc20_token', [ string.toRaw(accountIdOrName), ethAddress.toRaw(toEthereumAddress), erc20TokenId.toRaw(idOferc20Token), @@ -979,7 +979,7 @@ class WalletAPI { return Promise.reject(new Error('Accounts id or name should be string and valid')); } if (!isNotEmptyString(label)) return Promise.reject(new Error('Label should be string and valid')); - return this.wsRpc.call([0, 'generate_account_address', [ + return this.wsProvider.call([0, 'generate_account_address', [ string.toRaw(accountIdOrName), string.toRaw(label), bool.toRaw(shouldDoBroadcastToNetwork), @@ -994,7 +994,7 @@ class WalletAPI { * @returns {Promise} Addresses owned by account in specified ids interval */ getAccountAddresses(idOfAccount, startFrom, limit) { - return this.wsRpc.call([0, 'get_account_addresses', [ + return this.wsProvider.call([0, 'get_account_addresses', [ accountId.toRaw(idOfAccount), uint64.toRaw(startFrom), uint64.toRaw(limit), @@ -1006,7 +1006,7 @@ class WalletAPI { * @param {string} address address in form of ripemd160 hash * @returns {Promise} Account id of owner */ - getAccountByAddress(address) { return this.wsRpc.call([0, 'get_account_by_address', [ripemd160.toRaw(address)]]); } + getAccountByAddress(address) { return this.wsProvider.call([0, 'get_account_by_address', [ripemd160.toRaw(address)]]); } /** * Returns all approved withdrawals, for the given account id. @@ -1015,7 +1015,7 @@ class WalletAPI { * @returns {Promise} the all public withdrawals data stored in the blockchain */ getAccountWithdrawals(idOfAccount, type) { - return this.wsRpc.call([0, 'get_account_withdrawals', [accountId.toRaw(idOfAccount), type]]); + return this.wsProvider.call([0, 'get_account_withdrawals', [accountId.toRaw(idOfAccount), type]]); } /** @@ -1028,7 +1028,7 @@ class WalletAPI { * @returns {Promise} the signed version of the transaction */ approveProposal(feePayingAccountId, idOfProposal, delta, shouldDoBroadcastToNetwork) { - return this.wsRpc.call([0, 'approve_proposal', [ + return this.wsProvider.call([0, 'approve_proposal', [ accountId.toRaw(feePayingAccountId), proposalId.toRaw(idOfProposal), wallet.approvalDelta.toRaw(delta), @@ -1046,7 +1046,7 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'create_eth_address', [ + return this.wsProvider.call([0, 'create_eth_address', [ string.toRaw(accountIdOrName), bool.toRaw(shouldDoBroadcastToNetwork), ]]); @@ -1064,7 +1064,7 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'withdraw_eth', [ + return this.wsProvider.call([0, 'withdraw_eth', [ string.toRaw(accountIdOrName), ethAddress.toRaw(ethOfAddress), uint64.toRaw(value), @@ -1079,7 +1079,7 @@ class WalletAPI { * @returns {Promise} */ floodNetwork(prefix, numberOfTransactions) { - return this.wsRpc.call([0, 'flood_network', [ + return this.wsProvider.call([0, 'flood_network', [ string.toRaw(prefix), uint32.toRaw(numberOfTransactions), ]]); @@ -1097,7 +1097,7 @@ class WalletAPI { if (!limit > API_CONFIG.LIST_ASSETS_MAX_LIMIT) { return Promise.reject(new Error(`Limit should be capped at ${API_CONFIG.LIST_ASSETS_MAX_LIMIT}`)); } - return this.wsRpc.call([0, 'list_assets', [assetId.toRaw(lowerBoundSymbol), uint32.toRaw(limit)]]); + return this.wsProvider.call([0, 'list_assets', [assetId.toRaw(lowerBoundSymbol), uint32.toRaw(limit)]]); } /** @@ -1123,7 +1123,7 @@ class WalletAPI { return Promise.reject(new Error('Accounts id or name should be string and valid')); } if (!isAssetName(symbol)) return Promise.reject(new Error('Assets symbol should be string and valid')); - return this.wsRpc.call([0, 'create_asset', [ + return this.wsProvider.call([0, 'create_asset', [ string.toRaw(accountIdOrName), string.toRaw(symbol), uint8.toRaw(precision), @@ -1154,7 +1154,7 @@ class WalletAPI { if (!isAccountIdOrName(newIssuerIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'update_asset', [ + return this.wsProvider.call([0, 'update_asset', [ string.toRaw(assetIdOrName), string.toRaw(newIssuerIdOrName), options.toRaw(newOptions), @@ -1176,7 +1176,7 @@ class WalletAPI { if (!isAssetIdOrName(assetIdOrName)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsRpc.call([0, 'update_bitasset', [ + return this.wsProvider.call([0, 'update_bitasset', [ string.toRaw(assetIdOrName), bitassetOptions.toRaw(newBitasset), bool.toRaw(shouldDoBroadcastToNetwork), @@ -1200,7 +1200,7 @@ class WalletAPI { if (!newFeedProducers.every((idOrName) => !!isAccountIdOrName(idOrName))) { return Promise.reject(new Error('Accounts should contain valid account names or ids')); } - return this.wsRpc.call([0, 'update_asset_feed_producers', [ + return this.wsProvider.call([0, 'update_asset_feed_producers', [ string.toRaw(assetIdOrName), vector(string).toRaw(newFeedProducers), bool.toRaw(shouldDoBroadcastToNetwork), @@ -1234,7 +1234,7 @@ class WalletAPI { if (!isAssetIdOrName(assetIdOrName)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsRpc.call([0, 'publish_asset_feed', [ + return this.wsProvider.call([0, 'publish_asset_feed', [ string.toRaw(accountIdOrName), string.toRaw(assetIdOrName), price.toRaw(coreEchangeRate), @@ -1255,7 +1255,7 @@ class WalletAPI { return Promise.reject(new Error('Accounts id or name should be string and valid')); } if (!isValidAmount(amount)) return Promise.reject(new Error('Invalid number')); - return this.wsRpc.call([0, 'issue_asset', [ + return this.wsProvider.call([0, 'issue_asset', [ string.toRaw(accountIdOrName), string.toRaw(amount), string.toRaw(assetTicker), @@ -1272,7 +1272,7 @@ class WalletAPI { if (!isAssetIdOrName(assetIdOrName)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsRpc.call([0, 'get_asset', [string.toRaw(assetIdOrName)]]); + return this.wsProvider.call([0, 'get_asset', [string.toRaw(assetIdOrName)]]); } /** @@ -1286,7 +1286,7 @@ class WalletAPI { if (!isAssetIdOrName(bitassetIdOrName)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsRpc.call([0, 'get_bitasset_data', [string.toRaw(bitassetIdOrName)]]); + return this.wsProvider.call([0, 'get_bitasset_data', [string.toRaw(bitassetIdOrName)]]); } /** @@ -1307,7 +1307,7 @@ class WalletAPI { if (!isAssetIdOrName(assetIdOrName)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsRpc.call([0, 'fund_asset_fee_pool', [ + return this.wsProvider.call([0, 'fund_asset_fee_pool', [ string.toRaw(fromAccountIdOrName), string.toRaw(assetIdOrName), string.toRaw(amount), @@ -1335,7 +1335,7 @@ class WalletAPI { if (!isAssetIdOrName(assetIdOrName)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsRpc.call([0, 'reserve_asset', [ + return this.wsProvider.call([0, 'reserve_asset', [ string.toRaw(accountIdOrName), string.toRaw(amount), string.toRaw(assetIdOrName), @@ -1353,7 +1353,7 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'get_committee_member', [string.toRaw(accountIdOrName)]]); + return this.wsProvider.call([0, 'get_committee_member', [string.toRaw(accountIdOrName)]]); } /** @@ -1374,7 +1374,7 @@ class WalletAPI { if (!limit > API_CONFIG.COMMITTEE_MEMBER_ACCOUNTS_MAX_LIMIT) { return Promise.reject(new Error(`Limit should be less ${API_CONFIG.COMMITTEE_MEMBER_ACCOUNTS_MAX_LIMIT}`)); } - return this.wsRpc.call([0, 'list_committee_members', [string.toRaw(lowerBoundName), uint64.toRaw(limit)]]); + return this.wsProvider.call([0, 'list_committee_members', [string.toRaw(lowerBoundName), uint64.toRaw(limit)]]); } /** @@ -1390,7 +1390,7 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'propose_parameter_change', [ + return this.wsProvider.call([0, 'propose_parameter_change', [ string.toRaw(accountIdOrName), timePointSec.toRaw(expirationTime), variantObject.toRaw(changeValues), @@ -1411,7 +1411,7 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'propose_fee_change', [ + return this.wsProvider.call([0, 'propose_fee_change', [ string.toRaw(accountIdOrName), timePointSec.toRaw(expirationTime), variantObject.toRaw(changedValues), @@ -1430,7 +1430,7 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'change_sidechain_config', [ + return this.wsProvider.call([0, 'change_sidechain_config', [ string.toRaw(accountIdOrName), config.toRaw(changedValues), bool.toRaw(shouldDoBroadcastToNetwork), @@ -1442,20 +1442,20 @@ class WalletAPI { * @param {number} blockNum height of the block to retrieve * @return {Promise} info about the block, or undefined if not found */ - getBlock(blockNum) { return this.wsRpc.call([0, 'get_block', [uint32.toRaw(blockNum)]]); } + getBlock(blockNum) { return this.wsProvider.call([0, 'get_block', [uint32.toRaw(blockNum)]]); } /** * Returns block virtual ops by number * @param {number} blockNum height of the block to retrieve * @return {Promise} info about operation history object */ - getBlockVirtualOps(blockNum) { return this.wsRpc.call([0, 'get_block_virtual_ops', [uint32.toRaw(blockNum)]]); } + getBlockVirtualOps(blockNum) { return this.wsProvider.call([0, 'get_block_virtual_ops', [uint32.toRaw(blockNum)]]); } /** * Returns the number of accounts registered on the blockchain. * @return {Promise} the number of registered accounts */ - getAccountCount() { return this.wsRpc.call([0, 'get_account_count', []]); } + getAccountCount() { return this.wsProvider.call([0, 'get_account_count', []]); } /** * Returns the block chain's slowly-changing settings. @@ -1464,7 +1464,7 @@ class WalletAPI { * @see {@link WalletAPI['getDynamicGlobalProperties']} for frequently changing properties * @return {Promise} the global properties */ - getGlobalProperties() { return this.wsRpc.call([0, 'get_global_properties', []]); } + getGlobalProperties() { return this.wsProvider.call([0, 'get_global_properties', []]); } /** * Returns the block chain's rapidly-changing properties. @@ -1473,7 +1473,7 @@ class WalletAPI { * @see {@link WalletAPI['getGlobalProperties']} for less-frequently changing properties * @return {Promise} the dynamic global properties */ - getDynamicGlobalProperties() { return this.wsRpc.call([0, 'get_dynamic_global_properties', []]); } + getDynamicGlobalProperties() { return this.wsProvider.call([0, 'get_dynamic_global_properties', []]); } /** * Returns the blockchain object corresponding to the given id. @@ -1481,13 +1481,13 @@ class WalletAPI { * @param {string} objectId the id of the object to return * @returns {Promise} the requested object */ - getObject(objectId) { return this.wsRpc.call([0, 'get_object', [anyObjectId.toRaw(objectId)]]); } + getObject(objectId) { return this.wsProvider.call([0, 'get_object', [anyObjectId.toRaw(objectId)]]); } /** * Create a new transaction builder. * @returns {Promise} handle of the new transaction builder */ - beginBuilderTransaction() { return this.wsRpc.call([0, 'begin_builder_transaction', []]); } + beginBuilderTransaction() { return this.wsProvider.call([0, 'begin_builder_transaction', []]); } /** * Append a new operation to a transaction builder. @@ -1496,7 +1496,7 @@ class WalletAPI { * @returns {Promise} */ addOperationToBuilderTransaction(transactionTypeHandle, newOperation) { - return this.wsRpc.call([0, 'add_operation_to_builder_transaction', [ + return this.wsProvider.call([0, 'add_operation_to_builder_transaction', [ uint16.toRaw(transactionTypeHandle), operation.toRaw(newOperation), ]]); @@ -1510,7 +1510,7 @@ class WalletAPI { * @returns {Promise} */ replaceOperationInBuilderTransaction(transactionTypeHandle, unsignedOperation, newOperation) { - return this.wsRpc.call([0, 'replace_operation_in_builder_transaction', [ + return this.wsProvider.call([0, 'replace_operation_in_builder_transaction', [ uint16.toRaw(transactionTypeHandle), uint64.toRaw(unsignedOperation), operation.toRaw(newOperation), @@ -1527,7 +1527,7 @@ class WalletAPI { if (!isAssetIdOrName(feeAsset)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsRpc.call([0, 'set_fees_on_builder_transaction', [ + return this.wsProvider.call([0, 'set_fees_on_builder_transaction', [ uint16.toRaw(transactionTypeHandle), string.toRaw(feeAsset), ]]); @@ -1539,7 +1539,7 @@ class WalletAPI { * @returns {Promise} a transaction */ previewBuilderTransaction(transactionTypeHandle) { - return this.wsRpc.call([0, 'preview_builder_transaction', [uint64.toRaw(transactionTypeHandle)]]); + return this.wsProvider.call([0, 'preview_builder_transaction', [uint64.toRaw(transactionTypeHandle)]]); } /** @@ -1549,7 +1549,7 @@ class WalletAPI { * @returns {Promise} a signed transaction */ signBuilderTransaction(transactionTypeHandle, shouldDoBroadcastToNetwork) { - return this.wsRpc.call([0, 'sign_builder_transaction', [ + return this.wsProvider.call([0, 'sign_builder_transaction', [ uint16.toRaw(transactionTypeHandle), bool.toRaw(shouldDoBroadcastToNetwork), ]]); @@ -1566,7 +1566,7 @@ class WalletAPI { * @returns {Promise} a signed transaction */ proposeBuilderTransaction(transactionTypeHandle, expirationTime, reviewPeriod, shouldDoBroadcastToNetwork) { - return this.wsRpc.call([0, 'propose_builder_transaction', [ + return this.wsProvider.call([0, 'propose_builder_transaction', [ uint16.toRaw(transactionTypeHandle), timePointSec.toRaw(expirationTime), uint32.toRaw(reviewPeriod), @@ -1595,7 +1595,7 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsRpc.call([0, 'propose_builder_transaction2', [ + return this.wsProvider.call([0, 'propose_builder_transaction2', [ uint16.toRaw(transactionTypeHandle), string.toRaw(accountIdOrName), timePointSec.toRaw(expirationTime), @@ -1610,7 +1610,7 @@ class WalletAPI { * @returns {Promise} */ removeBuilderTransaction(transactionTypeHandle) { - return this.wsRpc.call([0, 'remove_builder_transaction', [uint16.toRaw(transactionTypeHandle)]]); + return this.wsProvider.call([0, 'remove_builder_transaction', [uint16.toRaw(transactionTypeHandle)]]); } /** @@ -1619,7 +1619,7 @@ class WalletAPI { * @returns {Promise} the binary form of the transaction. It will not be hex encoded, * this returns a raw string that may have null characters embedded in it */ - serializeTransaction(tr) { return this.wsRpc.call([0, 'serialize_transaction', [signedTransaction.toRaw(tr)]]); } + serializeTransaction(tr) { return this.wsProvider.call([0, 'serialize_transaction', [signedTransaction.toRaw(tr)]]); } /** * Signs a transaction. @@ -1630,7 +1630,7 @@ class WalletAPI { * @returns {Promise} the signed version of the transaction */ signTransaction(tr, shouldDoBroadcastToNetwork) { - return this.wsRpc.call([0, 'sign_transaction', [ + return this.wsProvider.call([0, 'sign_transaction', [ transaction.toRaw(tr), bool.toRaw(shouldDoBroadcastToNetwork), ]]); @@ -1650,7 +1650,7 @@ class WalletAPI { if (!isOperationPrototypeExists(operationType)) { return Promise.reject(new Error('This operation does not exists')); } - return this.wsRpc.call([0, 'get_prototype_operation', [string.toRaw(operationType)]]); + return this.wsProvider.call([0, 'get_prototype_operation', [string.toRaw(operationType)]]); } /* @@ -1667,7 +1667,7 @@ class WalletAPI { if (!isBoolean(shouldDoBroadcastToNetwork)) return Promise.reject(new Error('broadcast should be a boolean')); - return this.wsRpc.call([0, 'generate_btc_deposit_address', + return this.wsProvider.call([0, 'generate_btc_deposit_address', [accountIdOrName, backupAddress, shouldDoBroadcastToNetwork], ]); } @@ -1680,7 +1680,7 @@ class WalletAPI { getBtcAddress(account) { if (!isAccountId(account) || !isAccountName(account)) throw new Error('account should be valid'); - return this.wsRpc.call([0, 'get_btc_address', [account]]); + return this.wsProvider.call([0, 'get_btc_address', [account]]); } /** @@ -1689,7 +1689,7 @@ class WalletAPI { * @returns {Promise} */ getBtcDepositScript(btcDepositAddress) { - return this.wsRpc.call([0, 'get_btc_deposit_script', [btcDepositAddress]]); + return this.wsProvider.call([0, 'get_btc_deposit_script', [btcDepositAddress]]); } /** @@ -1708,7 +1708,7 @@ class WalletAPI { if (!isUInt64(amount)) return Promise.reject(new Error('amount should be a non negative integer')); if (!isBoolean(shouldDoBroadcastToNetwork)) return Promise.reject(new Error('broadcast should be a boolean')); - return this.wsRpc.call([0, 'withdraw_btc', + return this.wsProvider.call([0, 'withdraw_btc', [accountIdOrName, addressToWithdraw, amount, shouldDoBroadcastToNetwork], ]); } @@ -1726,7 +1726,7 @@ class WalletAPI { if (!isPublicKey(activeKey)) return Promise.reject(new Error('active key is invalid')); if (!isPublicKey(echorandKey)) return Promise.reject(new Error('echorand key is invalid')); - return this.wsRpc.call([0, 'register_account_with_api', [name, activeKey, echorandKey, evmAddress]]); + return this.wsProvider.call([0, 'register_account_with_api', [name, activeKey, echorandKey, evmAddress]]); } /** @@ -1739,7 +1739,7 @@ class WalletAPI { return Promise.reject(new Error('Account name or id is invalid')); } - return this.wsRpc.call([0, 'list_frozen_balances', [accountNameOrId]]); + return this.wsProvider.call([0, 'list_frozen_balances', [accountNameOrId]]); } /** @@ -1765,7 +1765,7 @@ class WalletAPI { if (!isUInt64(duration)) return Promise.reject(new Error('duration should be a non negative integer')); if (!isBoolean(shouldDoBroadcastToNetwork)) return Promise.reject(new Error('Broadcast should be a boolean')); - return this.wsRpc.call([0, 'freeze_balance', + return this.wsProvider.call([0, 'freeze_balance', [fromAccountNameOrId, amount, assetIdOrName, duration, shouldDoBroadcastToNetwork], ]); } @@ -1780,7 +1780,7 @@ class WalletAPI { return Promise.reject(new Error('Account name or id is invalid')); } - return this.wsRpc.call([0, 'get_committee_frozen_balance', [string.toRaw(ownerAccount)]]); + return this.wsProvider.call([0, 'get_committee_frozen_balance', [string.toRaw(ownerAccount)]]); } @@ -1795,7 +1795,7 @@ class WalletAPI { if (!isAccountIdOrName(ownerAccount)) return Promise.reject(new Error('Account name or id is invalid')); if (!isValidAmount(amount)) return Promise.reject(new Error('Invalid amount')); - return this.wsRpc.call([0, 'committee_freeze_balance', [ + return this.wsProvider.call([0, 'committee_freeze_balance', [ string.toRaw(ownerAccount), string.toRaw(amount), bool.toRaw(broadcast), @@ -1813,7 +1813,7 @@ class WalletAPI { if (!isAccountIdOrName(ownerAccount)) return Promise.reject(new Error('Account name or id is invalid')); if (!isValidAmount(amount)) return Promise.reject(new Error('Invalid amount')); - return this.wsRpc.call([0, 'committee_withdraw_balance', [ + return this.wsProvider.call([0, 'committee_withdraw_balance', [ string.toRaw(ownerAccount), string.toRaw(amount), bool.toRaw(broadcast), @@ -1832,7 +1832,7 @@ class WalletAPI { if (!isAccountIdOrName(sender)) return Promise.reject(new Error('Account name or id is invalid')); if (!isCommitteeMemberId(committeeToActivate)) return Promise.reject(new Error('Invalid committee member id')); - return this.wsRpc.call([0, 'create_activate_committee_member_proposal', [ + return this.wsProvider.call([0, 'create_activate_committee_member_proposal', [ accountId.toRaw(sender), committeeMemberId.toRaw(committeeToActivate), timePointSec.toRaw(expirationTime), @@ -1854,7 +1854,7 @@ class WalletAPI { return Promise.reject(new Error('Invalid committee member id')); } - return this.wsRpc.call([0, 'create_deactivate_committee_member_proposal', [ + return this.wsProvider.call([0, 'create_deactivate_committee_member_proposal', [ accountId.toRaw(sender), committeeMemberId.toRaw(committeeTodeactivate), timePointSec.toRaw(expirationTime), @@ -1877,7 +1877,7 @@ class WalletAPI { return Promise.reject(new Error('Url should be string and valid')); } - return this.wsRpc.call([0, 'update_committee_member', [ + return this.wsProvider.call([0, 'update_committee_member', [ accountId.toRaw(ownerAccount), string.toRaw(newUrl), string.toRaw(newEthAddress), @@ -1902,7 +1902,7 @@ class WalletAPI { } if (!isValidAmount(amount)) return Promise.reject(new Error('Invalid number')); - return this.wsRpc.call([0, 'create_committee_member', [ + return this.wsProvider.call([0, 'create_committee_member', [ accountId.toRaw(ownerAccount), string.toRaw(url), string.toRaw(amount), diff --git a/test/wallet-api.test.js b/test/wallet-api.test.js index 172b0e9a..4b0f7958 100644 --- a/test/wallet-api.test.js +++ b/test/wallet-api.test.js @@ -19,7 +19,7 @@ import { TRANSFER } from '../src/constants/operations-ids'; import PrivateKey from '../src/crypto/private-key'; import { bytecode } from './operations/_contract.test'; -describe.skip('WALLET API', () => { +describe('WALLET API', () => { const shouldDoBroadcastToNetwork = false; const brainKey = 'some key12'; From 60d040d4e7c6595c5a64e10e43b89d42ad9e68be Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 13 Apr 2020 20:21:07 +0300 Subject: [PATCH 54/62] [ECHOJS-249] Done --- src/echo/apis/wallet-api.js | 362 +++++++++++++++++++----------------- 1 file changed, 189 insertions(+), 173 deletions(-) diff --git a/src/echo/apis/wallet-api.js b/src/echo/apis/wallet-api.js index e1f02066..a3f8c7f7 100644 --- a/src/echo/apis/wallet-api.js +++ b/src/echo/apis/wallet-api.js @@ -1,6 +1,5 @@ import * as serializers from '../../serializers'; import { API_CONFIG } from '../../constants'; -import WsProvider from '../providers/WsProvider'; import { isAccountId, isAccountIdOrName, @@ -21,6 +20,7 @@ import { isCommitteeMemberId, validateAmount, } from '../../utils/validators'; +import { HttpProvider, WsProvider, ConnectionType } from '../providers'; const { ethAddress, accountListing } = serializers.protocol; const { vector, optional } = serializers.collections; @@ -80,7 +80,17 @@ const { class WalletAPI { - constructor() { this.wsProvider = new WsProvider(); } + get provider() { + if (this._provider === null) throw new Error('Wallet api not connected'); + return this._provider; + } + + constructor() { this._provider = null; } + + async _call(method, params) { + if (this.provider.connectionType === ConnectionType.WS) return this.provider.call([0, method, params]); + return this.provider.call(method, params); + } /** * Init params and connect to chain. @@ -88,13 +98,19 @@ class WalletAPI { * @param {Parameters1} connectionOptions connection params. * @returns {Promise} */ - async connect(url, connectionOptions) { await this.wsProvider.connect(url, connectionOptions); } + async connect(url, connectionOptions) { + if (url.startsWith('ws')) { + this._provider = new WsProvider(); + await this.provider.connect(url, connectionOptions); + } else if (url.startsWith('http')) this._provider = new HttpProvider(url); + else throw new Error('invalid url format'); + } /** * Exit from current wallet. * @returns {Promise} */ - exit() { return this.wsProvider.call([0, 'exit', []]); } + exit() { return this._call('exit', []); } /** * Returns a list of all commands supported by the wallet API. @@ -102,7 +118,7 @@ class WalletAPI { * For more detailed help on a single command, use `get_help()` * @returns {Promise} a multi-line string suitable for displaying on a terminal */ - help() { return this.wsProvider.call([0, 'help', []]); } + help() { return this._call('help', []); } /** * Returns detailed help on a single API command. @@ -111,7 +127,7 @@ class WalletAPI { */ helpMethod(method) { if (!isMethodExists(method)) return Promise.reject(new Error('This method does not exists')); - return this.wsProvider.call([0, 'help_method', [string.toRaw(method)]]); + return this._call('help_method', [string.toRaw(method)]); } /** @@ -119,46 +135,46 @@ class WalletAPI { * current active witnesses and committee members. * @returns {Promise} runtime info about the blockchain */ - info() { return this.wsProvider.call([0, 'info', []]); } + info() { return this._call('info', []); } /** * Returns info such as client version, git version of graphene/fc, version of boost, openssl. * @returns {Promise} compile time info and client and dependencies versions */ - about() { return this.wsProvider.call([0, 'about', []]); } + about() { return this._call('about', []); } /** * Add nodes to the network * @param {string} nodes nodes for adding * @returns {Promise} */ - networkAddNodes(nodes) { return this.wsProvider.call([0, 'network_add_nodes', [vector(string).toRaw(nodes)]]); } + networkAddNodes(nodes) { return this._call('network_add_nodes', [vector(string).toRaw(nodes)]); } /** * Get peers connected to network. * @returns {Promise} peers connected to network */ - networkGetConnectedPeers() { return this.wsProvider.call([0, 'network_get_connected_peers', []]); } + networkGetConnectedPeers() { return this._call('network_get_connected_peers', []); } /** * Checks whether the wallet has just been created and has not yet had a password set. * Calling `set_password` will transition the wallet to the locked state. * @returns {Promise} true if the wallet is new */ - isNew() { return this.wsProvider.call([0, 'is_new', []]); } + isNew() { return this._call('is_new', []); } /** * Checks whether the wallet is locked (is unable to use its private keys). * This state can be changed by calling `lock()` or `unlock()`. * @returns {Promise} true if the wallet is locked */ - isLocked() { return this.wsProvider.call([0, 'is_locked', []]); } + isLocked() { return this._call('is_locked', []); } /** * Locks the wallet immediately. * @returns {Promise} */ - lock() { return this.wsProvider.call([0, 'lock', []]); } + lock() { return this._call('lock', []); } /** * Unlocks the wallet. @@ -167,7 +183,7 @@ class WalletAPI { * in the wallet it should be input interactively * @returns {Promise} */ - unlock(password) { return this.wsProvider.call([0, 'unlock', [string.toRaw(password)]]); } + unlock(password) { return this._call('unlock', [string.toRaw(password)]); } /** * Sets a new password on the wallet. @@ -175,20 +191,20 @@ class WalletAPI { * @param {string} password the password, should be input automatically in the wallet * @returns {Promise} */ - setPassword(password) { return this.wsProvider.call([0, 'set_password', [string.toRaw(password)]]); } + setPassword(password) { return this._call('set_password', [string.toRaw(password)]); } /** * Create new EdDSA keypair encoded in base58. * @returns {Promise<[string, string]>} new private and public key */ - createEddsaKeypair() { return this.wsProvider.call([0, 'create_eddsa_keypair', []]); } + createEddsaKeypair() { return this._call('create_eddsa_keypair', []); } /** * Dumps all private keys owned by the wallet. * The keys are printed in WIF format. You can import these keys into another wallet using `import_key()` * @returns {Promise<[string, string][]>} a map containing the private keys, indexed by their public key */ - dumpPrivateKeys() { return this.wsProvider.call([0, 'dump_private_keys', []]); } + dumpPrivateKeys() { return this._call('dump_private_keys', []); } /** * Imports the private key for an existing account. @@ -202,7 +218,7 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'import_key', [string.toRaw(accountNameOrId), privateKey.toRaw(privateKeyWif)]]); + return this._call('import_key', [string.toRaw(accountNameOrId), privateKey.toRaw(privateKeyWif)]); } /** @@ -212,7 +228,7 @@ class WalletAPI { * @returns {[string, boolean][]} a map containing the accounts found and whether imported */ importAccounts(filename, password) { - return this.wsProvider.call([0, 'import_accounts', [string.toRaw(filename), string.toRaw(password)]]); + return this._call('import_accounts', [string.toRaw(filename), string.toRaw(password)]); } /** @@ -233,12 +249,12 @@ class WalletAPI { if (!isAccountName(destAccountName)) { return Promise.reject(new Error('destAccount name should be string and valid')); } - return this.wsProvider.call([0, 'import_account_keys', [ + return this._call('import_account_keys', [ string.toRaw(filename), string.toRaw(password), string.toRaw(srcAccountName), string.toRaw(destAccountName), - ]]); + ]); } /** @@ -253,11 +269,11 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'import_balance', [ + return this._call('import_balance', [ string.toRaw(accountNameOrId), bool.toRaw(shouldDoBroadcastToNetwork), vector(privateKey).toRaw(wifKeys), - ]]); + ]); } /** @@ -267,7 +283,7 @@ class WalletAPI { * (and, with effort, memorize). * @returns {Promise} a suggested brain_key */ - suggestBrainKey() { return this.wsProvider.call([0, 'suggest_brain_key', []]); } + suggestBrainKey() { return this._call('suggest_brain_key', []); } /** * Derive any number of *possible* owner keys from a given brain key. @@ -280,10 +296,10 @@ class WalletAPI { */ deriveKeysFromBrainKey(brainKey, numberOfDesiredKeys) { if (numberOfDesiredKeys < 1) return Promise.reject(new Error('Number should be positive integer')); - return this.wsProvider.call([0, 'derive_keys_from_brain_key', [ + return this._call('derive_keys_from_brain_key', [ string.toRaw(brainKey), int64.toRaw(numberOfDesiredKeys), - ]]); + ]); } /** @@ -293,7 +309,7 @@ class WalletAPI { * @returns {Promise} Whether a public key is known */ isPublicKeyRegistered(accountPublicKey) { - return this.wsProvider.call([0, 'is_public_key_registered', [publicKey.toRaw(accountPublicKey)]]); + return this._call('is_public_key_registered', [publicKey.toRaw(accountPublicKey)]); } /** @@ -301,7 +317,7 @@ class WalletAPI { * @param {any} tr the singed transaction * @returns {Promise} transaction id string */ - getTransactionId(tr) { return this.wsProvider.call([0, 'get_transaction_id', [signedTransaction.toRaw(tr)]]); } + getTransactionId(tr) { return this._call('get_transaction_id', [signedTransaction.toRaw(tr)]); } /** * Get the WIF private key corresponding to a public key. The private key must already be in the wallet. @@ -309,7 +325,7 @@ class WalletAPI { * @returns {Promise} private key of this account */ getPrivateKey(accountPublicKey) { - return this.wsProvider.call([0, 'get_private_key', [publicKey.toRaw(accountPublicKey)]]); + return this._call('get_private_key', [publicKey.toRaw(accountPublicKey)]); } /** @@ -321,7 +337,7 @@ class WalletAPI { * If `wallet_filename` is empty, it reloads the existing wallet file * @returns {Promise} true if the specified wallet is loaded */ - loadWalletFile(walletFilename) { return this.wsProvider.call([0, 'load_wallet_file', [string.toRaw(walletFilename)]]); } + loadWalletFile(walletFilename) { return this._call('load_wallet_file', [string.toRaw(walletFilename)]); } /** * Transforms a brain key to reduce the chance of errors when re-entering the key from memory. @@ -330,7 +346,7 @@ class WalletAPI { * @param {string} brainKey the brain key as supplied by the user * @returns {Promise} the brain key in its normalized form */ - normalizeBrainKey(brainKey) { return this.wsProvider.call([0, 'normalize_brain_key', [string.toRaw(brainKey)]]); } + normalizeBrainKey(brainKey) { return this._call('normalize_brain_key', [string.toRaw(brainKey)]); } /** * Saves the current wallet to the given filename. @@ -342,14 +358,14 @@ class WalletAPI { * If `wallet_filename` is empty, save to the current filename * @returns {Promise} */ - saveWalletFile(walletFilename) { return this.wsProvider.call([0, 'save_wallet_file', [string.toRaw(walletFilename)]]); } + saveWalletFile(walletFilename) { return this._call('save_wallet_file', [string.toRaw(walletFilename)]); } /** * Lists all accounts controlled by this wallet. * This returns a list of the full account objects for all accounts whose private keys we possess. * @returns {Promise} a list of account objects */ - listMyAccounts() { return this.wsProvider.call([0, 'list_my_accounts', []]); } + listMyAccounts() { return this._call('list_my_accounts', []); } /** * Lists all accounts registered in the blockchain. @@ -367,7 +383,7 @@ class WalletAPI { if (!limit > API_CONFIG.LIST_ACCOUNTS_MAX_LIMIT) { return Promise.reject(new Error(`Limit should be capped at ${API_CONFIG.LIST_ACCOUNTS_MAX_LIMIT}`)); } - return this.wsProvider.call([0, 'list_accounts', [string.toRaw(lowerbound), uint32.toRaw(limit)]]); + return this._call('list_accounts', [string.toRaw(lowerbound), uint32.toRaw(limit)]); } /** @@ -379,7 +395,7 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'list_account_balances', [string.toRaw(accountNameOrId)]]); + return this._call('list_account_balances', [string.toRaw(accountNameOrId)]); } /** @@ -387,7 +403,7 @@ class WalletAPI { * @param {string} idOfAccount id the id of either an account or a contract * @returns {Promise} a list of the given account/contract balances */ - listIdBalances(idOfAccount) { return this.wsProvider.call([0, 'list_id_balances', [accountId.toRaw(idOfAccount)]]); } + listIdBalances(idOfAccount) { return this._call('list_id_balances', [accountId.toRaw(idOfAccount)]); } /** * Registers a third party's account on the blockckain. @@ -408,12 +424,12 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'register_account', [ + return this._call('register_account', [ string.toRaw(name), publicKey.toRaw(activeKey), string.toRaw(accountNameOrId), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -434,13 +450,13 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'create_account_with_brain_key', [ + return this._call('create_account_with_brain_key', [ string.toRaw(brainKey), string.toRaw(accountName), string.toRaw(accountNameOrId), evmAddress, bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -468,7 +484,7 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) throw new Error('Accounts id or name should be string and valid'); if (!isContractCode(contractCode)) throw new Error('Byte code should be string and valid'); amount = validateAmount(amount); - return this.wsProvider.call([0, 'create_contract', [ + return this._call('create_contract', [ string.toRaw(accountNameOrId), string.toRaw(contractCode), string.toRaw(amount), @@ -476,7 +492,7 @@ class WalletAPI { assetId.toRaw(supportedAssetId), bool.toRaw(useEthereumAssetAccuracy), bool.toRaw(shouldSaveToWallet), - ]]); + ]); } /** @@ -500,14 +516,14 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) throw new Error('Accounts id or name should be string and valid'); if (!isContractCode(contractCode)) throw new Error('Byte code should be string and valid'); amount = validateAmount(amount); - return this.wsProvider.call([0, 'call_contract', [ + return this._call('call_contract', [ string.toRaw(accountNameOrId), contractId.toRaw(idOfContract), string.toRaw(contractCode), string.toRaw(amount), assetId.toRaw(assetType), bool.toRaw(shouldSaveToWallet), - ]]); + ]); } /** @@ -522,12 +538,12 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'contract_fund_fee_pool', [ + return this._call('contract_fund_fee_pool', [ string.toRaw(accountNameOrId), contractId.toRaw(idOfContract), uint64.toRaw(amount), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -539,7 +555,7 @@ class WalletAPI { if (!isContractResultId(contractResultId)) { return Promise.reject(new Error('Contract resultId should be string and valid')); } - return this.wsProvider.call([0, 'get_contract_result', [string.toRaw(contractResultId)]]); + return this._call('get_contract_result', [string.toRaw(contractResultId)]); } /** @@ -551,7 +567,7 @@ class WalletAPI { * @returns {Promise} a list of accounts mapping account names to account ids */ async getContractHistory(_contractId, limit) { - return this.wsProvider.call([0, 'get_contract_history', [contractId.toRaw(_contractId), uint32.toRaw(limit)]]); + return this._call('get_contract_history', [contractId.toRaw(_contractId), uint32.toRaw(limit)]); } /** @@ -563,12 +579,12 @@ class WalletAPI { * @returns {Promise} a list of operation history objects */ async getRelativeContractHistory(_contractId, stop, limit, start) { - return this.wsProvider.call([0, 'get_relative_contract_history', [ + return this._call('get_relative_contract_history', [ contractId.toRaw(_contractId), uint32.toRaw(stop), uint32.toRaw(limit), uint32.toRaw(start), - ]]); + ]); } /** @@ -591,13 +607,13 @@ class WalletAPI { if (!isAssetIdOrName(assetIdOrName)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsProvider.call([0, 'transfer', [ + return this._call('transfer', [ string.toRaw(fromAccountNameOrId), string.toRaw(toAccountNameOrId), string.toRaw(amount), string.toRaw(assetIdOrName), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -620,12 +636,12 @@ class WalletAPI { if (!isAssetIdOrName(assetIdOrName)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsProvider.call([0, 'transfer2', [ + return this._call('transfer2', [ string.toRaw(fromAccountNameOrId), string.toRaw(toAccountNameOrId), string.toRaw(amount), string.toRaw(assetIdOrName), - ]]); + ]); } /** @@ -654,12 +670,12 @@ class WalletAPI { if (!isAccountIdOrName(accountToList)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'whitelist_account', [ + return this._call('whitelist_account', [ string.toRaw(authorizingAccount), string.toRaw(accountToList), accountListing.toRaw(newListingStatus), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -671,7 +687,7 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'get_vesting_balances', [string.toRaw(accountNameOrId)]]); + return this._call('get_vesting_balances', [string.toRaw(accountNameOrId)]); } /** @@ -690,12 +706,12 @@ class WalletAPI { if (!isValidAmount(amount)) { return Promise.reject(new Error('Invalid amount')); } - return this.wsProvider.call([0, 'withdraw_vesting', [ + return this._call('withdraw_vesting', [ string.toRaw(witnessAccountNameOrId), string.toRaw(amount), string.toRaw(assetSymbol), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -707,7 +723,7 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'get_account', [string.toRaw(accountNameOrId)]]); + return this._call('get_account', [string.toRaw(accountNameOrId)]); } /** @@ -717,7 +733,7 @@ class WalletAPI { */ getAccountId(accountName) { if (!isAccountName(accountName)) return Promise.reject(new Error('Account name should be string and valid')); - return this.wsProvider.call([0, 'get_account_id', [string.toRaw(accountName)]]); + return this._call('get_account_id', [string.toRaw(accountName)]); } /** @@ -734,7 +750,7 @@ class WalletAPI { if (!limit > API_CONFIG.ACCOUNT_HISTORY_MAX_LIMIT) { return Promise.reject(new Error(`Limit should be capped at ${API_CONFIG.ACCOUNT_HISTORY_MAX_LIMIT}`)); } - return this.wsProvider.call([0, 'get_account_history', [string.toRaw(accountIdOrName), int64.toRaw(limit)]]); + return this._call('get_account_history', [string.toRaw(accountIdOrName), int64.toRaw(limit)]); } /** @@ -757,11 +773,11 @@ class WalletAPI { if (!limit > API_CONFIG.RELATIVE_ACCOUNT_HISTORY_MAX_LIMIT) { return Promise.reject(new Error(`Limit should be less ${API_CONFIG.RELATIVE_ACCOUNT_HISTORY_MAX_LIMIT}`)); } - return this.wsProvider.call([0, 'get_relative_account_history', [ + return this._call('get_relative_account_history', [ string.toRaw(accountIdOrName), uint64.toRaw(stop), int64.toRaw(limit), uint64.toRaw(start), - ]]); + ]); } /** @@ -770,7 +786,7 @@ class WalletAPI { * @returns {Promise} the contract object */ getContractObject(idOfContract) { - return this.wsProvider.call([0, 'get_contract_object', [contractId.toRaw(idOfContract)]]); + return this._call('get_contract_object', [contractId.toRaw(idOfContract)]); } /** @@ -778,7 +794,7 @@ class WalletAPI { * @param {string} idOfContract id of the contract * @returns {Promise} the contract information */ - getContract(idOfContract) { return this.wsProvider.call([0, 'get_contract', [contractId.toRaw(idOfContract)]]); } + getContract(idOfContract) { return this._call('get_contract', [contractId.toRaw(idOfContract)]); } /** * Whitelist or blacklist contract pool. @@ -805,7 +821,7 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'whitelist_contract_pool', [ + return this._call('whitelist_contract_pool', [ string.toRaw(accountIdOrName), contractId.toRaw(idOfContract), vector(accountId).toRaw(addToWhitelist), @@ -813,7 +829,7 @@ class WalletAPI { vector(accountId).toRaw(removeFromWhitelist), vector(accountId).toRaw(removeFromBlacklist), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -832,13 +848,13 @@ class WalletAPI { if (!isContractCode(codeOfTheContract)) { return Promise.reject(new Error('Byte code should be string and valid')); } - return this.wsProvider.call([0, 'call_contract_no_changing_state', [ + return this._call('call_contract_no_changing_state', [ contractId.toRaw(idOfContract), string.toRaw(caller), string.toRaw(amount), string.toRaw(assetType), string.toRaw(codeOfTheContract), - ]]); + ]); } /** @@ -847,7 +863,7 @@ class WalletAPI { * @returns {Promise} contract's feepool balance */ getContractPoolBalance(idOfContract) { - return this.wsProvider.call([0, 'get_contract_pool_balance', [contractId.toRaw(idOfContract)]]); + return this._call('get_contract_pool_balance', [contractId.toRaw(idOfContract)]); } /** @@ -856,7 +872,7 @@ class WalletAPI { * @returns {Promise} whitelist and blacklist of contract pool object */ getContractPoolWhitelist(idOfContract) { - return this.wsProvider.call([0, 'get_contract_pool_whitelist', [contractId.toRaw(idOfContract)]]); + return this._call('get_contract_pool_whitelist', [contractId.toRaw(idOfContract)]); } /** @@ -864,7 +880,7 @@ class WalletAPI { * @param {string} idOfAccount the id of the account to provide information about * @returns {Promise} the public eth address data stored in the blockchain */ - getEthAddress(idOfAccount) { return this.wsProvider.call([0, 'get_eth_address', [accountId.toRaw(idOfAccount)]]); } + getEthAddress(idOfAccount) { return this._call('get_eth_address', [accountId.toRaw(idOfAccount)]); } /** * Returns all approved deposits, for the given account id. @@ -873,7 +889,7 @@ class WalletAPI { * @returns {Promise} the all public deposits data stored in the blockchain */ getAccountDeposits(idOfAccount, type) { - return this.wsProvider.call([0, 'get_account_deposits', [accountId.toRaw(idOfAccount), type]]); + return this._call('get_account_deposits', [accountId.toRaw(idOfAccount), type]); } /** @@ -899,14 +915,14 @@ class WalletAPI { } if (!isNotEmptyString(tokenName)) return Promise.reject(new Error('Name should be string and valid')); if (!isNotEmptyString(tokenSymbol)) return Promise.reject(new Error('Name should be string and valid')); - return this.wsProvider.call([0, 'register_erc20_token', [ + return this._call('register_erc20_token', [ string.toRaw(accountIdOrName), ethAddress.toRaw(ethereumTokenAddress), string.toRaw(tokenName), string.toRaw(tokenSymbol), uint8.toRaw(decimals), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -915,7 +931,7 @@ class WalletAPI { * @returns {Promise} the public erc20 token data stored in the blockchain */ getErc20Token(ethereumTokenAddress) { - return this.wsProvider.call([0, 'get_erc20_token', [ethAddress.toRaw(ethereumTokenAddress)]]); + return this._call('get_erc20_token', [ethAddress.toRaw(ethereumTokenAddress)]); } /** @@ -924,7 +940,7 @@ class WalletAPI { * @returns {Promise} true if erc20 token data stored in the blockchain, else false */ checkErc20Token(idOfContract) { - return this.wsProvider.call([0, 'check_erc20_token', [contractId.toRaw(idOfContract)]]); + return this._call('check_erc20_token', [contractId.toRaw(idOfContract)]); } /** @@ -933,7 +949,7 @@ class WalletAPI { * @returns {Promise} the all public erc20 deposits data stored in the blockchain */ getErc20AccountDeposits(idOfAccount) { - return this.wsProvider.call([0, 'get_erc20_account_deposits', [accountId.toRaw(idOfAccount)]]); + return this._call('get_erc20_account_deposits', [accountId.toRaw(idOfAccount)]); } /** @@ -942,7 +958,7 @@ class WalletAPI { * @returns {Promise} the all public erc20 withdrawals data stored in the blockchain */ getErc20AccountWithdrawals(idOfAccount) { - return this.wsProvider.call([0, 'get_erc20_account_withdrawals', [accountId.toRaw(idOfAccount)]]); + return this._call('get_erc20_account_withdrawals', [accountId.toRaw(idOfAccount)]); } /** @@ -958,13 +974,13 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'withdraw_erc20_token', [ + return this._call('withdraw_erc20_token', [ string.toRaw(accountIdOrName), ethAddress.toRaw(toEthereumAddress), erc20TokenId.toRaw(idOferc20Token), uint256.toRaw(withdrawAmount), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -979,11 +995,11 @@ class WalletAPI { return Promise.reject(new Error('Accounts id or name should be string and valid')); } if (!isNotEmptyString(label)) return Promise.reject(new Error('Label should be string and valid')); - return this.wsProvider.call([0, 'generate_account_address', [ + return this._call('generate_account_address', [ string.toRaw(accountIdOrName), string.toRaw(label), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -994,11 +1010,11 @@ class WalletAPI { * @returns {Promise} Addresses owned by account in specified ids interval */ getAccountAddresses(idOfAccount, startFrom, limit) { - return this.wsProvider.call([0, 'get_account_addresses', [ + return this._call('get_account_addresses', [ accountId.toRaw(idOfAccount), uint64.toRaw(startFrom), uint64.toRaw(limit), - ]]); + ]); } /** @@ -1006,7 +1022,7 @@ class WalletAPI { * @param {string} address address in form of ripemd160 hash * @returns {Promise} Account id of owner */ - getAccountByAddress(address) { return this.wsProvider.call([0, 'get_account_by_address', [ripemd160.toRaw(address)]]); } + getAccountByAddress(address) { return this._call('get_account_by_address', [ripemd160.toRaw(address)]); } /** * Returns all approved withdrawals, for the given account id. @@ -1015,7 +1031,7 @@ class WalletAPI { * @returns {Promise} the all public withdrawals data stored in the blockchain */ getAccountWithdrawals(idOfAccount, type) { - return this.wsProvider.call([0, 'get_account_withdrawals', [accountId.toRaw(idOfAccount), type]]); + return this._call('get_account_withdrawals', [accountId.toRaw(idOfAccount), type]); } /** @@ -1028,12 +1044,12 @@ class WalletAPI { * @returns {Promise} the signed version of the transaction */ approveProposal(feePayingAccountId, idOfProposal, delta, shouldDoBroadcastToNetwork) { - return this.wsProvider.call([0, 'approve_proposal', [ + return this._call('approve_proposal', [ accountId.toRaw(feePayingAccountId), proposalId.toRaw(idOfProposal), wallet.approvalDelta.toRaw(delta), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1046,10 +1062,10 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'create_eth_address', [ + return this._call('create_eth_address', [ string.toRaw(accountIdOrName), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1064,12 +1080,12 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'withdraw_eth', [ + return this._call('withdraw_eth', [ string.toRaw(accountIdOrName), ethAddress.toRaw(ethOfAddress), uint64.toRaw(value), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1079,10 +1095,10 @@ class WalletAPI { * @returns {Promise} */ floodNetwork(prefix, numberOfTransactions) { - return this.wsProvider.call([0, 'flood_network', [ + return this._call('flood_network', [ string.toRaw(prefix), uint32.toRaw(numberOfTransactions), - ]]); + ]); } /** @@ -1097,7 +1113,7 @@ class WalletAPI { if (!limit > API_CONFIG.LIST_ASSETS_MAX_LIMIT) { return Promise.reject(new Error(`Limit should be capped at ${API_CONFIG.LIST_ASSETS_MAX_LIMIT}`)); } - return this.wsProvider.call([0, 'list_assets', [assetId.toRaw(lowerBoundSymbol), uint32.toRaw(limit)]]); + return this._call('list_assets', [assetId.toRaw(lowerBoundSymbol), uint32.toRaw(limit)]); } /** @@ -1123,14 +1139,14 @@ class WalletAPI { return Promise.reject(new Error('Accounts id or name should be string and valid')); } if (!isAssetName(symbol)) return Promise.reject(new Error('Assets symbol should be string and valid')); - return this.wsProvider.call([0, 'create_asset', [ + return this._call('create_asset', [ string.toRaw(accountIdOrName), string.toRaw(symbol), uint8.toRaw(precision), options.toRaw(assetOption), optional(bitassetOptions).toRaw(bitassetOpts), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1154,12 +1170,12 @@ class WalletAPI { if (!isAccountIdOrName(newIssuerIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'update_asset', [ + return this._call('update_asset', [ string.toRaw(assetIdOrName), string.toRaw(newIssuerIdOrName), options.toRaw(newOptions), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1176,11 +1192,11 @@ class WalletAPI { if (!isAssetIdOrName(assetIdOrName)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsProvider.call([0, 'update_bitasset', [ + return this._call('update_bitasset', [ string.toRaw(assetIdOrName), bitassetOptions.toRaw(newBitasset), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1200,11 +1216,11 @@ class WalletAPI { if (!newFeedProducers.every((idOrName) => !!isAccountIdOrName(idOrName))) { return Promise.reject(new Error('Accounts should contain valid account names or ids')); } - return this.wsProvider.call([0, 'update_asset_feed_producers', [ + return this._call('update_asset_feed_producers', [ string.toRaw(assetIdOrName), vector(string).toRaw(newFeedProducers), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1234,12 +1250,12 @@ class WalletAPI { if (!isAssetIdOrName(assetIdOrName)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsProvider.call([0, 'publish_asset_feed', [ + return this._call('publish_asset_feed', [ string.toRaw(accountIdOrName), string.toRaw(assetIdOrName), price.toRaw(coreEchangeRate), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1255,12 +1271,12 @@ class WalletAPI { return Promise.reject(new Error('Accounts id or name should be string and valid')); } if (!isValidAmount(amount)) return Promise.reject(new Error('Invalid number')); - return this.wsProvider.call([0, 'issue_asset', [ + return this._call('issue_asset', [ string.toRaw(accountIdOrName), string.toRaw(amount), string.toRaw(assetTicker), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1272,7 +1288,7 @@ class WalletAPI { if (!isAssetIdOrName(assetIdOrName)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsProvider.call([0, 'get_asset', [string.toRaw(assetIdOrName)]]); + return this._call('get_asset', [string.toRaw(assetIdOrName)]); } /** @@ -1286,7 +1302,7 @@ class WalletAPI { if (!isAssetIdOrName(bitassetIdOrName)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsProvider.call([0, 'get_bitasset_data', [string.toRaw(bitassetIdOrName)]]); + return this._call('get_bitasset_data', [string.toRaw(bitassetIdOrName)]); } /** @@ -1307,12 +1323,12 @@ class WalletAPI { if (!isAssetIdOrName(assetIdOrName)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsProvider.call([0, 'fund_asset_fee_pool', [ + return this._call('fund_asset_fee_pool', [ string.toRaw(fromAccountIdOrName), string.toRaw(assetIdOrName), string.toRaw(amount), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1335,12 +1351,12 @@ class WalletAPI { if (!isAssetIdOrName(assetIdOrName)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsProvider.call([0, 'reserve_asset', [ + return this._call('reserve_asset', [ string.toRaw(accountIdOrName), string.toRaw(amount), string.toRaw(assetIdOrName), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1353,7 +1369,7 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'get_committee_member', [string.toRaw(accountIdOrName)]]); + return this._call('get_committee_member', [string.toRaw(accountIdOrName)]); } /** @@ -1374,7 +1390,7 @@ class WalletAPI { if (!limit > API_CONFIG.COMMITTEE_MEMBER_ACCOUNTS_MAX_LIMIT) { return Promise.reject(new Error(`Limit should be less ${API_CONFIG.COMMITTEE_MEMBER_ACCOUNTS_MAX_LIMIT}`)); } - return this.wsProvider.call([0, 'list_committee_members', [string.toRaw(lowerBoundName), uint64.toRaw(limit)]]); + return this._call('list_committee_members', [string.toRaw(lowerBoundName), uint64.toRaw(limit)]); } /** @@ -1390,12 +1406,12 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'propose_parameter_change', [ + return this._call('propose_parameter_change', [ string.toRaw(accountIdOrName), timePointSec.toRaw(expirationTime), variantObject.toRaw(changeValues), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1411,12 +1427,12 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'propose_fee_change', [ + return this._call('propose_fee_change', [ string.toRaw(accountIdOrName), timePointSec.toRaw(expirationTime), variantObject.toRaw(changedValues), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1430,11 +1446,11 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'change_sidechain_config', [ + return this._call('change_sidechain_config', [ string.toRaw(accountIdOrName), config.toRaw(changedValues), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1442,20 +1458,20 @@ class WalletAPI { * @param {number} blockNum height of the block to retrieve * @return {Promise} info about the block, or undefined if not found */ - getBlock(blockNum) { return this.wsProvider.call([0, 'get_block', [uint32.toRaw(blockNum)]]); } + getBlock(blockNum) { return this._call('get_block', [uint32.toRaw(blockNum)]); } /** * Returns block virtual ops by number * @param {number} blockNum height of the block to retrieve * @return {Promise} info about operation history object */ - getBlockVirtualOps(blockNum) { return this.wsProvider.call([0, 'get_block_virtual_ops', [uint32.toRaw(blockNum)]]); } + getBlockVirtualOps(blockNum) { return this._call('get_block_virtual_ops', [uint32.toRaw(blockNum)]); } /** * Returns the number of accounts registered on the blockchain. * @return {Promise} the number of registered accounts */ - getAccountCount() { return this.wsProvider.call([0, 'get_account_count', []]); } + getAccountCount() { return this._call('get_account_count', []); } /** * Returns the block chain's slowly-changing settings. @@ -1464,7 +1480,7 @@ class WalletAPI { * @see {@link WalletAPI['getDynamicGlobalProperties']} for frequently changing properties * @return {Promise} the global properties */ - getGlobalProperties() { return this.wsProvider.call([0, 'get_global_properties', []]); } + getGlobalProperties() { return this._call('get_global_properties', []); } /** * Returns the block chain's rapidly-changing properties. @@ -1473,7 +1489,7 @@ class WalletAPI { * @see {@link WalletAPI['getGlobalProperties']} for less-frequently changing properties * @return {Promise} the dynamic global properties */ - getDynamicGlobalProperties() { return this.wsProvider.call([0, 'get_dynamic_global_properties', []]); } + getDynamicGlobalProperties() { return this._call('get_dynamic_global_properties', []); } /** * Returns the blockchain object corresponding to the given id. @@ -1481,13 +1497,13 @@ class WalletAPI { * @param {string} objectId the id of the object to return * @returns {Promise} the requested object */ - getObject(objectId) { return this.wsProvider.call([0, 'get_object', [anyObjectId.toRaw(objectId)]]); } + getObject(objectId) { return this._call('get_object', [anyObjectId.toRaw(objectId)]); } /** * Create a new transaction builder. * @returns {Promise} handle of the new transaction builder */ - beginBuilderTransaction() { return this.wsProvider.call([0, 'begin_builder_transaction', []]); } + beginBuilderTransaction() { return this._call('begin_builder_transaction', []); } /** * Append a new operation to a transaction builder. @@ -1496,10 +1512,10 @@ class WalletAPI { * @returns {Promise} */ addOperationToBuilderTransaction(transactionTypeHandle, newOperation) { - return this.wsProvider.call([0, 'add_operation_to_builder_transaction', [ + return this._call('add_operation_to_builder_transaction', [ uint16.toRaw(transactionTypeHandle), operation.toRaw(newOperation), - ]]); + ]); } /** @@ -1510,11 +1526,11 @@ class WalletAPI { * @returns {Promise} */ replaceOperationInBuilderTransaction(transactionTypeHandle, unsignedOperation, newOperation) { - return this.wsProvider.call([0, 'replace_operation_in_builder_transaction', [ + return this._call('replace_operation_in_builder_transaction', [ uint16.toRaw(transactionTypeHandle), uint64.toRaw(unsignedOperation), operation.toRaw(newOperation), - ]]); + ]); } /** @@ -1527,10 +1543,10 @@ class WalletAPI { if (!isAssetIdOrName(feeAsset)) { return Promise.reject(new Error('Assets id or name should be string and valid')); } - return this.wsProvider.call([0, 'set_fees_on_builder_transaction', [ + return this._call('set_fees_on_builder_transaction', [ uint16.toRaw(transactionTypeHandle), string.toRaw(feeAsset), - ]]); + ]); } /** @@ -1539,7 +1555,7 @@ class WalletAPI { * @returns {Promise} a transaction */ previewBuilderTransaction(transactionTypeHandle) { - return this.wsProvider.call([0, 'preview_builder_transaction', [uint64.toRaw(transactionTypeHandle)]]); + return this._call('preview_builder_transaction', [uint64.toRaw(transactionTypeHandle)]); } /** @@ -1549,10 +1565,10 @@ class WalletAPI { * @returns {Promise} a signed transaction */ signBuilderTransaction(transactionTypeHandle, shouldDoBroadcastToNetwork) { - return this.wsProvider.call([0, 'sign_builder_transaction', [ + return this._call('sign_builder_transaction', [ uint16.toRaw(transactionTypeHandle), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1566,12 +1582,12 @@ class WalletAPI { * @returns {Promise} a signed transaction */ proposeBuilderTransaction(transactionTypeHandle, expirationTime, reviewPeriod, shouldDoBroadcastToNetwork) { - return this.wsProvider.call([0, 'propose_builder_transaction', [ + return this._call('propose_builder_transaction', [ uint16.toRaw(transactionTypeHandle), timePointSec.toRaw(expirationTime), uint32.toRaw(reviewPeriod), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1595,13 +1611,13 @@ class WalletAPI { if (!isAccountIdOrName(accountIdOrName)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'propose_builder_transaction2', [ + return this._call('propose_builder_transaction2', [ uint16.toRaw(transactionTypeHandle), string.toRaw(accountIdOrName), timePointSec.toRaw(expirationTime), uint32.toRaw(reviewPeriod), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1610,7 +1626,7 @@ class WalletAPI { * @returns {Promise} */ removeBuilderTransaction(transactionTypeHandle) { - return this.wsProvider.call([0, 'remove_builder_transaction', [uint16.toRaw(transactionTypeHandle)]]); + return this._call('remove_builder_transaction', [uint16.toRaw(transactionTypeHandle)]); } /** @@ -1619,7 +1635,7 @@ class WalletAPI { * @returns {Promise} the binary form of the transaction. It will not be hex encoded, * this returns a raw string that may have null characters embedded in it */ - serializeTransaction(tr) { return this.wsProvider.call([0, 'serialize_transaction', [signedTransaction.toRaw(tr)]]); } + serializeTransaction(tr) { return this._call('serialize_transaction', [signedTransaction.toRaw(tr)]); } /** * Signs a transaction. @@ -1630,10 +1646,10 @@ class WalletAPI { * @returns {Promise} the signed version of the transaction */ signTransaction(tr, shouldDoBroadcastToNetwork) { - return this.wsProvider.call([0, 'sign_transaction', [ + return this._call('sign_transaction', [ transaction.toRaw(tr), bool.toRaw(shouldDoBroadcastToNetwork), - ]]); + ]); } /** @@ -1650,7 +1666,7 @@ class WalletAPI { if (!isOperationPrototypeExists(operationType)) { return Promise.reject(new Error('This operation does not exists')); } - return this.wsProvider.call([0, 'get_prototype_operation', [string.toRaw(operationType)]]); + return this._call('get_prototype_operation', [string.toRaw(operationType)]); } /* @@ -1667,9 +1683,7 @@ class WalletAPI { if (!isBoolean(shouldDoBroadcastToNetwork)) return Promise.reject(new Error('broadcast should be a boolean')); - return this.wsProvider.call([0, 'generate_btc_deposit_address', - [accountIdOrName, backupAddress, shouldDoBroadcastToNetwork], - ]); + return this._call('generate_btc_deposit_address', [accountIdOrName, backupAddress, shouldDoBroadcastToNetwork]); } /** @@ -1680,7 +1694,7 @@ class WalletAPI { getBtcAddress(account) { if (!isAccountId(account) || !isAccountName(account)) throw new Error('account should be valid'); - return this.wsProvider.call([0, 'get_btc_address', [account]]); + return this._call('get_btc_address', [account]); } /** @@ -1689,7 +1703,7 @@ class WalletAPI { * @returns {Promise} */ getBtcDepositScript(btcDepositAddress) { - return this.wsProvider.call([0, 'get_btc_deposit_script', [btcDepositAddress]]); + return this._call('get_btc_deposit_script', [btcDepositAddress]); } /** @@ -1708,9 +1722,7 @@ class WalletAPI { if (!isUInt64(amount)) return Promise.reject(new Error('amount should be a non negative integer')); if (!isBoolean(shouldDoBroadcastToNetwork)) return Promise.reject(new Error('broadcast should be a boolean')); - return this.wsProvider.call([0, 'withdraw_btc', - [accountIdOrName, addressToWithdraw, amount, shouldDoBroadcastToNetwork], - ]); + return this._call('withdraw_btc', [accountIdOrName, addressToWithdraw, amount, shouldDoBroadcastToNetwork]); } /* @@ -1726,7 +1738,7 @@ class WalletAPI { if (!isPublicKey(activeKey)) return Promise.reject(new Error('active key is invalid')); if (!isPublicKey(echorandKey)) return Promise.reject(new Error('echorand key is invalid')); - return this.wsProvider.call([0, 'register_account_with_api', [name, activeKey, echorandKey, evmAddress]]); + return this._call('register_account_with_api', [name, activeKey, echorandKey, evmAddress]); } /** @@ -1739,7 +1751,7 @@ class WalletAPI { return Promise.reject(new Error('Account name or id is invalid')); } - return this.wsProvider.call([0, 'list_frozen_balances', [accountNameOrId]]); + return this._call('list_frozen_balances', [accountNameOrId]); } /** @@ -1765,8 +1777,12 @@ class WalletAPI { if (!isUInt64(duration)) return Promise.reject(new Error('duration should be a non negative integer')); if (!isBoolean(shouldDoBroadcastToNetwork)) return Promise.reject(new Error('Broadcast should be a boolean')); - return this.wsProvider.call([0, 'freeze_balance', - [fromAccountNameOrId, amount, assetIdOrName, duration, shouldDoBroadcastToNetwork], + return this._call('freeze_balance', [ + fromAccountNameOrId, + amount, + assetIdOrName, + duration, + shouldDoBroadcastToNetwork, ]); } @@ -1780,7 +1796,7 @@ class WalletAPI { return Promise.reject(new Error('Account name or id is invalid')); } - return this.wsProvider.call([0, 'get_committee_frozen_balance', [string.toRaw(ownerAccount)]]); + return this._call('get_committee_frozen_balance', [string.toRaw(ownerAccount)]); } @@ -1795,11 +1811,11 @@ class WalletAPI { if (!isAccountIdOrName(ownerAccount)) return Promise.reject(new Error('Account name or id is invalid')); if (!isValidAmount(amount)) return Promise.reject(new Error('Invalid amount')); - return this.wsProvider.call([0, 'committee_freeze_balance', [ + return this._call('committee_freeze_balance', [ string.toRaw(ownerAccount), string.toRaw(amount), bool.toRaw(broadcast), - ]]); + ]); } /** @@ -1813,11 +1829,11 @@ class WalletAPI { if (!isAccountIdOrName(ownerAccount)) return Promise.reject(new Error('Account name or id is invalid')); if (!isValidAmount(amount)) return Promise.reject(new Error('Invalid amount')); - return this.wsProvider.call([0, 'committee_withdraw_balance', [ + return this._call('committee_withdraw_balance', [ string.toRaw(ownerAccount), string.toRaw(amount), bool.toRaw(broadcast), - ]]); + ]); } /** @@ -1832,12 +1848,12 @@ class WalletAPI { if (!isAccountIdOrName(sender)) return Promise.reject(new Error('Account name or id is invalid')); if (!isCommitteeMemberId(committeeToActivate)) return Promise.reject(new Error('Invalid committee member id')); - return this.wsProvider.call([0, 'create_activate_committee_member_proposal', [ + return this._call('create_activate_committee_member_proposal', [ accountId.toRaw(sender), committeeMemberId.toRaw(committeeToActivate), timePointSec.toRaw(expirationTime), bool.toRaw(broadcast), - ]]); + ]); } /** @@ -1854,12 +1870,12 @@ class WalletAPI { return Promise.reject(new Error('Invalid committee member id')); } - return this.wsProvider.call([0, 'create_deactivate_committee_member_proposal', [ + return this._call('create_deactivate_committee_member_proposal', [ accountId.toRaw(sender), committeeMemberId.toRaw(committeeTodeactivate), timePointSec.toRaw(expirationTime), bool.toRaw(broadcast), - ]]); + ]); } /** @@ -1877,13 +1893,13 @@ class WalletAPI { return Promise.reject(new Error('Url should be string and valid')); } - return this.wsProvider.call([0, 'update_committee_member', [ + return this._call('update_committee_member', [ accountId.toRaw(ownerAccount), string.toRaw(newUrl), string.toRaw(newEthAddress), string.toRaw(newBtcPublicKey), bool.toRaw(broadcast), - ]]); + ]); } /** @@ -1902,14 +1918,14 @@ class WalletAPI { } if (!isValidAmount(amount)) return Promise.reject(new Error('Invalid number')); - return this.wsProvider.call([0, 'create_committee_member', [ + return this._call('create_committee_member', [ accountId.toRaw(ownerAccount), string.toRaw(url), string.toRaw(amount), string.toRaw(ethereumAddress), string.toRaw(btcPublicKey), bool.toRaw(broadcast), - ]]); + ]); } } From bc765afb5af41ada717ce86caaf048f20a1298c6 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 13 Apr 2020 20:21:21 +0300 Subject: [PATCH 55/62] [ECHOJS-250] Fix HttpProvider --- src/echo/providers/HttpProvider.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/echo/providers/HttpProvider.js b/src/echo/providers/HttpProvider.js index 9b4ea5af..e0c64395 100644 --- a/src/echo/providers/HttpProvider.js +++ b/src/echo/providers/HttpProvider.js @@ -10,10 +10,10 @@ export default class HttpProvider { this.url = url; } - call(method, params) { + async call(method, params) { return Axios.post(this.url, { jsonrpc: '2.0', id: 0, method, params, - }); + }).then((res) => res.data.result); } } From f16c703e91c4b859496561d169ec2f8abd7d866d Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Tue, 14 Apr 2020 10:38:35 +0300 Subject: [PATCH 56/62] [ECHOJS-250] Fix default chain apis for http connection --- src/echo/apis/base-api.js | 3 ++- src/echo/index.js | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/echo/apis/base-api.js b/src/echo/apis/base-api.js index e0348c6c..93923c39 100644 --- a/src/echo/apis/base-api.js +++ b/src/echo/apis/base-api.js @@ -25,7 +25,8 @@ export default class BaseEchoApi { if (this.provider.connectionType === ConnectionType.WS) { if (this.apiName === CHAIN_API.LOGIN_API) this.apiId = 1; else this.apiId = await this.provider.call([1, this.apiName, []]); - } else this.apiId = 0; + } else if (this.apiName === CHAIN_API.DATABASE_API) this.apiId = 0; + else throw new Error(`${this.apiName} not available through http connection`); return this; } diff --git a/src/echo/index.js b/src/echo/index.js index f93b64a4..e6a88235 100644 --- a/src/echo/index.js +++ b/src/echo/index.js @@ -3,7 +3,7 @@ import Cache from './cache'; import API from './api'; import Subscriber from './subscriber'; import Transaction from './transaction'; -import { STATUS, DEFAULT_CHAIN_APIS } from '../constants/ws-constants'; +import { STATUS, DEFAULT_CHAIN_APIS, CHAIN_API } from '../constants/ws-constants'; import { WalletApi } from './apis'; import EchoApiEngine from './engine'; import { ConnectionType, WsProvider, HttpProvider } from './providers'; @@ -56,7 +56,9 @@ class Echo { if (optionError) throw new Error(optionError); const provider = address.startsWith('ws') ? new WsProvider() : new HttpProvider(address); if (provider.connectionType === ConnectionType.WS) await provider.connect(address, options); - this.engine = new EchoApiEngine(options.apis || DEFAULT_CHAIN_APIS, provider); + const apis = options.apis || + (provider.connectionType === ConnectionType.WS ? DEFAULT_CHAIN_APIS : [CHAIN_API.DATABASE_API]); + this.engine = new EchoApiEngine(apis, provider); if (this._isInitModules) return; this.subscriber.setOptions(options); await this._initModules(options); From fa09c8d23fd42820fc40dcd141325ef925339a35 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Tue, 14 Apr 2020 10:43:09 +0300 Subject: [PATCH 57/62] [ECHOJS-250] Fix eslint --- src/echo/apis/wallet-api.js | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/echo/apis/wallet-api.js b/src/echo/apis/wallet-api.js index e1f02066..b69c2a87 100644 --- a/src/echo/apis/wallet-api.js +++ b/src/echo/apis/wallet-api.js @@ -202,7 +202,10 @@ class WalletAPI { if (!isAccountIdOrName(accountNameOrId)) { return Promise.reject(new Error('Accounts id or name should be string and valid')); } - return this.wsProvider.call([0, 'import_key', [string.toRaw(accountNameOrId), privateKey.toRaw(privateKeyWif)]]); + return this.wsProvider.call([0, 'import_key', [ + string.toRaw(accountNameOrId), + privateKey.toRaw(privateKeyWif), + ]]); } /** @@ -321,7 +324,9 @@ class WalletAPI { * If `wallet_filename` is empty, it reloads the existing wallet file * @returns {Promise} true if the specified wallet is loaded */ - loadWalletFile(walletFilename) { return this.wsProvider.call([0, 'load_wallet_file', [string.toRaw(walletFilename)]]); } + loadWalletFile(walletFilename) { + return this.wsProvider.call([0, 'load_wallet_file', [string.toRaw(walletFilename)]]); + } /** * Transforms a brain key to reduce the chance of errors when re-entering the key from memory. @@ -342,7 +347,9 @@ class WalletAPI { * If `wallet_filename` is empty, save to the current filename * @returns {Promise} */ - saveWalletFile(walletFilename) { return this.wsProvider.call([0, 'save_wallet_file', [string.toRaw(walletFilename)]]); } + saveWalletFile(walletFilename) { + return this.wsProvider.call([0, 'save_wallet_file', [string.toRaw(walletFilename)]]); + } /** * Lists all accounts controlled by this wallet. @@ -387,7 +394,9 @@ class WalletAPI { * @param {string} idOfAccount id the id of either an account or a contract * @returns {Promise} a list of the given account/contract balances */ - listIdBalances(idOfAccount) { return this.wsProvider.call([0, 'list_id_balances', [accountId.toRaw(idOfAccount)]]); } + listIdBalances(idOfAccount) { + return this.wsProvider.call([0, 'list_id_balances', [accountId.toRaw(idOfAccount)]]); + } /** * Registers a third party's account on the blockckain. @@ -1006,7 +1015,9 @@ class WalletAPI { * @param {string} address address in form of ripemd160 hash * @returns {Promise} Account id of owner */ - getAccountByAddress(address) { return this.wsProvider.call([0, 'get_account_by_address', [ripemd160.toRaw(address)]]); } + getAccountByAddress(address) { + return this.wsProvider.call([0, 'get_account_by_address', [ripemd160.toRaw(address)]]); + } /** * Returns all approved withdrawals, for the given account id. @@ -1449,7 +1460,9 @@ class WalletAPI { * @param {number} blockNum height of the block to retrieve * @return {Promise} info about operation history object */ - getBlockVirtualOps(blockNum) { return this.wsProvider.call([0, 'get_block_virtual_ops', [uint32.toRaw(blockNum)]]); } + getBlockVirtualOps(blockNum) { + return this.wsProvider.call([0, 'get_block_virtual_ops', [uint32.toRaw(blockNum)]]); + } /** * Returns the number of accounts registered on the blockchain. @@ -1619,7 +1632,9 @@ class WalletAPI { * @returns {Promise} the binary form of the transaction. It will not be hex encoded, * this returns a raw string that may have null characters embedded in it */ - serializeTransaction(tr) { return this.wsProvider.call([0, 'serialize_transaction', [signedTransaction.toRaw(tr)]]); } + serializeTransaction(tr) { + return this.wsProvider.call([0, 'serialize_transaction', [signedTransaction.toRaw(tr)]]); + } /** * Signs a transaction. From 2a94988fd3b51685d785a681b6c86c5fd6f1c7a4 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Tue, 14 Apr 2020 14:46:10 +0300 Subject: [PATCH 58/62] [ECHOJS-253] Done --- test/_test-data.js | 9 +++-- test/http-connection.test.js | 65 ++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 test/http-connection.test.js diff --git a/test/_test-data.js b/test/_test-data.js index 32fb1b6c..b252f13a 100644 --- a/test/_test-data.js +++ b/test/_test-data.js @@ -5,8 +5,13 @@ export const accountName = 'nathan'; export const accountId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.ACCOUNT}.10`; export const contractId = `1.${constants.PROTOCOL_OBJECT_TYPE_ID.CONTRACT}.0`; -export const url = 'ws://127.0.0.1:6311'; -export const walletURL = 'ws://127.0.0.1:6312'; +export const endpoint = '127.0.0.1:6311'; +export const url = `ws://${endpoint}`; +export const httpUrl = `http://${endpoint}`; + +export const walletEndpoint = '127.0.0.1:6312'; +export const walletURL = `ws://${walletEndpoint}`; +export const walletHttpURL = `http://${walletEndpoint}`; export const ED_PRIVATE = '5eePidTGLR7ecWiQB1b7osm1iMDfQo2HKAzfyN4QDma4'; export const ED_PRIVATE_WITHOUT_PREFIX = '5eePidTGLR7ecWiQB1b7osm1iMDfQo2HKAzfyN4QDma4'; diff --git a/test/http-connection.test.js b/test/http-connection.test.js new file mode 100644 index 00000000..1e72ca50 --- /dev/null +++ b/test/http-connection.test.js @@ -0,0 +1,65 @@ +import assert from 'assert'; + +import { Echo, constants } from '../'; + +import { httpUrl, walletHttpURL } from './_test-data'; +import { shouldReject } from './_test-utils'; + +const { WS_CONSTANTS: { CHAIN_API } } = constants; + +describe('Http connection', () => { + describe('When connected without apis option', () => { + const echo = new Echo(); + it('should not reject', () => echo.connect(httpUrl)); + it('should connect only database api', () => { + assert.deepStrictEqual(echo.apis, new Set([CHAIN_API.DATABASE_API])); + }); + }); + describe('When connected with not database api', () => { + const echo = new Echo(); + const api = CHAIN_API.NETWORK_BROADCAST_API; + shouldReject(() => echo.connect(httpUrl, { apis: [api] }), `${api} not available through http connection`); + }); + describe('When try to call not database api', () => { + const echo = new Echo(); + before(() => echo.connect(httpUrl)); + shouldReject( + () => echo.api.getAllAssetHolders(), + `${CHAIN_API.ASSET_API} API is not available, try to specify this in connection option called "apis"`, + ); + }); + describe('When database api method called', () => { + const echo = new Echo(); + before(() => echo.connect(httpUrl)); + let res; + it('should not reject', async () => res = await echo.api.getChainProperties()); + it('should return', () => assert.notStrictEqual(res, undefined)); + it('result should be valid', () => { + assert.ok(typeof res === 'object'); + assert.ok(res !== null); + assert.ok(['id', 'chain_id'].every((field) => res[field] !== undefined)); + }); + }); + describe('When database method with callback called', () => { + const echo = new Echo(); + before(() => echo.connect(httpUrl)); + shouldReject(async () => { + await echo.api.getContractLogs(); + }, 'method get_contract_logs not supported by http connection'); + }); + describe('When useless database method called', () => { + const echo = new Echo(); + before(() => echo.connect(httpUrl)); + shouldReject(async () => { + await echo.api.unsubscribeContractLogs(0); + }, 'method unsubscribe_contract_logs not supported by http connection'); + }); + describe('When http connection used for wallet api', () => { + const echo = new Echo(); + it('connect should not reject', () => echo.connect(null, { wallet: walletHttpURL })); + let res; + it('method call should not reject', async () => res = await echo.walletApi.networkGetConnectedPeers()); + it('should return', () => assert.notStrictEqual(res, undefined)); + it('result should be valid', () => assert.ok(Array.isArray(res))); + }); +}); From 4154f86cb5562da05e02a664b8f28835c923a60e Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Tue, 14 Apr 2020 14:46:43 +0300 Subject: [PATCH 59/62] [ECHOJS-250] Fix --- src/echo/api.js | 4 ++-- src/echo/apis/base-api.js | 4 ++-- src/echo/providers/HttpProvider.js | 23 ++++++++++++++++++----- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/echo/api.js b/src/echo/api.js index 16e11293..6b856020 100644 --- a/src/echo/api.js +++ b/src/echo/api.js @@ -1971,7 +1971,7 @@ class API { for (const field of ['fromBlock', 'toBlock']) { ok(opts[field] === undefined || isUInt32(opts[field]), `"${field}" option is not uint32`); } - return new Promise((resolve) => { + return new Promise((resolve, reject) => { const cb = (logs) => { resolve(logs[0].map(([, log]) => log)); }; @@ -1980,7 +1980,7 @@ class API { topics, from_block: BigNumber.isBigNumber(opts.fromBlock) ? opts.fromBlock.toNumber() : opts.fromBlock, to_block: BigNumber.isBigNumber(opts.toBlock) ? opts.toBlock.toNumber() : opts.toBlock, - }); + }).catch((err) => reject(err)); }); } diff --git a/src/echo/apis/base-api.js b/src/echo/apis/base-api.js index 93923c39..5ef03009 100644 --- a/src/echo/apis/base-api.js +++ b/src/echo/apis/base-api.js @@ -36,13 +36,13 @@ export default class BaseEchoApi { * @param {any[]} params * @returns {Promise} */ - exec(method, params) { + async exec(method, params) { if (this.apiId === null) { const errMessage = [ `${this.apiName} API is not available`, 'try to specify this in connection option called "apis"', ].join(', '); - return Promise.reject(new Error(errMessage)); + throw new Error(errMessage); } if (this.provider.connectionType === ConnectionType.HTTP) return this.provider.call(method, params); return this.provider.call([this.apiId, method, params]); diff --git a/src/echo/providers/HttpProvider.js b/src/echo/providers/HttpProvider.js index e0c64395..955fd2b5 100644 --- a/src/echo/providers/HttpProvider.js +++ b/src/echo/providers/HttpProvider.js @@ -2,15 +2,28 @@ import Axios from 'axios'; import * as ConnectionType from './connection-types'; +export const unsupportedMethods = [ + // methods with callbacks + 'set_subscribe_callback', + 'set_pending_transaction_callback', + 'set_block_applied_callback', + 'get_contract_logs', + 'subscribe_contract_logs', + // useless for http connection methods + 'cancel_all_subscriptions', + 'subscribe_contracts', + 'unsubscribe_contract_logs', +]; + export default class HttpProvider { get connectionType() { return ConnectionType.HTTP; } - - constructor(url) { - this.url = url; - } - + get unsupportedMethods() { return [...unsupportedMethods]; } + constructor(url) { this.url = url; } async call(method, params) { + if (this.unsupportedMethods.includes(method)) { + throw new Error(`method ${method} not supported by http connection`); + } return Axios.post(this.url, { jsonrpc: '2.0', id: 0, method, params, }).then((res) => res.data.result); From 4c215624b4a666e9fdbeea0051990d384905a306 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Tue, 14 Apr 2020 16:38:23 +0300 Subject: [PATCH 60/62] [ECHOJS-250] Resolve conflicts with ECHOJS-247 --- src/echo/apis/wallet-api.js | 29 ----------------------------- src/echo/subscriber.js | 1 + 2 files changed, 1 insertion(+), 29 deletions(-) diff --git a/src/echo/apis/wallet-api.js b/src/echo/apis/wallet-api.js index 56660357..b69c2a87 100644 --- a/src/echo/apis/wallet-api.js +++ b/src/echo/apis/wallet-api.js @@ -580,35 +580,6 @@ class WalletAPI { ]]); } - /** - * Returns the most recent operations on the contract id. - * - * This returns a list of operation history objects, which describe activity on the contract. - * @param {typeof contractId["__TInput__"]} _contractId the ID of the contract - * @param {typeof uint32["__TInput__"]} limit the number of entries to return (starting from the most recent) - * @returns {Promise} a list of accounts mapping account names to account ids - */ - async getContractHistory(_contractId, limit) { - return this.wsRpc.call([0, 'get_contract_history', [contractId.toRaw(_contractId), uint32.toRaw(limit)]]); - } - - /** - * Returns the relative operations on the id contract from start number - * @param {typeof contractId["__TInput__"]} _contractId the ID of the contract - * @param {typeof uint32["__TInput__"]} stop Sequence number of earliest operation - * @param {typeof uint32["__TInput__"]} limit the number of entries to return - * @param {typeof uint32["__TInput__"]} start the sequence number where to start looping back throw the history - * @returns {Promise} a list of operation history objects - */ - async getRelativeContractHistory(_contractId, stop, limit, start) { - return this.wsRpc.call([0, 'get_relative_contract_history', [ - contractId.toRaw(_contractId), - uint32.toRaw(stop), - uint32.toRaw(limit), - uint32.toRaw(start), - ]]); - } - /** * Transfer an amount from one account to another. * @param {string} fromAccountNameOrId the name or id of the account sending the funds diff --git a/src/echo/subscriber.js b/src/echo/subscriber.js index aede0782..fee7ed79 100644 --- a/src/echo/subscriber.js +++ b/src/echo/subscriber.js @@ -38,6 +38,7 @@ import { import { handleConnectionClosedError } from '../utils/helpers'; import { IMPLEMENTATION_OBJECT_TYPE_ID } from '../constants/chain-types'; import { ConnectionType } from './providers'; +import { toRawContractLogsFilterOptions } from '../utils/converters'; /** @typedef {import("./engine").default} EchoApiEngine */ From 093020dcd720025083e9f0b41b88f03c8395f133 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Tue, 14 Apr 2020 16:40:16 +0300 Subject: [PATCH 61/62] [ECHOJS-250] Remove temp interfaces --- types/echo/echo-api.d.ts | 10 ---------- types/echo/engine.d.ts | 11 ----------- types/echo/providers/base-provider.d.ts | 13 ------------- types/echo/providers/connection-type.d.ts | 6 ------ types/echo/providers/http-provider.d.ts | 8 -------- types/echo/providers/index.d.ts | 4 ---- types/echo/providers/ws-provider.d.ts | 22 ---------------------- 7 files changed, 74 deletions(-) delete mode 100644 types/echo/echo-api.d.ts delete mode 100644 types/echo/engine.d.ts delete mode 100644 types/echo/providers/base-provider.d.ts delete mode 100644 types/echo/providers/connection-type.d.ts delete mode 100644 types/echo/providers/http-provider.d.ts delete mode 100644 types/echo/providers/index.d.ts delete mode 100644 types/echo/providers/ws-provider.d.ts diff --git a/types/echo/echo-api.d.ts b/types/echo/echo-api.d.ts deleted file mode 100644 index 6d1812ca..00000000 --- a/types/echo/echo-api.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { HttpProvider, WsProvider } from "./providers"; - -export default class EchoApi { - public readonly apiId: number | null; - public readonly apiName: string; - public readonly provider: HttpProvider | WsProvider; - constructor(provider: HttpProvider | WsProvider, apiName: string); - init(): Promise; - exec(method: string, params: any[]): Promise; -} diff --git a/types/echo/engine.d.ts b/types/echo/engine.d.ts deleted file mode 100644 index 43f6522f..00000000 --- a/types/echo/engine.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import ChainApi from "../interfaces/ChainApi"; -import EchoApi from "./echo-api"; -import { HttpProvider, WsProvider } from "./providers"; - -export default class EchoApiEngine { - public readonly availableApis: readonly ChainApi[]; - public readonly api: Readonly<{ [apiName in ChainApi]: EchoApi }>; - public readonly provider: HttpProvider | WsProvider; - constructor(apis: readonly ChainApi[], provider: HttpProvider | WsProvider); - public init(): Promise; -} diff --git a/types/echo/providers/base-provider.d.ts b/types/echo/providers/base-provider.d.ts deleted file mode 100644 index 30329538..00000000 --- a/types/echo/providers/base-provider.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import ConnectionType from "./connection-type"; - -export interface BaseProviderOptions { - debug?: boolean; -} - -export default abstract class BaseProvider { - public readonly connectionType: ConnectionType; - public readonly url: string; - public debug: boolean; - constructor(url: string, options?: BaseProviderOptions); - protected log(message: string): void; -} diff --git a/types/echo/providers/connection-type.d.ts b/types/echo/providers/connection-type.d.ts deleted file mode 100644 index 52efe99f..00000000 --- a/types/echo/providers/connection-type.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -declare enum ConnectionType { - WS = "ws", - HTTP = "http", -} - -export default ConnectionType; diff --git a/types/echo/providers/http-provider.d.ts b/types/echo/providers/http-provider.d.ts deleted file mode 100644 index 3196986a..00000000 --- a/types/echo/providers/http-provider.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import BaseProvider, { BaseProviderOptions } from "./base-provider"; -import ConnectionType from "./connection-type"; - -export default class HttpProvider extends BaseProvider { - public readonly connectionType: ConnectionType.HTTP; - constructor(url: string, options: BaseProviderOptions); - public call(method: string, params: any[]): Promise; -} diff --git a/types/echo/providers/index.d.ts b/types/echo/providers/index.d.ts deleted file mode 100644 index ac4aef23..00000000 --- a/types/echo/providers/index.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { default as BaseProvider, BaseProviderOptions } from "./base-provider"; -export { default as ConnectionType } from "./connection-type"; -export { default as HttpProvider } from "./http-provider"; -export { default as WsProvider, WsProviderOptions } from "./ws-provider"; diff --git a/types/echo/providers/ws-provider.d.ts b/types/echo/providers/ws-provider.d.ts deleted file mode 100644 index 2b23736f..00000000 --- a/types/echo/providers/ws-provider.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import BaseProvider, { BaseProviderOptions } from "./base-provider"; -import ConnectionType from "./connection-type"; - -export interface WsProviderOptions extends BaseProviderOptions { - connectionTimeout?: number; - maxRetries?: number; - pingDelay?: number; - pingTimeout?: number; -} - -export default class WsProvider extends BaseProvider { - public readonly connectionType: ConnectionType.WS; - public connectionTimeout: number; - public maxRetries: number; - public pingDelay: number; - public pingTimeout: number; - constructor(url: string, options?: WsProviderOptions); - public call(apiId: number, method: string, params: any[]): Promise; - public close(): Promise; - public connect(): Promise; - public reconnect(): Promise; -} From b9626361c6975c3479e0fbace5660efa04fc46f1 Mon Sep 17 00:00:00 2001 From: NickLatkovich Date: Mon, 20 Apr 2020 15:03:28 +0300 Subject: [PATCH 62/62] Remove custom rpc timeout from wallet-api test --- test/wallet-api.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/wallet-api.test.js b/test/wallet-api.test.js index 4b0f7958..5cb6ebfe 100644 --- a/test/wallet-api.test.js +++ b/test/wallet-api.test.js @@ -55,7 +55,6 @@ describe('WALLET API', () => { before(async () => { await echo.connect(url, { - connectionTimeout: 1000, apis: constants.WS_CONSTANTS.CHAIN_APIS, wallet: walletURL, }