From cdc8d55da3536a7cd2b6e913cbb95b95ba857b42 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 21 Feb 2022 13:30:07 +0200 Subject: [PATCH 001/133] Sketch interface INetworkProvider, proxy implementation. --- .../networkProvider/proxyNetworkProvider.ts | 193 ++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 src-network-providers/networkProvider/proxyNetworkProvider.ts diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts new file mode 100644 index 00000000..643e0f9a --- /dev/null +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -0,0 +1,193 @@ +import axios, { AxiosRequestConfig } from "axios"; +import { BigNumber } from "bignumber.js"; +import { AccountOnNetwork, TokenOfAccountOnNetwork } from "../account"; +import { Address } from "../address"; +import { defaultConfig } from "../constants"; +import { ErrApiProviderGet, ErrContractQuery } from "../errors"; +import { INetworkProvider } from "../interface.networkProvider"; +import { Logger } from "../logger"; +import { NetworkConfig } from "../networkConfig"; +import { NetworkStake } from "../networkStake"; +import { NetworkStatus } from "../networkStatus"; +import { Query, QueryResponse } from "../smartcontracts"; +import { Stats } from "../stats"; +import { Token } from "../token"; +import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; +import { TransactionOnNetwork } from "../transactionOnNetwork"; + + +export class NetworkProxyProvider implements INetworkProvider { + private url: string; + private config: AxiosRequestConfig; + + /** + * Creates a new {@link INetworkProvider} backed by an Elrond Proxy. + * @param url the URL of the Elrond Proxy + * @param config axios request config options + */ + constructor(url: string, config?: AxiosRequestConfig) { + this.url = url; + this.config = { ...defaultConfig, ...config }; + } + + async getNetworkConfig(): Promise { + let response = await this.doGetGeneric("network/config"); + let networkConfig = NetworkConfig.fromHttpResponse(response.config); + return networkConfig; + } + + async getNetworkStatus(): Promise { + let response = await this.doGetGeneric("network/status/4294967295"); + let networkStatus = NetworkStatus.fromHttpResponse(response.status); + return networkStatus; + } + + async getAccount(address: Address): Promise { + let response = await this.doGetGeneric(`address/${address.bech32()}`); + let account = AccountOnNetwork.fromHttpResponse(response.account); + return account; + } + + async getAddressEsdtList(address: Address): Promise { + let url = `address/${address.bech32()}/esdt`; + let response = await this.doGetGeneric(url); + let tokens = Object.values(response.esdts).map(item => TokenOfAccountOnNetwork.fromHttpResponse(item)); + return tokens; + } + + async getAddressEsdt(address: Address, tokenIdentifier: string): Promise { + let response = await this.doGetGeneric(`address/${address.bech32()}/esdt/${tokenIdentifier}`); + let tokenData = response.tokenData; + return tokenData; + } + + async getAddressNft(address: Address, tokenIdentifier: string, nonce: BigNumber.Value): Promise { + let response = await this.doGetGeneric(`address/${address.bech32()}/nft/${tokenIdentifier}/nonce/${nonce}`); + let tokenData = response.tokenData; + return tokenData; + } + + async getTransaction(txHash: TransactionHash, hintSender?: Address): Promise { + let url = this.buildUrlWithQueryParameters(`transaction/${txHash.toString()}`, { + withSender: hintSender ? hintSender.bech32() : "", + withResults: "true" + }); + + let response = await this.doGetGeneric(url); + let transaction = TransactionOnNetwork.fromHttpResponse(txHash, response.transaction); + return transaction; + } + + async getTransactionStatus(txHash: TransactionHash): Promise { + let response = await this.doGetGeneric(`transaction/${txHash.toString()}/status`); + let status = new TransactionStatus(response.status); + return status; + } + + async sendTransaction(tx: Transaction): Promise { + let response = await this.doPostGeneric("transaction/send", tx.toSendable()); + let hash = new TransactionHash(response.txHash) + return hash; + } + + async simulateTransaction(tx: Transaction): Promise { + let response = await this.doPostGeneric("transaction/simulate", tx.toSendable(), (response) => response); + return response; + } + + async queryContract(query: Query): Promise { + try { + let data = query.toHttpRequest(); + let response = await this.doPostGeneric("vm-values/query", data); + let queryResponse = QueryResponse.fromHttpResponse(response.data || response.vmOutput) + return queryResponse; + } catch (err: any) { + throw ErrContractQuery.increaseSpecificity(err); + } + } + + getNetworkStake(): Promise { + // TODO: Implement wrt.: + // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/stake/stake.service.ts + throw new Error("Method not implemented."); + } + + getNetworkStats(): Promise { + // TODO: Implement wrt. (full implementation may not be possible): + // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/network/network.service.ts + throw new Error("Method not implemented."); + } + + getToken(_tokenIdentifier: string): Promise { + // TODO: Implement wrt.: + // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/esdt/esdt.service.ts#L221 + throw new Error("Method not implemented."); + } + + getDefinitionOfTokenCollection(): Promise { + // TODO: Implement wrt.: + // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/collections/collection.service.ts + // https://docs.elrond.com/developers/esdt-tokens/#get-esdt-token-properties + throw new Error("Method not implemented."); + } + + async doGetGeneric(resourceUrl: string): Promise { + let response = await this.doGet(resourceUrl); + return response; + } + + async doPostGeneric(resourceUrl: string, payload: any): Promise { + let response = await this.doPost(resourceUrl, payload); + return response; + } + + private async doGet(resourceUrl: string): Promise { + try { + let url = `${this.url}/${resourceUrl}`; + let response = await axios.get(url, this.config); + let payload = response.data.data; + return payload; + } catch (error) { + this.handleApiError(error, resourceUrl); + } + } + + private async doPost(resourceUrl: string, payload: any): Promise { + try { + let url = `${this.url}/${resourceUrl}`; + let response = await axios.post(url, payload, { + ...this.config, + headers: { + "Content-Type": "application/json", + }, + }); + let responsePayload = response.data.data; + return responsePayload; + } catch (error) { + this.handleApiError(error, resourceUrl); + } + } + + private buildUrlWithQueryParameters(endpoint: string, params: Record): string { + let searchParams = new URLSearchParams(); + + for (let [key, value] of Object.entries(params)) { + if (value) { + searchParams.append(key, value); + } + } + + return `${endpoint}?${searchParams.toString()}`; + } + + private handleApiError(error: any, resourceUrl: string) { + if (!error.response) { + Logger.warn(error); + throw new ErrApiProviderGet(resourceUrl, error.toString(), error); + } + + let errorData = error.response.data; + let originalErrorMessage = errorData.error || errorData.message || JSON.stringify(errorData); + throw new ErrApiProviderGet(resourceUrl, originalErrorMessage, error); + } +} From cbe64af51256ef5ddb0c85347029be6fc09aa31b Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 21 Feb 2022 15:19:31 +0200 Subject: [PATCH 002/133] Sketch implementation. --- .../networkProvider/apiNetworkProvider.ts | 184 ++++++++++++++++++ .../networkProvider/proxyNetworkProvider.ts | 40 ++-- 2 files changed, 207 insertions(+), 17 deletions(-) create mode 100644 src-network-providers/networkProvider/apiNetworkProvider.ts diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts new file mode 100644 index 00000000..cae27e70 --- /dev/null +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -0,0 +1,184 @@ +import axios, { AxiosRequestConfig } from "axios"; +import { BigNumber } from "bignumber.js"; +import { AccountOnNetwork, TokenOfAccountOnNetwork } from "../account"; +import { Address } from "../address"; +import { defaultConfig } from "../constants"; +import { ErrApiProviderGet, ErrContractQuery } from "../errors"; +import { INetworkProvider } from "../interface.networkProvider"; +import { Logger } from "../logger"; +import { NetworkConfig } from "../networkConfig"; +import { NetworkStake } from "../networkStake"; +import { NetworkStatus } from "../networkStatus"; +import { NFTToken } from "../nftToken"; +import { Query, QueryResponse } from "../smartcontracts"; +import { getHexMagnitudeOfBigInt } from "../smartcontracts/codec/utils"; +import { Stats } from "../stats"; +import { Token } from "../token"; +import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; +import { TransactionOnNetwork } from "../transactionOnNetwork"; +import { ProxyNetworkProvider } from "./proxyNetworkProvider"; + +/** + * This is a temporary change, this will be the only provider used, ProxyProvider will be deprecated + */ +export class ApiNetworkProvider implements INetworkProvider { + private url: string; + private config: AxiosRequestConfig; + private backingProxyNetworkProvider; + + /** + * Creates a new ApiProvider. + * @param url the URL of the Elrond Api + * @param config axios request config options + */ + constructor(url: string, config?: AxiosRequestConfig) { + this.url = url; + this.config = { ...defaultConfig, ...config }; + this.backingProxyNetworkProvider = new ProxyNetworkProvider(url, config); + } + + async getNetworkConfig(): Promise { + return await this.backingProxyNetworkProvider.getNetworkConfig(); + } + + async getNetworkStatus(): Promise { + return await this.backingProxyNetworkProvider.getNetworkStatus(); + } + + async getNetworkStake(): Promise { + let response = await this.doGetGeneric("stake"); + let networkStake = NetworkStake.fromHttpResponse(response) + return networkStake; + } + + async getNetworkStats(): Promise { + let response = await this.doGetGeneric("stats"); + let stats = Stats.fromHttpResponse(response) + return stats; + } + + async getAccount(address: Address): Promise { + let response = await this.doGetGeneric(`accounts/${address.bech32()}`); + let account = AccountOnNetwork.fromHttpResponse(response); + return account; + } + + async getAddressEsdtList(address: Address): Promise { + let url = `accounts/${address.bech32()}/tokens`; + let response: any[] = await this.doGetGeneric(url); + let tokens = response.map(item => TokenOfAccountOnNetwork.fromHttpResponse(item)); + return tokens; + } + + async getAddressEsdt(address: Address, tokenIdentifier: string): Promise { + let response = await this.doGetGeneric(`accounts/${address.bech32()}/tokens/${tokenIdentifier}`); + let tokenData = response.tokenData; + return tokenData; + } + + async getAddressNft(address: Address, collection: string, nonce: BigNumber.Value): Promise { + let nonceHex = getHexMagnitudeOfBigInt(new BigNumber(nonce)); + let response = await this.doGetGeneric(`accounts/${address.bech32()}/nfts/${collection}-${nonceHex}`); + let tokenData = response.tokenData; + return tokenData; + } + + async getTransaction(txHash: TransactionHash): Promise { + let response = await this.doGetGeneric(`transactions/${txHash.toString()}`); + let transaction = TransactionOnNetwork.fromHttpResponse(txHash, response.transaction); + return transaction; + } + + async getTransactionStatus(txHash: TransactionHash): Promise { + let response = await this.doGetGeneric(`transactions/${txHash.toString()}?fields=status`); + let status = new TransactionStatus(response.status); + return status; + } + + async sendTransaction(tx: Transaction): Promise { + let response = await this.doPostGeneric("transactions", tx.toSendable()); + // Also see: https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/transactions/entities/transaction.send.result.ts + let hash = new TransactionHash(response.txHash); + return hash; + } + + async simulateTransaction(tx: Transaction): Promise { + return await this.backingProxyNetworkProvider.simulateTransaction(tx); + } + + async queryContract(query: Query): Promise { + try { + let data = query.toHttpRequest(); + let response = await this.doPostGeneric("query", data); + let queryResponse = QueryResponse.fromHttpResponse(response) + return queryResponse; + } catch (err: any) { + throw ErrContractQuery.increaseSpecificity(err); + } + } + + async getToken(tokenIdentifier: string): Promise { + let response = await this.doGetGeneric(`tokens/${tokenIdentifier}`); + let token = Token.fromHttpResponse(response); + return token; + } + + async getNFTToken(tokenIdentifier: string): Promise { + let response = await this.doGetGeneric(`nfts/${tokenIdentifier}`); + let token = NFTToken.fromHttpResponse(response); + return token; + } + + async getDefinitionOfTokenCollection(collection: string): Promise { + let response = await this.doGetGeneric(`collections/${collection}`); + return response; + } + + async doGetGeneric(resourceUrl: string): Promise { + let response = await this.doGet(resourceUrl); + return response; + } + + async doPostGeneric(resourceUrl: string, payload: any): Promise { + let response = await this.doPost(resourceUrl, payload); + return response; + } + + private async doGet(resourceUrl: string): Promise { + try { + let url = `${this.url}/${resourceUrl}`; + let response = await axios.get(url, this.config); + + return response.data; + } catch (error) { + this.handleApiError(error, resourceUrl); + } + } + + private async doPost(resourceUrl: string, payload: any): Promise { + try { + let url = `${this.url}/${resourceUrl}`; + let response = await axios.post(url, payload, { + ...this.config, + headers: { + "Content-Type": "application/json", + }, + }); + let responsePayload = response.data; + return responsePayload; + } catch (error) { + this.handleApiError(error, resourceUrl); + } + } + + private handleApiError(error: any, resourceUrl: string) { + if (!error.response) { + Logger.warn(error); + throw new ErrApiProviderGet(resourceUrl, error.toString(), error); + } + + let errorData = error.response.data; + let originalErrorMessage = errorData.error || errorData.message || JSON.stringify(errorData); + throw new ErrApiProviderGet(resourceUrl, originalErrorMessage, error); + } +} diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index 643e0f9a..6f819b27 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -9,6 +9,7 @@ import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; +import { NFTToken } from "../nftToken"; import { Query, QueryResponse } from "../smartcontracts"; import { Stats } from "../stats"; import { Token } from "../token"; @@ -16,7 +17,7 @@ import { Transaction, TransactionHash, TransactionStatus } from "../transaction" import { TransactionOnNetwork } from "../transactionOnNetwork"; -export class NetworkProxyProvider implements INetworkProvider { +export class ProxyNetworkProvider implements INetworkProvider { private url: string; private config: AxiosRequestConfig; @@ -42,6 +43,18 @@ export class NetworkProxyProvider implements INetworkProvider { return networkStatus; } + async getNetworkStake(): Promise { + // TODO: Implement wrt.: + // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/stake/stake.service.ts + throw new Error("Method not implemented."); + } + + async getNetworkStats(): Promise { + // TODO: Implement wrt. (full implementation may not be possible): + // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/network/network.service.ts + throw new Error("Method not implemented."); + } + async getAccount(address: Address): Promise { let response = await this.doGetGeneric(`address/${address.bech32()}`); let account = AccountOnNetwork.fromHttpResponse(response.account); @@ -61,8 +74,8 @@ export class NetworkProxyProvider implements INetworkProvider { return tokenData; } - async getAddressNft(address: Address, tokenIdentifier: string, nonce: BigNumber.Value): Promise { - let response = await this.doGetGeneric(`address/${address.bech32()}/nft/${tokenIdentifier}/nonce/${nonce}`); + async getAddressNft(address: Address, collection: string, nonce: BigNumber.Value): Promise { + let response = await this.doGetGeneric(`address/${address.bech32()}/nft/${collection}/nonce/${nonce}`); let tokenData = response.tokenData; return tokenData; } @@ -86,12 +99,12 @@ export class NetworkProxyProvider implements INetworkProvider { async sendTransaction(tx: Transaction): Promise { let response = await this.doPostGeneric("transaction/send", tx.toSendable()); - let hash = new TransactionHash(response.txHash) + let hash = new TransactionHash(response.txHash); return hash; } async simulateTransaction(tx: Transaction): Promise { - let response = await this.doPostGeneric("transaction/simulate", tx.toSendable(), (response) => response); + let response = await this.doPostGeneric("transaction/simulate", tx.toSendable()); return response; } @@ -99,32 +112,25 @@ export class NetworkProxyProvider implements INetworkProvider { try { let data = query.toHttpRequest(); let response = await this.doPostGeneric("vm-values/query", data); - let queryResponse = QueryResponse.fromHttpResponse(response.data || response.vmOutput) + let queryResponse = QueryResponse.fromHttpResponse(response.data) return queryResponse; } catch (err: any) { throw ErrContractQuery.increaseSpecificity(err); } } - getNetworkStake(): Promise { + async getToken(_tokenIdentifier: string): Promise { // TODO: Implement wrt.: - // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/stake/stake.service.ts - throw new Error("Method not implemented."); - } - - getNetworkStats(): Promise { - // TODO: Implement wrt. (full implementation may not be possible): - // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/network/network.service.ts + // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/esdt/esdt.service.ts#L221 throw new Error("Method not implemented."); } - getToken(_tokenIdentifier: string): Promise { + async getNFTToken(_tokenIdentifier: string): Promise { // TODO: Implement wrt.: - // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/esdt/esdt.service.ts#L221 throw new Error("Method not implemented."); } - getDefinitionOfTokenCollection(): Promise { + async getDefinitionOfTokenCollection(_collection: string): Promise { // TODO: Implement wrt.: // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/collections/collection.service.ts // https://docs.elrond.com/developers/esdt-tokens/#get-esdt-token-properties From cc9324b2bfbdb2eabd8b3b0e569d61c31e9e2133 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 21 Feb 2022 19:34:09 +0200 Subject: [PATCH 003/133] WIP. --- .../networkProvider/apiNetworkProvider.ts | 28 ++++++---- .../networkProvider/index.ts | 2 + .../networkProvider/proxyNetworkProvider.ts | 34 ++++++++---- .../networkProvider/tokens.ts | 54 +++++++++++++++++++ 4 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 src-network-providers/networkProvider/index.ts create mode 100644 src-network-providers/networkProvider/tokens.ts diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index cae27e70..fec48aa1 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -1,6 +1,6 @@ import axios, { AxiosRequestConfig } from "axios"; import { BigNumber } from "bignumber.js"; -import { AccountOnNetwork, TokenOfAccountOnNetwork } from "../account"; +import { AccountOnNetwork } from "../account"; import { Address } from "../address"; import { defaultConfig } from "../constants"; import { ErrApiProviderGet, ErrContractQuery } from "../errors"; @@ -17,6 +17,7 @@ import { Token } from "../token"; import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; import { TransactionOnNetwork } from "../transactionOnNetwork"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; +import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; /** * This is a temporary change, this will be the only provider used, ProxyProvider will be deprecated @@ -45,13 +46,13 @@ export class ApiNetworkProvider implements INetworkProvider { return await this.backingProxyNetworkProvider.getNetworkStatus(); } - async getNetworkStake(): Promise { + async getNetworkStakeStatistics(): Promise { let response = await this.doGetGeneric("stake"); let networkStake = NetworkStake.fromHttpResponse(response) return networkStake; } - async getNetworkStats(): Promise { + async getNetworkGeneralStatistics(): Promise { let response = await this.doGetGeneric("stats"); let stats = Stats.fromHttpResponse(response) return stats; @@ -63,23 +64,32 @@ export class ApiNetworkProvider implements INetworkProvider { return account; } - async getAddressEsdtList(address: Address): Promise { + async getFungibleTokensOfAccount(address: Address): Promise { let url = `accounts/${address.bech32()}/tokens`; let response: any[] = await this.doGetGeneric(url); - let tokens = response.map(item => TokenOfAccountOnNetwork.fromHttpResponse(item)); + let tokens = response.map(item => FungibleTokenOfAccountOnNetwork.fromHttpResponse(item)); + tokens.sort((a, b) => a.tokenIdentifier.localeCompare(b.tokenIdentifier)); return tokens; } - async getAddressEsdt(address: Address, tokenIdentifier: string): Promise { + async getNonFungibleTokensOfAccount(address: Address): Promise { + let url = `accounts/${address.bech32()}/nfts`; + let response: any[] = await this.doGetGeneric(url); + let tokens = response.map(item => NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(item)); + tokens.sort((a, b) => a.tokenIdentifier.localeCompare(b.tokenIdentifier)); + return tokens; + } + + async getFungibleTokenOfAccount(address: Address, tokenIdentifier: string): Promise { let response = await this.doGetGeneric(`accounts/${address.bech32()}/tokens/${tokenIdentifier}`); - let tokenData = response.tokenData; + let tokenData = FungibleTokenOfAccountOnNetwork.fromHttpResponse(response.tokenData); return tokenData; } - async getAddressNft(address: Address, collection: string, nonce: BigNumber.Value): Promise { + async getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: BigNumber.Value): Promise { let nonceHex = getHexMagnitudeOfBigInt(new BigNumber(nonce)); let response = await this.doGetGeneric(`accounts/${address.bech32()}/nfts/${collection}-${nonceHex}`); - let tokenData = response.tokenData; + let tokenData = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response.tokenData); return tokenData; } diff --git a/src-network-providers/networkProvider/index.ts b/src-network-providers/networkProvider/index.ts new file mode 100644 index 00000000..0969c4db --- /dev/null +++ b/src-network-providers/networkProvider/index.ts @@ -0,0 +1,2 @@ +export * from "./apiNetworkProvider"; +export * from "./proxyNetworkProvider"; diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index 6f819b27..9f77bcc4 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -1,6 +1,6 @@ import axios, { AxiosRequestConfig } from "axios"; import { BigNumber } from "bignumber.js"; -import { AccountOnNetwork, TokenOfAccountOnNetwork } from "../account"; +import { AccountOnNetwork } from "../account"; import { Address } from "../address"; import { defaultConfig } from "../constants"; import { ErrApiProviderGet, ErrContractQuery } from "../errors"; @@ -15,6 +15,7 @@ import { Stats } from "../stats"; import { Token } from "../token"; import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; import { TransactionOnNetwork } from "../transactionOnNetwork"; +import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; export class ProxyNetworkProvider implements INetworkProvider { @@ -43,13 +44,13 @@ export class ProxyNetworkProvider implements INetworkProvider { return networkStatus; } - async getNetworkStake(): Promise { + async getNetworkStakeStatistics(): Promise { // TODO: Implement wrt.: // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/stake/stake.service.ts throw new Error("Method not implemented."); } - async getNetworkStats(): Promise { + async getNetworkGeneralStatistics(): Promise { // TODO: Implement wrt. (full implementation may not be possible): // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/network/network.service.ts throw new Error("Method not implemented."); @@ -61,22 +62,37 @@ export class ProxyNetworkProvider implements INetworkProvider { return account; } - async getAddressEsdtList(address: Address): Promise { + async getFungibleTokensOfAccount(address: Address): Promise { let url = `address/${address.bech32()}/esdt`; let response = await this.doGetGeneric(url); - let tokens = Object.values(response.esdts).map(item => TokenOfAccountOnNetwork.fromHttpResponse(item)); + let responseItems: any[] = Object.values(response.esdts); + // Skip NFTs / SFTs. + let responseItemsFiltered = responseItems.filter(item => !item.attributes); + let tokens = responseItemsFiltered.map(item => FungibleTokenOfAccountOnNetwork.fromHttpResponse(item)); + tokens.sort((a, b) => a.tokenIdentifier.localeCompare(b.tokenIdentifier)); return tokens; } - async getAddressEsdt(address: Address, tokenIdentifier: string): Promise { + async getNonFungibleTokensOfAccount(address: Address): Promise { + let url = `address/${address.bech32()}/esdt`; + let response = await this.doGetGeneric(url); + let responseItems: any[] = Object.values(response.esdts); + // Skip fungible tokens. + let responseItemsFiltered = responseItems.filter(item => item.nonce >= 0); + let tokens = responseItemsFiltered.map(item => NonFungibleTokenOfAccountOnNetwork.fromProxyHttpResponse(item)); + tokens.sort((a, b) => a.tokenIdentifier.localeCompare(b.tokenIdentifier)); + return tokens; + } + + async getFungibleTokenOfAccount(address: Address, tokenIdentifier: string): Promise { let response = await this.doGetGeneric(`address/${address.bech32()}/esdt/${tokenIdentifier}`); - let tokenData = response.tokenData; + let tokenData = FungibleTokenOfAccountOnNetwork.fromHttpResponse(response.tokenData); return tokenData; } - async getAddressNft(address: Address, collection: string, nonce: BigNumber.Value): Promise { + async getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: BigNumber.Value): Promise { let response = await this.doGetGeneric(`address/${address.bech32()}/nft/${collection}/nonce/${nonce}`); - let tokenData = response.tokenData; + let tokenData = NonFungibleTokenOfAccountOnNetwork.fromProxyHttpResponse(response.tokenData); return tokenData; } diff --git a/src-network-providers/networkProvider/tokens.ts b/src-network-providers/networkProvider/tokens.ts new file mode 100644 index 00000000..fdb780f9 --- /dev/null +++ b/src-network-providers/networkProvider/tokens.ts @@ -0,0 +1,54 @@ +import { BigNumber } from "bignumber.js"; +import { Address } from "../address"; +import { IFungibleTokenOfAccountOnNetwork, INonFungibleTokenOfAccountOnNetwork } from "../interface.networkProvider"; +import { Nonce } from "../nonce"; + +export class FungibleTokenOfAccountOnNetwork implements IFungibleTokenOfAccountOnNetwork { + tokenIdentifier: string = ""; + balance: BigNumber = new BigNumber(0); + + static fromHttpResponse(payload: any): FungibleTokenOfAccountOnNetwork { + let result = new FungibleTokenOfAccountOnNetwork(); + + result.tokenIdentifier = payload.tokenIdentifier || payload.identifier || ""; + result.balance = new BigNumber(payload.balance || 0); + + return result; + } +} + +export class NonFungibleTokenOfAccountOnNetwork implements INonFungibleTokenOfAccountOnNetwork { + tokenIdentifier: string = ""; + attributes: Buffer = Buffer.from([]); + balance: BigNumber = new BigNumber(0); + nonce: Nonce = new Nonce(0); + creator: Address = new Address(""); + royalties: BigNumber = new BigNumber(0); + + static fromProxyHttpResponse(payload: any): NonFungibleTokenOfAccountOnNetwork { + let result = new NonFungibleTokenOfAccountOnNetwork(); + + result.tokenIdentifier = payload.tokenIdentifier || payload.identifier || ""; + result.attributes = Buffer.from(payload.attributes || "", "base64"); + result.balance = new BigNumber(payload.balance || 0); + result.nonce = new Nonce(payload.nonce || 0); + result.creator = new Address(payload.creator || ""); + result.royalties = new BigNumber(payload.royalties || 0).div(100); + + return result; + } + + static fromApiHttpResponse(payload: any): NonFungibleTokenOfAccountOnNetwork { + let result = new NonFungibleTokenOfAccountOnNetwork(); + + result.tokenIdentifier = payload.tokenIdentifier || payload.identifier || ""; + result.attributes = Buffer.from(payload.attributes || "", "base64"); + // On API, missing balance means NFT. + result.balance = new BigNumber(payload.balance || 1); + result.nonce = new Nonce(payload.nonce || 0); + result.creator = new Address(payload.creator || ""); + result.royalties = new BigNumber(payload.royalties || 0); + + return result; + } +} From 807fa8cf4b617c710391c985a50b8fdb49b65c22 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 21 Feb 2022 23:02:02 +0200 Subject: [PATCH 004/133] WIP. Tests. --- .../networkProvider/apiNetworkProvider.ts | 31 ++-- .../networkProvider/providers.dev.net.spec.ts | 149 ++++++++++++++++++ .../networkProvider/proxyNetworkProvider.ts | 17 +- 3 files changed, 179 insertions(+), 18 deletions(-) create mode 100644 src-network-providers/networkProvider/providers.dev.net.spec.ts diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index fec48aa1..c82b3a71 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -4,7 +4,7 @@ import { AccountOnNetwork } from "../account"; import { Address } from "../address"; import { defaultConfig } from "../constants"; import { ErrApiProviderGet, ErrContractQuery } from "../errors"; -import { INetworkProvider } from "../interface.networkProvider"; +import { IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, Pagination } from "../interface.networkProvider"; import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; @@ -19,9 +19,6 @@ import { TransactionOnNetwork } from "../transactionOnNetwork"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; -/** - * This is a temporary change, this will be the only provider used, ProxyProvider will be deprecated - */ export class ApiNetworkProvider implements INetworkProvider { private url: string; private config: AxiosRequestConfig; @@ -64,29 +61,37 @@ export class ApiNetworkProvider implements INetworkProvider { return account; } - async getFungibleTokensOfAccount(address: Address): Promise { - let url = `accounts/${address.bech32()}/tokens`; + async getFungibleTokensOfAccount(address: Address, pagination?: Pagination): Promise { + pagination = pagination || Pagination.default(); + + let url = `accounts/${address.bech32()}/tokens?${this.buildPaginationParams(pagination)}`; let response: any[] = await this.doGetGeneric(url); let tokens = response.map(item => FungibleTokenOfAccountOnNetwork.fromHttpResponse(item)); + + // TODO: Fix sorting tokens.sort((a, b) => a.tokenIdentifier.localeCompare(b.tokenIdentifier)); return tokens; } - async getNonFungibleTokensOfAccount(address: Address): Promise { - let url = `accounts/${address.bech32()}/nfts`; + async getNonFungibleTokensOfAccount(address: Address, pagination?: Pagination): Promise { + pagination = pagination || Pagination.default(); + + let url = `accounts/${address.bech32()}/nfts?${this.buildPaginationParams(pagination)}`; let response: any[] = await this.doGetGeneric(url); let tokens = response.map(item => NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(item)); + + // TODO: Fix sorting tokens.sort((a, b) => a.tokenIdentifier.localeCompare(b.tokenIdentifier)); return tokens; } - async getFungibleTokenOfAccount(address: Address, tokenIdentifier: string): Promise { + async getFungibleTokenOfAccount(address: Address, tokenIdentifier: string): Promise { let response = await this.doGetGeneric(`accounts/${address.bech32()}/tokens/${tokenIdentifier}`); - let tokenData = FungibleTokenOfAccountOnNetwork.fromHttpResponse(response.tokenData); + let tokenData = FungibleTokenOfAccountOnNetwork.fromHttpResponse(response); return tokenData; } - async getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: BigNumber.Value): Promise { + async getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: BigNumber.Value): Promise { let nonceHex = getHexMagnitudeOfBigInt(new BigNumber(nonce)); let response = await this.doGetGeneric(`accounts/${address.bech32()}/nfts/${collection}-${nonceHex}`); let tokenData = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response.tokenData); @@ -154,6 +159,10 @@ export class ApiNetworkProvider implements INetworkProvider { return response; } + private buildPaginationParams(pagination: Pagination) { + return `from=${pagination.from}&size=${pagination.size}`; + } + private async doGet(resourceUrl: string): Promise { try { let url = `${this.url}/${resourceUrl}`; diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts new file mode 100644 index 00000000..a0a9c7d2 --- /dev/null +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -0,0 +1,149 @@ +import { assert } from "chai"; +import { ApiNetworkProvider, ProxyNetworkProvider } from "."; +import { Hash } from "../hash"; +import { TransactionOnNetwork, TransactionOnNetworkType } from "../transactionOnNetwork"; +import { INetworkProvider } from "../interface.networkProvider"; +import { Address } from "../address"; +import { loadTestWallets, TestWallet } from "../testutils"; + +describe("test network providers on devnet: Proxy and API", function () { + let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 5000 }); + let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.elrond.com", { timeout: 5000 }); + + let alice: TestWallet; + let bob: TestWallet; + let carol: TestWallet; + let dan: TestWallet; + + before(async function () { + ({ alice, bob, carol, dan } = await loadTestWallets()); + }); + + it("should have same response for getNetworkConfig()", async function () { + let apiResponse = await apiProvider.getNetworkConfig(); + let proxyResponse = await proxyProvider.getNetworkConfig(); + assert.deepEqual(apiResponse, proxyResponse); + }); + + it("should have same response for getNetworkStatus()", async function () { + let apiResponse = await apiProvider.getNetworkStatus(); + let proxyResponse = await proxyProvider.getNetworkStatus(); + assert.deepEqual(apiResponse, proxyResponse); + }); + + // TODO: Enable test after implementing ProxyNetworkProvider.getNetworkStakeStatistics(). + it.skip("should have same response for getNetworkStakeStatistics()", async function () { + let apiResponse = await apiProvider.getNetworkStakeStatistics(); + let proxyResponse = await proxyProvider.getNetworkStakeStatistics(); + assert.deepEqual(apiResponse, proxyResponse); + }); + + // TODO: Enable test after implementing ProxyNetworkProvider.getNetworkGeneralStatistics(). + it.skip("should have same response for getNetworkGeneralStatistics()", async function () { + let apiResponse = await apiProvider.getNetworkGeneralStatistics(); + let proxyResponse = await proxyProvider.getNetworkGeneralStatistics(); + assert.deepEqual(apiResponse, proxyResponse); + }); + + it("should have same response for getAccount()", async function () { + for (const user of [alice, bob, carol, dan]) { + let apiResponse = await apiProvider.getAccount(user.address); + let proxyResponse = await proxyProvider.getAccount(user.address); + assert.deepEqual(apiResponse, proxyResponse); + } + }); + + it.only("should have same response for getFungibleTokensOfAccount(), getFungibleTokenOfAccount()", async function () { + this.timeout(10000); + + for (const user of [alice, bob, carol, dan]) { + let apiResponse = await apiProvider.getFungibleTokensOfAccount(user.address); + let proxyResponse = await proxyProvider.getFungibleTokensOfAccount(user.address); + assert.deepEqual(apiResponse.slice(0, 100), proxyResponse.slice(0, 100)); + + for (const item of apiResponse.slice(0, 5)) { + let apiResponse = await apiProvider.getFungibleTokenOfAccount(user.address, item.tokenIdentifier); + let proxyResponse = await proxyProvider.getFungibleTokenOfAccount(user.address, item.tokenIdentifier); + //assert.deepEqual(apiResponse, proxyResponse, `user: ${user.address.bech32()}, token: ${item.tokenIdentifier}`); + } + } + }); + + it("should have same response for getNonFungibleTokensOfAccount(), getNonFungibleTokenOfAccount", async function () { + this.timeout(10000); + + for (const user of [alice, bob, carol, dan]) { + let apiResponse = await apiProvider.getNonFungibleTokensOfAccount(user.address); + let proxyResponse = await proxyProvider.getNonFungibleTokensOfAccount(user.address); + assert.deepEqual(apiResponse.slice(0, 100), proxyResponse.slice(0, 100)); + + for (const item of apiResponse.slice(0, 5)) { + // let apiResponse = await apiProvider.getNonFungibleTokenOfAccount(user.address, item.tokenIdentifier); + // let proxyResponse = await proxyProvider.getNonFungibleTokenOfAccount(user.address, item.tokenIdentifier); + assert.deepEqual(apiResponse, proxyResponse, `user: ${user.address.bech32()}, token: ${item.tokenIdentifier}`); + } + } + }); + + // it("check get transaction", async function () { + // this.timeout(20000); + + // let sender = new Address("erd1testnlersh4z0wsv8kjx39me4rmnvjkwu8dsaea7ukdvvc9z396qykv7z7"); + // let proxyProvider = chooseProxyProvider("elrond-devnet"); + // let apiProvider = chooseApiProvider("elrond-devnet"); + + // let hashes = [ + // new TransactionHash("b41f5fc39e96b1f194d07761c6efd6cb92278b95f5012ab12cbc910058ca8b54"), + // new TransactionHash("7757397a59378e9d0f6d5f08cc934c260e33a50ae0d73fdf869f7c02b6b47b33"), + // new TransactionHash("b87238089e81527158a6daee520280324bc7e5322ba54d1b3c9a5678abe953ea"), + // new TransactionHash("b45dd5e598bc85ba71639f2cbce8c5dff2fbe93159e637852fddeb16c0e84a48"), + // new TransactionHash("83db780e98d4d3c917668c47b33ba51445591efacb0df2a922f88e7dfbb5fc7d"), + // new TransactionHash("c2eb62b28cc7320da2292d87944c5424a70e1f443323c138c1affada7f6e9705") + // ] + + // for (const hash of hashes) { + // let transactionOnProxy = await proxyProvider.getTransaction(hash, sender, true); + // let transactionOnAPI = await apiProvider.getTransaction(hash); + + // ignoreKnownDifferencesBetweenProviders(transactionOnProxy, transactionOnAPI); + // assert.deepEqual(transactionOnProxy, transactionOnAPI); + // } + // }); + + // // TODO: Strive to have as little differences as possible between Proxy and API. + // // ... On client-side (erdjs), try to handle the differences in ProxyProvider & ApiProvider, or in TransactionOnNetwork. + // // ... Merging the providers (in the future) should solve this as well. + // function ignoreKnownDifferencesBetweenProviders(transactionOnProxy: TransactionOnNetwork, transactionOnAPI: TransactionOnNetwork) { + // // Ignore status, since it differs between Proxy and API (for smart contract calls): + // transactionOnProxy.status = new TransactionStatus("unknown"); + // transactionOnAPI.status = new TransactionStatus("unknown"); + + // // Ignore fields which are not present on API response: + // transactionOnProxy.epoch = 0; + // transactionOnProxy.type = new TransactionOnNetworkType(); + // transactionOnProxy.blockNonce = new Nonce(0); + // transactionOnProxy.hyperblockNonce = new Nonce(0); + // transactionOnProxy.hyperblockHash = new Hash(""); + + // let immediateContractResultOnAPI: SmartContractResultItem = (transactionOnAPI).results.immediate; + // let contractResultsOnAPI: SmartContractResultItem[] = (transactionOnAPI).results.items; + // let resultingCallsOnAPI: SmartContractResultItem[] = (transactionOnAPI).results.resultingCalls; + // let allContractResults = [immediateContractResultOnAPI].concat(resultingCallsOnAPI).concat(contractResultsOnAPI); + + // // Important issue (existing bug)! When working with TransactionOnNetwork objects, SCRs cannot be parsed correctly from API, only from Proxy. + // // On API response, base64 decode "data" from smart contract results: + // for (const item of allContractResults) { + // item.data = Buffer.from(item.data, "base64").toString(); + // } + + // // On API response, convert "callType" of smart contract results to a number: + // for (const item of allContractResults) { + // item.callType = Number(item.callType); + // } + + // // On API response, sort contract results by nonce: + // contractResultsOnAPI.sort(function (a: SmartContractResultItem, b: SmartContractResultItem) { + // return a.nonce.valueOf() - b.nonce.valueOf(); + // }); + // } +}); diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index 9f77bcc4..340b060c 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -4,7 +4,7 @@ import { AccountOnNetwork } from "../account"; import { Address } from "../address"; import { defaultConfig } from "../constants"; import { ErrApiProviderGet, ErrContractQuery } from "../errors"; -import { INetworkProvider } from "../interface.networkProvider"; +import { IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, Pagination } from "../interface.networkProvider"; import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; @@ -17,7 +17,6 @@ import { Transaction, TransactionHash, TransactionStatus } from "../transaction" import { TransactionOnNetwork } from "../transactionOnNetwork"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; - export class ProxyNetworkProvider implements INetworkProvider { private url: string; private config: AxiosRequestConfig; @@ -62,35 +61,39 @@ export class ProxyNetworkProvider implements INetworkProvider { return account; } - async getFungibleTokensOfAccount(address: Address): Promise { + async getFungibleTokensOfAccount(address: Address, _pagination?: Pagination): Promise { let url = `address/${address.bech32()}/esdt`; let response = await this.doGetGeneric(url); let responseItems: any[] = Object.values(response.esdts); // Skip NFTs / SFTs. - let responseItemsFiltered = responseItems.filter(item => !item.attributes); + let responseItemsFiltered = responseItems.filter(item => !item.nonce); let tokens = responseItemsFiltered.map(item => FungibleTokenOfAccountOnNetwork.fromHttpResponse(item)); + + // TODO: Fix sorting tokens.sort((a, b) => a.tokenIdentifier.localeCompare(b.tokenIdentifier)); return tokens; } - async getNonFungibleTokensOfAccount(address: Address): Promise { + async getNonFungibleTokensOfAccount(address: Address, _pagination?: Pagination): Promise { let url = `address/${address.bech32()}/esdt`; let response = await this.doGetGeneric(url); let responseItems: any[] = Object.values(response.esdts); // Skip fungible tokens. let responseItemsFiltered = responseItems.filter(item => item.nonce >= 0); let tokens = responseItemsFiltered.map(item => NonFungibleTokenOfAccountOnNetwork.fromProxyHttpResponse(item)); + + // TODO: Fix sorting tokens.sort((a, b) => a.tokenIdentifier.localeCompare(b.tokenIdentifier)); return tokens; } - async getFungibleTokenOfAccount(address: Address, tokenIdentifier: string): Promise { + async getFungibleTokenOfAccount(address: Address, tokenIdentifier: string): Promise { let response = await this.doGetGeneric(`address/${address.bech32()}/esdt/${tokenIdentifier}`); let tokenData = FungibleTokenOfAccountOnNetwork.fromHttpResponse(response.tokenData); return tokenData; } - async getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: BigNumber.Value): Promise { + async getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: BigNumber.Value): Promise { let response = await this.doGetGeneric(`address/${address.bech32()}/nft/${collection}/nonce/${nonce}`); let tokenData = NonFungibleTokenOfAccountOnNetwork.fromProxyHttpResponse(response.tokenData); return tokenData; From 4ab793ef077da44340417fa859df0c07eac4f649 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 22 Feb 2022 11:31:00 +0200 Subject: [PATCH 005/133] WIP. --- .../networkProvider/apiNetworkProvider.ts | 17 ++- .../networkProvider/index.ts | 3 + .../networkProvider/providers.dev.net.spec.ts | 118 +++++++----------- .../networkProvider/proxyNetworkProvider.ts | 14 +-- .../networkProvider/tokens.ts | 13 +- .../networkProvider/transactions.ts | 90 +++++++++++++ 6 files changed, 165 insertions(+), 90 deletions(-) create mode 100644 src-network-providers/networkProvider/transactions.ts diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index c82b3a71..93eddac8 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -4,20 +4,20 @@ import { AccountOnNetwork } from "../account"; import { Address } from "../address"; import { defaultConfig } from "../constants"; import { ErrApiProviderGet, ErrContractQuery } from "../errors"; -import { IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, Pagination } from "../interface.networkProvider"; +import { IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, Pagination } from "../interface.networkProvider"; import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; import { NFTToken } from "../nftToken"; +import { Nonce } from "../nonce"; import { Query, QueryResponse } from "../smartcontracts"; -import { getHexMagnitudeOfBigInt } from "../smartcontracts/codec/utils"; import { Stats } from "../stats"; import { Token } from "../token"; import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; -import { TransactionOnNetwork } from "../transactionOnNetwork"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; +import { TransactionOnNetwork } from "./transactions"; export class ApiNetworkProvider implements INetworkProvider { private url: string; @@ -91,16 +91,15 @@ export class ApiNetworkProvider implements INetworkProvider { return tokenData; } - async getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: BigNumber.Value): Promise { - let nonceHex = getHexMagnitudeOfBigInt(new BigNumber(nonce)); - let response = await this.doGetGeneric(`accounts/${address.bech32()}/nfts/${collection}-${nonceHex}`); - let tokenData = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response.tokenData); + async getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: Nonce): Promise { + let response = await this.doGetGeneric(`accounts/${address.bech32()}/nfts/${collection}-${nonce.hex()}`); + let tokenData = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response); return tokenData; } - async getTransaction(txHash: TransactionHash): Promise { + async getTransaction(txHash: TransactionHash): Promise { let response = await this.doGetGeneric(`transactions/${txHash.toString()}`); - let transaction = TransactionOnNetwork.fromHttpResponse(txHash, response.transaction); + let transaction = TransactionOnNetwork.fromApiHttpResponse(txHash, response); return transaction; } diff --git a/src-network-providers/networkProvider/index.ts b/src-network-providers/networkProvider/index.ts index 0969c4db..a4276ae7 100644 --- a/src-network-providers/networkProvider/index.ts +++ b/src-network-providers/networkProvider/index.ts @@ -1,2 +1,5 @@ export * from "./apiNetworkProvider"; export * from "./proxyNetworkProvider"; + +// do not export "./tokens" (encapsulation) +// do not export "./transactions" (encapsulation) diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts index a0a9c7d2..2ef52b30 100644 --- a/src-network-providers/networkProvider/providers.dev.net.spec.ts +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -1,10 +1,11 @@ import { assert } from "chai"; import { ApiNetworkProvider, ProxyNetworkProvider } from "."; import { Hash } from "../hash"; -import { TransactionOnNetwork, TransactionOnNetworkType } from "../transactionOnNetwork"; -import { INetworkProvider } from "../interface.networkProvider"; +import { INetworkProvider, ITransactionOnNetwork } from "../interface.networkProvider"; import { Address } from "../address"; import { loadTestWallets, TestWallet } from "../testutils"; +import { TransactionHash, TransactionStatus } from "../transaction"; +import { Nonce } from "../nonce"; describe("test network providers on devnet: Proxy and API", function () { let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 5000 }); @@ -53,7 +54,7 @@ describe("test network providers on devnet: Proxy and API", function () { } }); - it.only("should have same response for getFungibleTokensOfAccount(), getFungibleTokenOfAccount()", async function () { + it("should have same response for getFungibleTokensOfAccount(), getFungibleTokenOfAccount()", async function () { this.timeout(10000); for (const user of [alice, bob, carol, dan]) { @@ -61,15 +62,15 @@ describe("test network providers on devnet: Proxy and API", function () { let proxyResponse = await proxyProvider.getFungibleTokensOfAccount(user.address); assert.deepEqual(apiResponse.slice(0, 100), proxyResponse.slice(0, 100)); - for (const item of apiResponse.slice(0, 5)) { - let apiResponse = await apiProvider.getFungibleTokenOfAccount(user.address, item.tokenIdentifier); - let proxyResponse = await proxyProvider.getFungibleTokenOfAccount(user.address, item.tokenIdentifier); - //assert.deepEqual(apiResponse, proxyResponse, `user: ${user.address.bech32()}, token: ${item.tokenIdentifier}`); - } + // for (const item of apiResponse.slice(0, 5)) { + // let apiResponse = await apiProvider.getFungibleTokenOfAccount(user.address, item.tokenIdentifier); + // let proxyResponse = await proxyProvider.getFungibleTokenOfAccount(user.address, item.tokenIdentifier); + // //assert.deepEqual(apiResponse, proxyResponse, `user: ${user.address.bech32()}, token: ${item.tokenIdentifier}`); + // } } }); - it("should have same response for getNonFungibleTokensOfAccount(), getNonFungibleTokenOfAccount", async function () { + it.only("should have same response for getNonFungibleTokensOfAccount(), getNonFungibleTokenOfAccount", async function () { this.timeout(10000); for (const user of [alice, bob, carol, dan]) { @@ -78,72 +79,45 @@ describe("test network providers on devnet: Proxy and API", function () { assert.deepEqual(apiResponse.slice(0, 100), proxyResponse.slice(0, 100)); for (const item of apiResponse.slice(0, 5)) { - // let apiResponse = await apiProvider.getNonFungibleTokenOfAccount(user.address, item.tokenIdentifier); - // let proxyResponse = await proxyProvider.getNonFungibleTokenOfAccount(user.address, item.tokenIdentifier); + let apiResponse = await apiProvider.getNonFungibleTokenOfAccount(user.address, item.collection, item.nonce); + let proxyResponse = await proxyProvider.getNonFungibleTokenOfAccount(user.address, item.collection, item.nonce); assert.deepEqual(apiResponse, proxyResponse, `user: ${user.address.bech32()}, token: ${item.tokenIdentifier}`); } } }); - // it("check get transaction", async function () { - // this.timeout(20000); - - // let sender = new Address("erd1testnlersh4z0wsv8kjx39me4rmnvjkwu8dsaea7ukdvvc9z396qykv7z7"); - // let proxyProvider = chooseProxyProvider("elrond-devnet"); - // let apiProvider = chooseApiProvider("elrond-devnet"); - - // let hashes = [ - // new TransactionHash("b41f5fc39e96b1f194d07761c6efd6cb92278b95f5012ab12cbc910058ca8b54"), - // new TransactionHash("7757397a59378e9d0f6d5f08cc934c260e33a50ae0d73fdf869f7c02b6b47b33"), - // new TransactionHash("b87238089e81527158a6daee520280324bc7e5322ba54d1b3c9a5678abe953ea"), - // new TransactionHash("b45dd5e598bc85ba71639f2cbce8c5dff2fbe93159e637852fddeb16c0e84a48"), - // new TransactionHash("83db780e98d4d3c917668c47b33ba51445591efacb0df2a922f88e7dfbb5fc7d"), - // new TransactionHash("c2eb62b28cc7320da2292d87944c5424a70e1f443323c138c1affada7f6e9705") - // ] - - // for (const hash of hashes) { - // let transactionOnProxy = await proxyProvider.getTransaction(hash, sender, true); - // let transactionOnAPI = await apiProvider.getTransaction(hash); - - // ignoreKnownDifferencesBetweenProviders(transactionOnProxy, transactionOnAPI); - // assert.deepEqual(transactionOnProxy, transactionOnAPI); - // } - // }); - - // // TODO: Strive to have as little differences as possible between Proxy and API. - // // ... On client-side (erdjs), try to handle the differences in ProxyProvider & ApiProvider, or in TransactionOnNetwork. - // // ... Merging the providers (in the future) should solve this as well. - // function ignoreKnownDifferencesBetweenProviders(transactionOnProxy: TransactionOnNetwork, transactionOnAPI: TransactionOnNetwork) { - // // Ignore status, since it differs between Proxy and API (for smart contract calls): - // transactionOnProxy.status = new TransactionStatus("unknown"); - // transactionOnAPI.status = new TransactionStatus("unknown"); - - // // Ignore fields which are not present on API response: - // transactionOnProxy.epoch = 0; - // transactionOnProxy.type = new TransactionOnNetworkType(); - // transactionOnProxy.blockNonce = new Nonce(0); - // transactionOnProxy.hyperblockNonce = new Nonce(0); - // transactionOnProxy.hyperblockHash = new Hash(""); - - // let immediateContractResultOnAPI: SmartContractResultItem = (transactionOnAPI).results.immediate; - // let contractResultsOnAPI: SmartContractResultItem[] = (transactionOnAPI).results.items; - // let resultingCallsOnAPI: SmartContractResultItem[] = (transactionOnAPI).results.resultingCalls; - // let allContractResults = [immediateContractResultOnAPI].concat(resultingCallsOnAPI).concat(contractResultsOnAPI); - - // // Important issue (existing bug)! When working with TransactionOnNetwork objects, SCRs cannot be parsed correctly from API, only from Proxy. - // // On API response, base64 decode "data" from smart contract results: - // for (const item of allContractResults) { - // item.data = Buffer.from(item.data, "base64").toString(); - // } - - // // On API response, convert "callType" of smart contract results to a number: - // for (const item of allContractResults) { - // item.callType = Number(item.callType); - // } - - // // On API response, sort contract results by nonce: - // contractResultsOnAPI.sort(function (a: SmartContractResultItem, b: SmartContractResultItem) { - // return a.nonce.valueOf() - b.nonce.valueOf(); - // }); - // } + it("should have same response for getTransaction(), getTransactionStatus()", async function () { + this.timeout(20000); + + let sender = new Address("erd1testnlersh4z0wsv8kjx39me4rmnvjkwu8dsaea7ukdvvc9z396qykv7z7"); + + let hashes = [ + new TransactionHash("b41f5fc39e96b1f194d07761c6efd6cb92278b95f5012ab12cbc910058ca8b54"), + new TransactionHash("7757397a59378e9d0f6d5f08cc934c260e33a50ae0d73fdf869f7c02b6b47b33"), + new TransactionHash("b87238089e81527158a6daee520280324bc7e5322ba54d1b3c9a5678abe953ea"), + new TransactionHash("b45dd5e598bc85ba71639f2cbce8c5dff2fbe93159e637852fddeb16c0e84a48"), + new TransactionHash("83db780e98d4d3c917668c47b33ba51445591efacb0df2a922f88e7dfbb5fc7d"), + new TransactionHash("c2eb62b28cc7320da2292d87944c5424a70e1f443323c138c1affada7f6e9705") + ]; + + for (const hash of hashes) { + let apiResponse = await apiProvider.getTransaction(hash); + let proxyResponse = await proxyProvider.getTransaction(hash, sender); + + ignoreKnownTxDifferencesBetweenProviders(apiResponse, proxyResponse); + assert.deepEqual(apiResponse, proxyResponse); + } + }); + + // TODO: Strive to have as little differences as possible between Proxy and API. + function ignoreKnownTxDifferencesBetweenProviders(apiResponse: ITransactionOnNetwork, proxyResponse: ITransactionOnNetwork) { + apiResponse.status = proxyResponse.status = new TransactionStatus("ignore"); + apiResponse.type = proxyResponse.type = { value: "ignore" }; + + // Ignore fields which are not present on API response: + proxyResponse.epoch = 0; + proxyResponse.blockNonce = new Nonce(0); + proxyResponse.hyperblockNonce = new Nonce(0); + proxyResponse.hyperblockHash = new Hash(""); + } }); diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index 340b060c..99874e9d 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -1,21 +1,21 @@ import axios, { AxiosRequestConfig } from "axios"; -import { BigNumber } from "bignumber.js"; import { AccountOnNetwork } from "../account"; import { Address } from "../address"; import { defaultConfig } from "../constants"; import { ErrApiProviderGet, ErrContractQuery } from "../errors"; -import { IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, Pagination } from "../interface.networkProvider"; +import { IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, Pagination } from "../interface.networkProvider"; import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; import { NFTToken } from "../nftToken"; +import { Nonce } from "../nonce"; import { Query, QueryResponse } from "../smartcontracts"; import { Stats } from "../stats"; import { Token } from "../token"; import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; -import { TransactionOnNetwork } from "../transactionOnNetwork"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; +import { TransactionOnNetwork } from "./transactions"; export class ProxyNetworkProvider implements INetworkProvider { private url: string; @@ -93,20 +93,20 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokenData; } - async getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: BigNumber.Value): Promise { - let response = await this.doGetGeneric(`address/${address.bech32()}/nft/${collection}/nonce/${nonce}`); + async getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: Nonce): Promise { + let response = await this.doGetGeneric(`address/${address.bech32()}/nft/${collection}/nonce/${nonce.hex()}`); let tokenData = NonFungibleTokenOfAccountOnNetwork.fromProxyHttpResponse(response.tokenData); return tokenData; } - async getTransaction(txHash: TransactionHash, hintSender?: Address): Promise { + async getTransaction(txHash: TransactionHash, hintSender?: Address): Promise { let url = this.buildUrlWithQueryParameters(`transaction/${txHash.toString()}`, { withSender: hintSender ? hintSender.bech32() : "", withResults: "true" }); let response = await this.doGetGeneric(url); - let transaction = TransactionOnNetwork.fromHttpResponse(txHash, response.transaction); + let transaction = TransactionOnNetwork.fromProxyHttpResponse(txHash, response.transaction); return transaction; } diff --git a/src-network-providers/networkProvider/tokens.ts b/src-network-providers/networkProvider/tokens.ts index fdb780f9..5cf66794 100644 --- a/src-network-providers/networkProvider/tokens.ts +++ b/src-network-providers/networkProvider/tokens.ts @@ -19,6 +19,7 @@ export class FungibleTokenOfAccountOnNetwork implements IFungibleTokenOfAccountO export class NonFungibleTokenOfAccountOnNetwork implements INonFungibleTokenOfAccountOnNetwork { tokenIdentifier: string = ""; + collection: string = ""; attributes: Buffer = Buffer.from([]); balance: BigNumber = new BigNumber(0); nonce: Nonce = new Nonce(0); @@ -28,7 +29,8 @@ export class NonFungibleTokenOfAccountOnNetwork implements INonFungibleTokenOfAc static fromProxyHttpResponse(payload: any): NonFungibleTokenOfAccountOnNetwork { let result = new NonFungibleTokenOfAccountOnNetwork(); - result.tokenIdentifier = payload.tokenIdentifier || payload.identifier || ""; + result.tokenIdentifier = payload.tokenIdentifier || ""; + result.collection = NonFungibleTokenOfAccountOnNetwork.parseCollectionFromIdentifier(result.tokenIdentifier); result.attributes = Buffer.from(payload.attributes || "", "base64"); result.balance = new BigNumber(payload.balance || 0); result.nonce = new Nonce(payload.nonce || 0); @@ -38,10 +40,17 @@ export class NonFungibleTokenOfAccountOnNetwork implements INonFungibleTokenOfAc return result; } + private static parseCollectionFromIdentifier(identifier: string): string { + let parts = identifier.split("-"); + let collection = parts.slice(0, 2).join("-"); + return collection; + } + static fromApiHttpResponse(payload: any): NonFungibleTokenOfAccountOnNetwork { let result = new NonFungibleTokenOfAccountOnNetwork(); - result.tokenIdentifier = payload.tokenIdentifier || payload.identifier || ""; + result.tokenIdentifier = payload.identifier || ""; + result.collection = payload.collection || ""; result.attributes = Buffer.from(payload.attributes || "", "base64"); // On API, missing balance means NFT. result.balance = new BigNumber(payload.balance || 1); diff --git a/src-network-providers/networkProvider/transactions.ts b/src-network-providers/networkProvider/transactions.ts new file mode 100644 index 00000000..0e9a76c3 --- /dev/null +++ b/src-network-providers/networkProvider/transactions.ts @@ -0,0 +1,90 @@ +import { Address } from "../address"; +import { Balance } from "../balance"; +import { Hash } from "../hash"; +import { ITransactionOnNetwork, ITypeOfTransactionOnNetwork } from "../interface.networkProvider"; +import { GasLimit, GasPrice } from "../networkParams"; +import { Nonce } from "../nonce"; +import { Signature } from "../signature"; +import { TransactionHash, TransactionStatus } from "../transaction"; +import { TransactionPayload } from "../transactionPayload"; + + export class TransactionOnNetwork implements ITransactionOnNetwork { + hash: TransactionHash = new TransactionHash(""); + type: ITypeOfTransactionOnNetwork = new TypeOfTransactionOnNetwork(); + nonce: Nonce = new Nonce(0); + round: number = 0; + epoch: number = 0; + value: Balance = Balance.Zero(); + receiver: Address = new Address(); + sender: Address = new Address(); + gasPrice: GasPrice = new GasPrice(0); + gasLimit: GasLimit = new GasLimit(0); + data: TransactionPayload = new TransactionPayload(); + signature: Signature = Signature.empty(); + status: TransactionStatus = TransactionStatus.createUnknown(); + timestamp: number = 0; + + blockNonce: Nonce = new Nonce(0); + hyperblockNonce: Nonce = new Nonce(0); + hyperblockHash: Hash = Hash.empty(); + + static fromProxyHttpResponse(txHash: TransactionHash, response: any): TransactionOnNetwork { + let transactionOnNetwork = new TransactionOnNetwork(); + + transactionOnNetwork.hash = txHash; + transactionOnNetwork.type = new TypeOfTransactionOnNetwork(response.type || ""); + transactionOnNetwork.nonce = new Nonce(response.nonce || 0); + transactionOnNetwork.round = response.round; + transactionOnNetwork.epoch = response.epoch || 0; + transactionOnNetwork.value = Balance.fromString(response.value); + transactionOnNetwork.sender = Address.fromBech32(response.sender); + transactionOnNetwork.receiver = Address.fromBech32(response.receiver); + transactionOnNetwork.gasPrice = new GasPrice(response.gasPrice); + transactionOnNetwork.gasLimit = new GasLimit(response.gasLimit); + transactionOnNetwork.data = TransactionPayload.fromEncoded(response.data); + transactionOnNetwork.status = new TransactionStatus(response.status); + transactionOnNetwork.timestamp = response.timestamp || 0; + + transactionOnNetwork.blockNonce = new Nonce(response.blockNonce || 0); + transactionOnNetwork.hyperblockNonce = new Nonce(response.hyperblockNonce || 0); + transactionOnNetwork.hyperblockHash = new Hash(response.hyperblockHash); + + return transactionOnNetwork; + } + + static fromApiHttpResponse(txHash: TransactionHash, response: any): TransactionOnNetwork { + let transactionOnNetwork = new TransactionOnNetwork(); + + transactionOnNetwork.hash = txHash; + transactionOnNetwork.type = new TypeOfTransactionOnNetwork(response.type || ""); + transactionOnNetwork.nonce = new Nonce(response.nonce || 0); + transactionOnNetwork.round = response.round; + transactionOnNetwork.epoch = response.epoch || 0; + transactionOnNetwork.value = Balance.fromString(response.value); + transactionOnNetwork.sender = Address.fromBech32(response.sender); + transactionOnNetwork.receiver = Address.fromBech32(response.receiver); + transactionOnNetwork.gasPrice = new GasPrice(response.gasPrice); + transactionOnNetwork.gasLimit = new GasLimit(response.gasLimit); + transactionOnNetwork.data = TransactionPayload.fromEncoded(response.data); + transactionOnNetwork.status = new TransactionStatus(response.status); + transactionOnNetwork.timestamp = response.timestamp || 0; + + transactionOnNetwork.blockNonce = new Nonce(response.blockNonce || 0); + transactionOnNetwork.hyperblockNonce = new Nonce(response.hyperblockNonce || 0); + transactionOnNetwork.hyperblockHash = new Hash(response.hyperblockHash); + + return transactionOnNetwork; + } + + getDateTime(): Date { + return new Date(this.timestamp * 1000); + } +} + +class TypeOfTransactionOnNetwork implements ITypeOfTransactionOnNetwork { + readonly value: string; + + constructor(value?: string) { + this.value = value || "unknown"; + } +} From a9b7f6d647478df7ee46ae93ba6f93e936729081 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 22 Feb 2022 11:54:12 +0200 Subject: [PATCH 006/133] WIP. --- .../networkProvider/providers.dev.net.spec.ts | 24 +++++++++---------- .../networkProvider/proxyNetworkProvider.ts | 4 ++-- .../networkProvider/tokens.ts | 19 +++++++++++++++ 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts index 2ef52b30..fa7448ed 100644 --- a/src-network-providers/networkProvider/providers.dev.net.spec.ts +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -8,8 +8,8 @@ import { TransactionHash, TransactionStatus } from "../transaction"; import { Nonce } from "../nonce"; describe("test network providers on devnet: Proxy and API", function () { - let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 5000 }); - let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.elrond.com", { timeout: 5000 }); + let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 10000 }); + let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.elrond.com", { timeout: 10000 }); let alice: TestWallet; let bob: TestWallet; @@ -47,7 +47,7 @@ describe("test network providers on devnet: Proxy and API", function () { }); it("should have same response for getAccount()", async function () { - for (const user of [alice, bob, carol, dan]) { + for (const user of [bob, carol, dan]) { let apiResponse = await apiProvider.getAccount(user.address); let proxyResponse = await proxyProvider.getAccount(user.address); assert.deepEqual(apiResponse, proxyResponse); @@ -55,23 +55,23 @@ describe("test network providers on devnet: Proxy and API", function () { }); it("should have same response for getFungibleTokensOfAccount(), getFungibleTokenOfAccount()", async function () { - this.timeout(10000); + this.timeout(30000); - for (const user of [alice, bob, carol, dan]) { + for (const user of [carol, dan]) { let apiResponse = await apiProvider.getFungibleTokensOfAccount(user.address); let proxyResponse = await proxyProvider.getFungibleTokensOfAccount(user.address); assert.deepEqual(apiResponse.slice(0, 100), proxyResponse.slice(0, 100)); - // for (const item of apiResponse.slice(0, 5)) { - // let apiResponse = await apiProvider.getFungibleTokenOfAccount(user.address, item.tokenIdentifier); - // let proxyResponse = await proxyProvider.getFungibleTokenOfAccount(user.address, item.tokenIdentifier); - // //assert.deepEqual(apiResponse, proxyResponse, `user: ${user.address.bech32()}, token: ${item.tokenIdentifier}`); - // } + for (const item of apiResponse.slice(0, 5)) { + let apiResponse = await apiProvider.getFungibleTokenOfAccount(user.address, item.tokenIdentifier); + let proxyResponse = await proxyProvider.getFungibleTokenOfAccount(user.address, item.tokenIdentifier); + assert.deepEqual(apiResponse, proxyResponse, `user: ${user.address.bech32()}, token: ${item.tokenIdentifier}`); + } } }); - it.only("should have same response for getNonFungibleTokensOfAccount(), getNonFungibleTokenOfAccount", async function () { - this.timeout(10000); + it("should have same response for getNonFungibleTokensOfAccount(), getNonFungibleTokenOfAccount", async function () { + this.timeout(30000); for (const user of [alice, bob, carol, dan]) { let apiResponse = await apiProvider.getNonFungibleTokensOfAccount(user.address); diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index 99874e9d..b615aa13 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -94,8 +94,8 @@ export class ProxyNetworkProvider implements INetworkProvider { } async getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: Nonce): Promise { - let response = await this.doGetGeneric(`address/${address.bech32()}/nft/${collection}/nonce/${nonce.hex()}`); - let tokenData = NonFungibleTokenOfAccountOnNetwork.fromProxyHttpResponse(response.tokenData); + let response = await this.doGetGeneric(`address/${address.bech32()}/nft/${collection}/nonce/${nonce.valueOf()}`); + let tokenData = NonFungibleTokenOfAccountOnNetwork.fromProxyHttpResponseByNonce(response.tokenData); return tokenData; } diff --git a/src-network-providers/networkProvider/tokens.ts b/src-network-providers/networkProvider/tokens.ts index 5cf66794..54a73efe 100644 --- a/src-network-providers/networkProvider/tokens.ts +++ b/src-network-providers/networkProvider/tokens.ts @@ -40,6 +40,20 @@ export class NonFungibleTokenOfAccountOnNetwork implements INonFungibleTokenOfAc return result; } + static fromProxyHttpResponseByNonce(payload: any): NonFungibleTokenOfAccountOnNetwork { + let result = new NonFungibleTokenOfAccountOnNetwork(); + + result.attributes = Buffer.from(payload.attributes || "", "base64"); + result.balance = new BigNumber(payload.balance || 0); + result.nonce = new Nonce(payload.nonce || 0); + result.creator = new Address(payload.creator || ""); + result.royalties = new BigNumber(payload.royalties || 0).div(100); + result.tokenIdentifier = `${payload.tokenIdentifier}-${result.nonce.hex()}`; + result.collection = payload.tokenIdentifier || ""; + + return result; + } + private static parseCollectionFromIdentifier(identifier: string): string { let parts = identifier.split("-"); let collection = parts.slice(0, 2).join("-"); @@ -58,6 +72,11 @@ export class NonFungibleTokenOfAccountOnNetwork implements INonFungibleTokenOfAc result.creator = new Address(payload.creator || ""); result.royalties = new BigNumber(payload.royalties || 0); + if (!payload.creator) { + console.log(payload); + throw new Error("??? api"); + } + return result; } } From 8baba731835d55677b9d7d4250bafc4b2f2ca3a7 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 22 Feb 2022 12:31:03 +0200 Subject: [PATCH 007/133] Simplifications. --- .../networkProvider/providers.dev.net.spec.ts | 17 ++++++++++++----- .../networkProvider/proxyNetworkProvider.ts | 8 ++------ .../networkProvider/transactions.ts | 12 +----------- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts index fa7448ed..c177ad09 100644 --- a/src-network-providers/networkProvider/providers.dev.net.spec.ts +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -102,17 +102,24 @@ describe("test network providers on devnet: Proxy and API", function () { for (const hash of hashes) { let apiResponse = await apiProvider.getTransaction(hash); - let proxyResponse = await proxyProvider.getTransaction(hash, sender); + let proxyResponse = await proxyProvider.getTransaction(hash); - ignoreKnownTxDifferencesBetweenProviders(apiResponse, proxyResponse); - assert.deepEqual(apiResponse, proxyResponse); + ignoreKnownTransactionDifferencesBetweenProviders(apiResponse, proxyResponse); + assert.deepEqual(apiResponse, proxyResponse, `transaction: ${hash}`); + } + + for (const hash of hashes) { + let apiResponse = await apiProvider.getTransactionStatus(hash); + let proxyResponse = await proxyProvider.getTransactionStatus(hash); + + // TODO: Fix differences of "tx.status". + // assert.deepEqual(apiResponse, proxyResponse, `transaction: ${hash}`); } }); // TODO: Strive to have as little differences as possible between Proxy and API. - function ignoreKnownTxDifferencesBetweenProviders(apiResponse: ITransactionOnNetwork, proxyResponse: ITransactionOnNetwork) { + function ignoreKnownTransactionDifferencesBetweenProviders(apiResponse: ITransactionOnNetwork, proxyResponse: ITransactionOnNetwork) { apiResponse.status = proxyResponse.status = new TransactionStatus("ignore"); - apiResponse.type = proxyResponse.type = { value: "ignore" }; // Ignore fields which are not present on API response: proxyResponse.epoch = 0; diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index b615aa13..d5ef1f8b 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -99,12 +99,8 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokenData; } - async getTransaction(txHash: TransactionHash, hintSender?: Address): Promise { - let url = this.buildUrlWithQueryParameters(`transaction/${txHash.toString()}`, { - withSender: hintSender ? hintSender.bech32() : "", - withResults: "true" - }); - + async getTransaction(txHash: TransactionHash): Promise { + let url = this.buildUrlWithQueryParameters(`transaction/${txHash.toString()}`, { withResults: "true" }); let response = await this.doGetGeneric(url); let transaction = TransactionOnNetwork.fromProxyHttpResponse(txHash, response.transaction); return transaction; diff --git a/src-network-providers/networkProvider/transactions.ts b/src-network-providers/networkProvider/transactions.ts index 0e9a76c3..fd46e4fb 100644 --- a/src-network-providers/networkProvider/transactions.ts +++ b/src-network-providers/networkProvider/transactions.ts @@ -1,7 +1,7 @@ import { Address } from "../address"; import { Balance } from "../balance"; import { Hash } from "../hash"; -import { ITransactionOnNetwork, ITypeOfTransactionOnNetwork } from "../interface.networkProvider"; +import { ITransactionOnNetwork } from "../interface.networkProvider"; import { GasLimit, GasPrice } from "../networkParams"; import { Nonce } from "../nonce"; import { Signature } from "../signature"; @@ -10,7 +10,6 @@ import { TransactionPayload } from "../transactionPayload"; export class TransactionOnNetwork implements ITransactionOnNetwork { hash: TransactionHash = new TransactionHash(""); - type: ITypeOfTransactionOnNetwork = new TypeOfTransactionOnNetwork(); nonce: Nonce = new Nonce(0); round: number = 0; epoch: number = 0; @@ -32,7 +31,6 @@ import { TransactionPayload } from "../transactionPayload"; let transactionOnNetwork = new TransactionOnNetwork(); transactionOnNetwork.hash = txHash; - transactionOnNetwork.type = new TypeOfTransactionOnNetwork(response.type || ""); transactionOnNetwork.nonce = new Nonce(response.nonce || 0); transactionOnNetwork.round = response.round; transactionOnNetwork.epoch = response.epoch || 0; @@ -56,7 +54,6 @@ import { TransactionPayload } from "../transactionPayload"; let transactionOnNetwork = new TransactionOnNetwork(); transactionOnNetwork.hash = txHash; - transactionOnNetwork.type = new TypeOfTransactionOnNetwork(response.type || ""); transactionOnNetwork.nonce = new Nonce(response.nonce || 0); transactionOnNetwork.round = response.round; transactionOnNetwork.epoch = response.epoch || 0; @@ -81,10 +78,3 @@ import { TransactionPayload } from "../transactionPayload"; } } -class TypeOfTransactionOnNetwork implements ITypeOfTransactionOnNetwork { - readonly value: string; - - constructor(value?: string) { - this.value = value || "unknown"; - } -} From 1b97a67d6630a8bc26b566a63207d91cda6ea2d2 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 22 Feb 2022 20:19:20 +0200 Subject: [PATCH 008/133] WIP. --- .../networkProvider/apiNetworkProvider.ts | 31 ++++---- .../networkProvider/providers.dev.net.spec.ts | 58 +++++++++++++-- .../networkProvider/proxyNetworkProvider.ts | 19 ++--- .../networkProvider/tokenDefinitions.ts | 73 +++++++++++++++++++ .../networkProvider/tokens.ts | 25 +++---- 5 files changed, 158 insertions(+), 48 deletions(-) create mode 100644 src-network-providers/networkProvider/tokenDefinitions.ts diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index 93eddac8..f27e1f65 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -1,21 +1,19 @@ import axios, { AxiosRequestConfig } from "axios"; -import { BigNumber } from "bignumber.js"; import { AccountOnNetwork } from "../account"; import { Address } from "../address"; import { defaultConfig } from "../constants"; import { ErrApiProviderGet, ErrContractQuery } from "../errors"; -import { IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, Pagination } from "../interface.networkProvider"; +import { IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, Pagination } from "../interface.networkProvider"; import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; -import { NFTToken } from "../nftToken"; import { Nonce } from "../nonce"; import { Query, QueryResponse } from "../smartcontracts"; import { Stats } from "../stats"; -import { Token } from "../token"; import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; +import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; @@ -69,7 +67,7 @@ export class ApiNetworkProvider implements INetworkProvider { let tokens = response.map(item => FungibleTokenOfAccountOnNetwork.fromHttpResponse(item)); // TODO: Fix sorting - tokens.sort((a, b) => a.tokenIdentifier.localeCompare(b.tokenIdentifier)); + tokens.sort((a, b) => a.identifier.localeCompare(b.identifier)); return tokens; } @@ -81,7 +79,7 @@ export class ApiNetworkProvider implements INetworkProvider { let tokens = response.map(item => NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(item)); // TODO: Fix sorting - tokens.sort((a, b) => a.tokenIdentifier.localeCompare(b.tokenIdentifier)); + tokens.sort((a, b) => a.identifier.localeCompare(b.identifier)); return tokens; } @@ -131,21 +129,22 @@ export class ApiNetworkProvider implements INetworkProvider { } } - async getToken(tokenIdentifier: string): Promise { + async getDefinitionOfFungibleToken(tokenIdentifier: string): Promise { let response = await this.doGetGeneric(`tokens/${tokenIdentifier}`); - let token = Token.fromHttpResponse(response); - return token; + let definition = DefinitionOfFungibleTokenOnNetwork.fromApiHttpResponse(response); + return definition; } - async getNFTToken(tokenIdentifier: string): Promise { - let response = await this.doGetGeneric(`nfts/${tokenIdentifier}`); - let token = NFTToken.fromHttpResponse(response); - return token; + async getDefinitionOfTokenCollection(collection: string): Promise { + let response = await this.doGetGeneric(`collections/${collection}`); + let definition = DefinitionOfTokenCollectionOnNetwork.fromApiHttpResponse(response); + return definition; } - async getDefinitionOfTokenCollection(collection: string): Promise { - let response = await this.doGetGeneric(`collections/${collection}`); - return response; + async getNonFungibleToken(collection: string, nonce: Nonce): Promise { + let response = await this.doGetGeneric(`nfts/${collection}-${nonce.hex()}`); + let token = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response); + return token; } async doGetGeneric(resourceUrl: string): Promise { diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts index c177ad09..871a282d 100644 --- a/src-network-providers/networkProvider/providers.dev.net.spec.ts +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -63,9 +63,9 @@ describe("test network providers on devnet: Proxy and API", function () { assert.deepEqual(apiResponse.slice(0, 100), proxyResponse.slice(0, 100)); for (const item of apiResponse.slice(0, 5)) { - let apiResponse = await apiProvider.getFungibleTokenOfAccount(user.address, item.tokenIdentifier); - let proxyResponse = await proxyProvider.getFungibleTokenOfAccount(user.address, item.tokenIdentifier); - assert.deepEqual(apiResponse, proxyResponse, `user: ${user.address.bech32()}, token: ${item.tokenIdentifier}`); + let apiResponse = await apiProvider.getFungibleTokenOfAccount(user.address, item.identifier); + let proxyResponse = await proxyProvider.getFungibleTokenOfAccount(user.address, item.identifier); + assert.deepEqual(apiResponse, proxyResponse, `user: ${user.address.bech32()}, token: ${item.identifier}`); } } }); @@ -81,7 +81,7 @@ describe("test network providers on devnet: Proxy and API", function () { for (const item of apiResponse.slice(0, 5)) { let apiResponse = await apiProvider.getNonFungibleTokenOfAccount(user.address, item.collection, item.nonce); let proxyResponse = await proxyProvider.getNonFungibleTokenOfAccount(user.address, item.collection, item.nonce); - assert.deepEqual(apiResponse, proxyResponse, `user: ${user.address.bech32()}, token: ${item.tokenIdentifier}`); + assert.deepEqual(apiResponse, proxyResponse, `user: ${user.address.bech32()}, token: ${item.identifier}`); } } }); @@ -103,7 +103,7 @@ describe("test network providers on devnet: Proxy and API", function () { for (const hash of hashes) { let apiResponse = await apiProvider.getTransaction(hash); let proxyResponse = await proxyProvider.getTransaction(hash); - + ignoreKnownTransactionDifferencesBetweenProviders(apiResponse, proxyResponse); assert.deepEqual(apiResponse, proxyResponse, `transaction: ${hash}`); } @@ -111,7 +111,7 @@ describe("test network providers on devnet: Proxy and API", function () { for (const hash of hashes) { let apiResponse = await apiProvider.getTransactionStatus(hash); let proxyResponse = await proxyProvider.getTransactionStatus(hash); - + // TODO: Fix differences of "tx.status". // assert.deepEqual(apiResponse, proxyResponse, `transaction: ${hash}`); } @@ -127,4 +127,50 @@ describe("test network providers on devnet: Proxy and API", function () { proxyResponse.hyperblockNonce = new Nonce(0); proxyResponse.hyperblockHash = new Hash(""); } + + it("should have same response for getDefinitionOfFungibleToken()", async function () { + this.timeout(10000); + + let identifiers = ["MEX-b6bb7d", "WEGLD-88600a", "RIDE-482531", "USDC-a32906"]; + + for (const identifier of identifiers) { + let apiResponse = await apiProvider.getDefinitionOfFungibleToken(identifier); + + assert.equal(apiResponse.identifier, identifier); + + // TODO: Uncomment after implementing the function in the proxy provider. + // let proxyResponse = await proxyProvider.getDefinitionOfFungibleToken(identifier); + // assert.deepEqual(apiResponse, proxyResponse); + } + }); + + it("should have same response for getDefinitionOfTokenCollection()", async function () { + this.timeout(10000); + + let collections = ["LKMEX-9acade", "LKFARM-c20c1c", "MEXFARM-bab93a", "ART-264971", "MOS-ff0040"]; + + for (const collection of collections) { + let apiResponse = await apiProvider.getDefinitionOfTokenCollection(collection); + assert.equal(apiResponse.collection, collection); + + // TODO: Uncomment after implementing the function in the proxy provider. + // let proxyResponse = await proxyProvider.getDefinitionOfTokenCollection(identifier); + // assert.deepEqual(apiResponse, proxyResponse); + } + }); + + it("should have same response for getNonFungibleToken()", async function () { + this.timeout(10000); + + let tokens = [{ id: "ERDJSNFT-4a5669", nonce: new Nonce(1) }]; + + for (const token of tokens) { + let apiResponse = await apiProvider.getNonFungibleToken(token.id, token.nonce); + assert.equal(apiResponse.collection, token.id); + + // TODO: Uncomment after implementing the function in the proxy provider. + // let proxyResponse = await proxyProvider.getNonFungibleToken(token.id, token.nonce); + // assert.deepEqual(apiResponse, proxyResponse); + } + }); }); diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index d5ef1f8b..0db43da3 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -3,16 +3,14 @@ import { AccountOnNetwork } from "../account"; import { Address } from "../address"; import { defaultConfig } from "../constants"; import { ErrApiProviderGet, ErrContractQuery } from "../errors"; -import { IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, Pagination } from "../interface.networkProvider"; +import { IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, Pagination } from "../interface.networkProvider"; import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; -import { NFTToken } from "../nftToken"; import { Nonce } from "../nonce"; import { Query, QueryResponse } from "../smartcontracts"; import { Stats } from "../stats"; -import { Token } from "../token"; import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; @@ -70,7 +68,7 @@ export class ProxyNetworkProvider implements INetworkProvider { let tokens = responseItemsFiltered.map(item => FungibleTokenOfAccountOnNetwork.fromHttpResponse(item)); // TODO: Fix sorting - tokens.sort((a, b) => a.tokenIdentifier.localeCompare(b.tokenIdentifier)); + tokens.sort((a, b) => a.identifier.localeCompare(b.identifier)); return tokens; } @@ -83,7 +81,7 @@ export class ProxyNetworkProvider implements INetworkProvider { let tokens = responseItemsFiltered.map(item => NonFungibleTokenOfAccountOnNetwork.fromProxyHttpResponse(item)); // TODO: Fix sorting - tokens.sort((a, b) => a.tokenIdentifier.localeCompare(b.tokenIdentifier)); + tokens.sort((a, b) => a.identifier.localeCompare(b.identifier)); return tokens; } @@ -134,21 +132,20 @@ export class ProxyNetworkProvider implements INetworkProvider { } } - async getToken(_tokenIdentifier: string): Promise { + async getDefinitionOfFungibleToken(_tokenIdentifier: string): Promise { // TODO: Implement wrt.: // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/esdt/esdt.service.ts#L221 throw new Error("Method not implemented."); } - async getNFTToken(_tokenIdentifier: string): Promise { + async getDefinitionOfTokenCollection(_collection: string): Promise { // TODO: Implement wrt.: + // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/collections/collection.service.ts + // https://docs.elrond.com/developers/esdt-tokens/#get-esdt-token-properties throw new Error("Method not implemented."); } - async getDefinitionOfTokenCollection(_collection: string): Promise { - // TODO: Implement wrt.: - // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/collections/collection.service.ts - // https://docs.elrond.com/developers/esdt-tokens/#get-esdt-token-properties + async getNonFungibleToken(_collection: string, _nonce: Nonce): Promise { throw new Error("Method not implemented."); } diff --git a/src-network-providers/networkProvider/tokenDefinitions.ts b/src-network-providers/networkProvider/tokenDefinitions.ts new file mode 100644 index 00000000..407e05d1 --- /dev/null +++ b/src-network-providers/networkProvider/tokenDefinitions.ts @@ -0,0 +1,73 @@ +import { BigNumber } from "bignumber.js"; +import { Address } from "../address"; +import { IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INonFungibleTokenOfAccountOnNetwork } from "../interface.networkProvider"; + +export class DefinitionOfFungibleTokenOnNetwork implements IDefinitionOfFungibleTokenOnNetwork { + identifier: string = ""; + name: string = ""; + ticker: string = ""; + owner: Address = new Address(); + decimals: number = 0; + supply: BigNumber = new BigNumber(0); + isPaused: boolean = false; + canUpgrade: boolean = false; + canMint: boolean = false; + canBurn: boolean = false; + canChangeOwner: boolean = false; + canPause: boolean = false; + canFreeze: boolean = false; + canWipe: boolean = false; + canAddSpecialRoles: boolean = false; + + static fromApiHttpResponse(payload: any): DefinitionOfFungibleTokenOnNetwork { + let result = new DefinitionOfFungibleTokenOnNetwork(); + + result.identifier = payload.identifier || ""; + result.name = payload.name || ""; + result.ticker = payload.ticker || ""; + result.owner = new Address(payload.owner || ""); + result.decimals = payload.decimals || 0; + result.supply = new BigNumber(payload.supply || "0"); + result.isPaused = payload.isPaused || false; + result.canUpgrade = payload.canUpgrade || false; + result.canMint = payload.canMint || false; + result.canBurn = payload.canBurn || false; + result.canChangeOwner = payload.canChangeOwner || false; + result.canPause = payload.canPause || false; + result.canFreeze = payload.canFreeze || false; + result.canWipe = payload.canWipe || false; + result.canAddSpecialRoles = payload.canAddSpecialRoles || false; + + return result; + } +} + +export class DefinitionOfTokenCollectionOnNetwork implements IDefinitionOfTokenCollectionOnNetwork { + collection: string = ""; + type: string = ""; + name: string = ""; + ticker: string = ""; + owner: Address = new Address(); + decimals: number = 0; + canPause: boolean = false; + canFreeze: boolean = false; + canWipe: boolean = false; + canTransferRole: boolean = false; + + static fromApiHttpResponse(payload: any): DefinitionOfTokenCollectionOnNetwork { + let result = new DefinitionOfTokenCollectionOnNetwork(); + + result.collection = payload.collection || ""; + result.type = payload.type || ""; + result.name = payload.name || ""; + result.ticker = payload.ticker || ""; + result.owner = new Address(payload.owner || ""); + result.decimals = payload.decimals || 0; + result.canPause = payload.canPause || false; + result.canFreeze = payload.canFreeze || false; + result.canWipe = payload.canWipe || false; + result.canTransferRole = payload.canTransferRole || false; + + return result; + } +} diff --git a/src-network-providers/networkProvider/tokens.ts b/src-network-providers/networkProvider/tokens.ts index 54a73efe..235c33f8 100644 --- a/src-network-providers/networkProvider/tokens.ts +++ b/src-network-providers/networkProvider/tokens.ts @@ -4,13 +4,13 @@ import { IFungibleTokenOfAccountOnNetwork, INonFungibleTokenOfAccountOnNetwork } import { Nonce } from "../nonce"; export class FungibleTokenOfAccountOnNetwork implements IFungibleTokenOfAccountOnNetwork { - tokenIdentifier: string = ""; + identifier: string = ""; balance: BigNumber = new BigNumber(0); - + static fromHttpResponse(payload: any): FungibleTokenOfAccountOnNetwork { let result = new FungibleTokenOfAccountOnNetwork(); - result.tokenIdentifier = payload.tokenIdentifier || payload.identifier || ""; + result.identifier = payload.tokenIdentifier || payload.identifier || ""; result.balance = new BigNumber(payload.balance || 0); return result; @@ -18,7 +18,7 @@ export class FungibleTokenOfAccountOnNetwork implements IFungibleTokenOfAccountO } export class NonFungibleTokenOfAccountOnNetwork implements INonFungibleTokenOfAccountOnNetwork { - tokenIdentifier: string = ""; + identifier: string = ""; collection: string = ""; attributes: Buffer = Buffer.from([]); balance: BigNumber = new BigNumber(0); @@ -29,8 +29,8 @@ export class NonFungibleTokenOfAccountOnNetwork implements INonFungibleTokenOfAc static fromProxyHttpResponse(payload: any): NonFungibleTokenOfAccountOnNetwork { let result = new NonFungibleTokenOfAccountOnNetwork(); - result.tokenIdentifier = payload.tokenIdentifier || ""; - result.collection = NonFungibleTokenOfAccountOnNetwork.parseCollectionFromIdentifier(result.tokenIdentifier); + result.identifier = payload.tokenIdentifier || ""; + result.collection = NonFungibleTokenOfAccountOnNetwork.parseCollectionFromIdentifier(result.identifier); result.attributes = Buffer.from(payload.attributes || "", "base64"); result.balance = new BigNumber(payload.balance || 0); result.nonce = new Nonce(payload.nonce || 0); @@ -48,9 +48,9 @@ export class NonFungibleTokenOfAccountOnNetwork implements INonFungibleTokenOfAc result.nonce = new Nonce(payload.nonce || 0); result.creator = new Address(payload.creator || ""); result.royalties = new BigNumber(payload.royalties || 0).div(100); - result.tokenIdentifier = `${payload.tokenIdentifier}-${result.nonce.hex()}`; + result.identifier = `${payload.tokenIdentifier}-${result.nonce.hex()}`; result.collection = payload.tokenIdentifier || ""; - + return result; } @@ -63,7 +63,7 @@ export class NonFungibleTokenOfAccountOnNetwork implements INonFungibleTokenOfAc static fromApiHttpResponse(payload: any): NonFungibleTokenOfAccountOnNetwork { let result = new NonFungibleTokenOfAccountOnNetwork(); - result.tokenIdentifier = payload.identifier || ""; + result.identifier = payload.identifier || ""; result.collection = payload.collection || ""; result.attributes = Buffer.from(payload.attributes || "", "base64"); // On API, missing balance means NFT. @@ -71,12 +71,7 @@ export class NonFungibleTokenOfAccountOnNetwork implements INonFungibleTokenOfAc result.nonce = new Nonce(payload.nonce || 0); result.creator = new Address(payload.creator || ""); result.royalties = new BigNumber(payload.royalties || 0); - - if (!payload.creator) { - console.log(payload); - throw new Error("??? api"); - } - + return result; } } From 3976cffd3a2582160a7c0e976d1be12cdc87c8d2 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 23 Feb 2022 12:31:27 +0200 Subject: [PATCH 009/133] Contract queries. WIP. --- .../networkProvider/apiNetworkProvider.ts | 25 ++++----- .../networkProvider/contractResults.ts | 34 ++++++++++++ .../networkProvider/providers.dev.net.spec.ts | 53 +++++++++++++++++++ .../networkProvider/proxyNetworkProvider.ts | 25 ++++----- 4 files changed, 109 insertions(+), 28 deletions(-) create mode 100644 src-network-providers/networkProvider/contractResults.ts diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index f27e1f65..1b87925c 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -2,16 +2,17 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "../account"; import { Address } from "../address"; import { defaultConfig } from "../constants"; -import { ErrApiProviderGet, ErrContractQuery } from "../errors"; -import { IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, Pagination } from "../interface.networkProvider"; +import { ErrNetworkProvider } from "../errors"; +import { IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, Pagination } from "../interface.networkProvider"; import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; import { Nonce } from "../nonce"; -import { Query, QueryResponse } from "../smartcontracts"; +import { Query } from "../smartcontracts"; import { Stats } from "../stats"; import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; +import { ContractQueryResponse } from "./contractResults"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; @@ -118,15 +119,11 @@ export class ApiNetworkProvider implements INetworkProvider { return await this.backingProxyNetworkProvider.simulateTransaction(tx); } - async queryContract(query: Query): Promise { - try { - let data = query.toHttpRequest(); - let response = await this.doPostGeneric("query", data); - let queryResponse = QueryResponse.fromHttpResponse(response) - return queryResponse; - } catch (err: any) { - throw ErrContractQuery.increaseSpecificity(err); - } + async queryContract(query: Query): Promise { + let data = query.toHttpRequest(); + let response = await this.doPostGeneric("query", data); + let queryResponse = ContractQueryResponse.fromHttpResponse(response); + return queryResponse; } async getDefinitionOfFungibleToken(tokenIdentifier: string): Promise { @@ -191,11 +188,11 @@ export class ApiNetworkProvider implements INetworkProvider { private handleApiError(error: any, resourceUrl: string) { if (!error.response) { Logger.warn(error); - throw new ErrApiProviderGet(resourceUrl, error.toString(), error); + throw new ErrNetworkProvider(resourceUrl, error.toString(), error); } let errorData = error.response.data; let originalErrorMessage = errorData.error || errorData.message || JSON.stringify(errorData); - throw new ErrApiProviderGet(resourceUrl, originalErrorMessage, error); + throw new ErrNetworkProvider(resourceUrl, originalErrorMessage, error); } } diff --git a/src-network-providers/networkProvider/contractResults.ts b/src-network-providers/networkProvider/contractResults.ts new file mode 100644 index 00000000..457dd648 --- /dev/null +++ b/src-network-providers/networkProvider/contractResults.ts @@ -0,0 +1,34 @@ +import { BigNumber } from "bignumber.js"; +import { IContractQueryResponse } from "../interface.networkProvider"; +import { GasLimit } from "../networkParams"; +import { ArgSerializer, EndpointDefinition, MaxUint64, ReturnCode, TypedValue } from "../smartcontracts"; + +export class ContractQueryResponse implements IContractQueryResponse { + returnData: string[] = []; + returnCode: ReturnCode = ReturnCode.None; + returnMessage: string = ""; + gasUsed: GasLimit = new GasLimit(0); + + static fromHttpResponse(payload: any): ContractQueryResponse { + let response = new ContractQueryResponse(); + let gasRemaining = new BigNumber(payload["gasRemaining"] || payload["GasRemaining"] || 0); + + response.returnData = payload["returnData"] || []; + response.returnCode = payload["returnCode"] || ""; + response.returnMessage = payload["returnMessage"] || ""; + response.gasUsed = new GasLimit(MaxUint64.minus(gasRemaining).toNumber()); + + return response; + } + + getOutputUntyped(): Buffer[] { + let buffers = this.returnData.map((item) => Buffer.from(item || "", "base64")); + return buffers; + } + + getOutputTyped(endpointDefinition: EndpointDefinition): TypedValue[] { + let buffers = this.getOutputUntyped(); + let values = new ArgSerializer().buffersToValues(buffers, endpointDefinition!.output); + return values; + } +} diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts index 871a282d..63aa28e4 100644 --- a/src-network-providers/networkProvider/providers.dev.net.spec.ts +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -6,6 +6,10 @@ import { Address } from "../address"; import { loadTestWallets, TestWallet } from "../testutils"; import { TransactionHash, TransactionStatus } from "../transaction"; import { Nonce } from "../nonce"; +import { ContractFunction, Query } from "../smartcontracts"; +import { BigUIntValue, U32Value, BytesValue, VariadicValue, VariadicType, CompositeType, BytesType, BooleanType } from "../smartcontracts/typesystem"; +import { BigNumber } from "bignumber.js"; +import { Balance } from "../balance"; describe("test network providers on devnet: Proxy and API", function () { let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 10000 }); @@ -173,4 +177,53 @@ describe("test network providers on devnet: Proxy and API", function () { // assert.deepEqual(apiResponse, proxyResponse); } }); + + // TODO: enable when API fixes the imprecision around "gasRemaining". + // TODO: enable when API supports queries with "value". + it.skip("should have same response for queryContract()", async function () { + this.timeout(10000); + + // Query: get ultimate answer + let query = new Query({ + address: new Address("erd1qqqqqqqqqqqqqpgqggww7tjryk9saqzfpq09tw3vm06kl8h3396qqz277y"), + func: new ContractFunction("getUltimateAnswer"), + args: [] + }); + + let apiResponse = await apiProvider.queryContract(query); + let proxyResponse = await proxyProvider.queryContract(query); + assert.deepEqual(apiResponse, proxyResponse); + assert.deepEqual(apiResponse.getOutputUntyped(), proxyResponse.getOutputUntyped()); + + // Query: increment counter + query = new Query({ + address: new Address("erd1qqqqqqqqqqqqqpgqz045rw74nthgzw2te9lytgah775n3l08396q3wt4qq"), + func: new ContractFunction("increment"), + args: [] + }); + + apiResponse = await apiProvider.queryContract(query); + proxyResponse = await proxyProvider.queryContract(query); + assert.deepEqual(apiResponse, proxyResponse); + assert.deepEqual(apiResponse.getOutputUntyped(), proxyResponse.getOutputUntyped()); + + // Query: issue ESDT + query = new Query({ + address: new Address("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"), + func: new ContractFunction("issue"), + value: Balance.egld(0.05), + args: [ + BytesValue.fromUTF8("FOO"), + BytesValue.fromUTF8("FOO"), + new BigUIntValue(new BigNumber("10000")), + new U32Value(18), + new VariadicValue(new VariadicType(new CompositeType(new BytesType(), new BooleanType())), []) + ] + }); + + apiResponse = await apiProvider.queryContract(query); + proxyResponse = await proxyProvider.queryContract(query); + assert.deepEqual(apiResponse, proxyResponse); + assert.deepEqual(apiResponse.getOutputUntyped(), proxyResponse.getOutputUntyped()); + }); }); diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index 0db43da3..c9f1d348 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -2,16 +2,17 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "../account"; import { Address } from "../address"; import { defaultConfig } from "../constants"; -import { ErrApiProviderGet, ErrContractQuery } from "../errors"; -import { IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, Pagination } from "../interface.networkProvider"; +import { ErrNetworkProvider } from "../errors"; +import { IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, Pagination } from "../interface.networkProvider"; import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; import { Nonce } from "../nonce"; -import { Query, QueryResponse } from "../smartcontracts"; +import { Query } from "../smartcontracts"; import { Stats } from "../stats"; import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; +import { ContractQueryResponse } from "./contractResults"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; @@ -121,15 +122,11 @@ export class ProxyNetworkProvider implements INetworkProvider { return response; } - async queryContract(query: Query): Promise { - try { - let data = query.toHttpRequest(); - let response = await this.doPostGeneric("vm-values/query", data); - let queryResponse = QueryResponse.fromHttpResponse(response.data) - return queryResponse; - } catch (err: any) { - throw ErrContractQuery.increaseSpecificity(err); - } + async queryContract(query: Query): Promise { + let data = query.toHttpRequest(); + let response = await this.doPostGeneric("vm-values/query", data); + let queryResponse = ContractQueryResponse.fromHttpResponse(response.data); + return queryResponse; } async getDefinitionOfFungibleToken(_tokenIdentifier: string): Promise { @@ -201,11 +198,11 @@ export class ProxyNetworkProvider implements INetworkProvider { private handleApiError(error: any, resourceUrl: string) { if (!error.response) { Logger.warn(error); - throw new ErrApiProviderGet(resourceUrl, error.toString(), error); + throw new ErrNetworkProvider(resourceUrl, error.toString(), error); } let errorData = error.response.data; let originalErrorMessage = errorData.error || errorData.message || JSON.stringify(errorData); - throw new ErrApiProviderGet(resourceUrl, originalErrorMessage, error); + throw new ErrNetworkProvider(resourceUrl, originalErrorMessage, error); } } From 281eafb9ded1bb10115e86d2f592c1f850bad45c Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 23 Feb 2022 14:57:44 +0200 Subject: [PATCH 010/133] Logs, results, refactor, WIP. --- .../networkProvider/contractResults.ts | 35 ++++++++++++++++- .../networkProvider/providers.dev.net.spec.ts | 8 ++-- .../networkProvider/tokens.ts | 38 +++++++++---------- 3 files changed, 56 insertions(+), 25 deletions(-) diff --git a/src-network-providers/networkProvider/contractResults.ts b/src-network-providers/networkProvider/contractResults.ts index 457dd648..0915d525 100644 --- a/src-network-providers/networkProvider/contractResults.ts +++ b/src-network-providers/networkProvider/contractResults.ts @@ -1,8 +1,39 @@ import { BigNumber } from "bignumber.js"; -import { IContractQueryResponse } from "../interface.networkProvider"; -import { GasLimit } from "../networkParams"; +import { Address } from "../address"; +import { Balance } from "../balance"; +import { Hash } from "../hash"; +import { IContractQueryResponse, IContractResultItem, IContractResults } from "../interface.networkProvider"; +import { GasLimit, GasPrice } from "../networkParams"; +import { Nonce } from "../nonce"; import { ArgSerializer, EndpointDefinition, MaxUint64, ReturnCode, TypedValue } from "../smartcontracts"; +export class ContractResults implements IContractResults { + readonly items: IContractResultItem[]; + + constructor(items: IContractResultItem[]) { + this.items = items; + } + + static empty(): ContractResults { + return new ContractResults([]); + } +} + +export class ContractResultItem implements IContractResultItem { + hash: Hash = Hash.empty(); + nonce: Nonce = new Nonce(0); + value: Balance = Balance.Zero(); + receiver: Address = new Address(); + sender: Address = new Address(); + data: string = ""; + previousHash: Hash = Hash.empty(); + originalHash: Hash = Hash.empty(); + gasLimit: GasLimit = new GasLimit(0); + gasPrice: GasPrice = new GasPrice(0); + callType: number = 0; + returnMessage: string = ""; +} + export class ContractQueryResponse implements IContractQueryResponse { returnData: string[] = []; returnCode: ReturnCode = ReturnCode.None; diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts index 63aa28e4..817bc6f7 100644 --- a/src-network-providers/networkProvider/providers.dev.net.spec.ts +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -93,15 +93,17 @@ describe("test network providers on devnet: Proxy and API", function () { it("should have same response for getTransaction(), getTransactionStatus()", async function () { this.timeout(20000); - let sender = new Address("erd1testnlersh4z0wsv8kjx39me4rmnvjkwu8dsaea7ukdvvc9z396qykv7z7"); - let hashes = [ new TransactionHash("b41f5fc39e96b1f194d07761c6efd6cb92278b95f5012ab12cbc910058ca8b54"), new TransactionHash("7757397a59378e9d0f6d5f08cc934c260e33a50ae0d73fdf869f7c02b6b47b33"), new TransactionHash("b87238089e81527158a6daee520280324bc7e5322ba54d1b3c9a5678abe953ea"), new TransactionHash("b45dd5e598bc85ba71639f2cbce8c5dff2fbe93159e637852fddeb16c0e84a48"), new TransactionHash("83db780e98d4d3c917668c47b33ba51445591efacb0df2a922f88e7dfbb5fc7d"), - new TransactionHash("c2eb62b28cc7320da2292d87944c5424a70e1f443323c138c1affada7f6e9705") + new TransactionHash("c2eb62b28cc7320da2292d87944c5424a70e1f443323c138c1affada7f6e9705"), + new TransactionHash("98e913c2a78cafdf4fa7f0113c1285fb29c2409bd7a746bb6f5506ad76841d54"), + new TransactionHash("5b05945be8ba2635e7c13d792ad727533494358308b5fcf36a816e52b5b272b8"), + new TransactionHash("47b089b5f0220299a017359003694a01fd75d075100166b8072c418d5143fe06"), + new TransactionHash("85021f20b06662240d8302d62f68031bbf7261bacb53b84e3dc9346c0f10a8e7") ]; for (const hash of hashes) { diff --git a/src-network-providers/networkProvider/tokens.ts b/src-network-providers/networkProvider/tokens.ts index 235c33f8..716de777 100644 --- a/src-network-providers/networkProvider/tokens.ts +++ b/src-network-providers/networkProvider/tokens.ts @@ -27,51 +27,49 @@ export class NonFungibleTokenOfAccountOnNetwork implements INonFungibleTokenOfAc royalties: BigNumber = new BigNumber(0); static fromProxyHttpResponse(payload: any): NonFungibleTokenOfAccountOnNetwork { - let result = new NonFungibleTokenOfAccountOnNetwork(); + let result = NonFungibleTokenOfAccountOnNetwork.fromHttpResponse(payload); result.identifier = payload.tokenIdentifier || ""; result.collection = NonFungibleTokenOfAccountOnNetwork.parseCollectionFromIdentifier(result.identifier); - result.attributes = Buffer.from(payload.attributes || "", "base64"); - result.balance = new BigNumber(payload.balance || 0); - result.nonce = new Nonce(payload.nonce || 0); - result.creator = new Address(payload.creator || ""); result.royalties = new BigNumber(payload.royalties || 0).div(100); return result; } static fromProxyHttpResponseByNonce(payload: any): NonFungibleTokenOfAccountOnNetwork { - let result = new NonFungibleTokenOfAccountOnNetwork(); + let result = NonFungibleTokenOfAccountOnNetwork.fromHttpResponse(payload); - result.attributes = Buffer.from(payload.attributes || "", "base64"); - result.balance = new BigNumber(payload.balance || 0); - result.nonce = new Nonce(payload.nonce || 0); - result.creator = new Address(payload.creator || ""); - result.royalties = new BigNumber(payload.royalties || 0).div(100); result.identifier = `${payload.tokenIdentifier}-${result.nonce.hex()}`; result.collection = payload.tokenIdentifier || ""; + result.royalties = new BigNumber(payload.royalties || 0).div(100); return result; } - private static parseCollectionFromIdentifier(identifier: string): string { - let parts = identifier.split("-"); - let collection = parts.slice(0, 2).join("-"); - return collection; - } - static fromApiHttpResponse(payload: any): NonFungibleTokenOfAccountOnNetwork { - let result = new NonFungibleTokenOfAccountOnNetwork(); + let result = NonFungibleTokenOfAccountOnNetwork.fromHttpResponse(payload); result.identifier = payload.identifier || ""; result.collection = payload.collection || ""; + + return result; + } + + private static fromHttpResponse(payload: any): NonFungibleTokenOfAccountOnNetwork { + let result = new NonFungibleTokenOfAccountOnNetwork(); + result.attributes = Buffer.from(payload.attributes || "", "base64"); - // On API, missing balance means NFT. result.balance = new BigNumber(payload.balance || 1); result.nonce = new Nonce(payload.nonce || 0); result.creator = new Address(payload.creator || ""); result.royalties = new BigNumber(payload.royalties || 0); - + return result; } + + private static parseCollectionFromIdentifier(identifier: string): string { + let parts = identifier.split("-"); + let collection = parts.slice(0, 2).join("-"); + return collection; + } } From 97581a8aa0ed555e10f888a14820b81f98e80ca9 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 23 Feb 2022 16:12:14 +0200 Subject: [PATCH 011/133] SCRs, tests. --- .../networkProvider/contractResults.ts | 48 ++++++++++++ .../networkProvider/providers.dev.net.spec.ts | 38 +++++++--- .../networkProvider/transactions.ts | 74 +++++++++---------- 3 files changed, 112 insertions(+), 48 deletions(-) diff --git a/src-network-providers/networkProvider/contractResults.ts b/src-network-providers/networkProvider/contractResults.ts index 0915d525..ef719ef5 100644 --- a/src-network-providers/networkProvider/contractResults.ts +++ b/src-network-providers/networkProvider/contractResults.ts @@ -6,17 +6,32 @@ import { IContractQueryResponse, IContractResultItem, IContractResults } from ". import { GasLimit, GasPrice } from "../networkParams"; import { Nonce } from "../nonce"; import { ArgSerializer, EndpointDefinition, MaxUint64, ReturnCode, TypedValue } from "../smartcontracts"; +import { TransactionHash } from "../transaction"; export class ContractResults implements IContractResults { readonly items: IContractResultItem[]; constructor(items: IContractResultItem[]) { this.items = items; + + this.items.sort(function (a: IContractResultItem, b: IContractResultItem) { + return a.nonce.valueOf() - b.nonce.valueOf(); + }); } static empty(): ContractResults { return new ContractResults([]); } + + static fromProxyHttpResponse(results: any[]): ContractResults { + let items = results.map(item => ContractResultItem.fromProxyHttpResponse(item)); + return new ContractResults(items); + } + + static fromApiHttpResponse(results: any[]): ContractResults { + let items = results.map(item => ContractResultItem.fromApiHttpResponse(item)); + return new ContractResults(items); + } } export class ContractResultItem implements IContractResultItem { @@ -32,6 +47,39 @@ export class ContractResultItem implements IContractResultItem { gasPrice: GasPrice = new GasPrice(0); callType: number = 0; returnMessage: string = ""; + + static fromProxyHttpResponse(response: any): ContractResultItem { + let item = ContractResultItem.fromHttpResponse(response); + return item; + } + + static fromApiHttpResponse(response: any): ContractResultItem { + let item = ContractResultItem.fromHttpResponse(response); + + item.data = Buffer.from(item.data, "base64").toString(); + item.callType = Number(item.callType); + + return item; + } + + private static fromHttpResponse(response: any): ContractResultItem { + let item = new ContractResultItem(); + + item.hash = new TransactionHash(response.hash); + item.nonce = new Nonce(response.nonce || 0); + item.value = Balance.fromString(response.value); + item.receiver = new Address(response.receiver); + item.sender = new Address(response.sender); + item.previousHash = new TransactionHash(response.prevTxHash); + item.originalHash = new TransactionHash(response.originalTxHash); + item.gasLimit = new GasLimit(response.gasLimit); + item.gasPrice = new GasPrice(response.gasPrice); + item.data = response.data || ""; + item.callType = response.callType; + item.returnMessage = response.returnMessage; + + return item; + } } export class ContractQueryResponse implements IContractQueryResponse { diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts index 817bc6f7..280c66fe 100644 --- a/src-network-providers/networkProvider/providers.dev.net.spec.ts +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -90,7 +90,7 @@ describe("test network providers on devnet: Proxy and API", function () { } }); - it("should have same response for getTransaction(), getTransactionStatus()", async function () { + it("should have same response for getTransaction()", async function () { this.timeout(20000); let hashes = [ @@ -100,7 +100,8 @@ describe("test network providers on devnet: Proxy and API", function () { new TransactionHash("b45dd5e598bc85ba71639f2cbce8c5dff2fbe93159e637852fddeb16c0e84a48"), new TransactionHash("83db780e98d4d3c917668c47b33ba51445591efacb0df2a922f88e7dfbb5fc7d"), new TransactionHash("c2eb62b28cc7320da2292d87944c5424a70e1f443323c138c1affada7f6e9705"), - new TransactionHash("98e913c2a78cafdf4fa7f0113c1285fb29c2409bd7a746bb6f5506ad76841d54"), + // TODO: Uncomment once the Gateway returns all SCRs in this case, as well. + // new TransactionHash("98e913c2a78cafdf4fa7f0113c1285fb29c2409bd7a746bb6f5506ad76841d54"), new TransactionHash("5b05945be8ba2635e7c13d792ad727533494358308b5fcf36a816e52b5b272b8"), new TransactionHash("47b089b5f0220299a017359003694a01fd75d075100166b8072c418d5143fe06"), new TransactionHash("85021f20b06662240d8302d62f68031bbf7261bacb53b84e3dc9346c0f10a8e7") @@ -113,18 +114,11 @@ describe("test network providers on devnet: Proxy and API", function () { ignoreKnownTransactionDifferencesBetweenProviders(apiResponse, proxyResponse); assert.deepEqual(apiResponse, proxyResponse, `transaction: ${hash}`); } - - for (const hash of hashes) { - let apiResponse = await apiProvider.getTransactionStatus(hash); - let proxyResponse = await proxyProvider.getTransactionStatus(hash); - - // TODO: Fix differences of "tx.status". - // assert.deepEqual(apiResponse, proxyResponse, `transaction: ${hash}`); - } }); // TODO: Strive to have as little differences as possible between Proxy and API. function ignoreKnownTransactionDifferencesBetweenProviders(apiResponse: ITransactionOnNetwork, proxyResponse: ITransactionOnNetwork) { + // TODO: Remove this once "tx.status" is uniformized. apiResponse.status = proxyResponse.status = new TransactionStatus("ignore"); // Ignore fields which are not present on API response: @@ -134,6 +128,30 @@ describe("test network providers on devnet: Proxy and API", function () { proxyResponse.hyperblockHash = new Hash(""); } + // TODO: Fix differences of "tx.status", then enable this test. + it.skip("should have same response for getTransactionStatus()", async function () { + this.timeout(20000); + + let hashes = [ + new TransactionHash("b41f5fc39e96b1f194d07761c6efd6cb92278b95f5012ab12cbc910058ca8b54"), + new TransactionHash("7757397a59378e9d0f6d5f08cc934c260e33a50ae0d73fdf869f7c02b6b47b33"), + new TransactionHash("b87238089e81527158a6daee520280324bc7e5322ba54d1b3c9a5678abe953ea"), + new TransactionHash("b45dd5e598bc85ba71639f2cbce8c5dff2fbe93159e637852fddeb16c0e84a48"), + new TransactionHash("83db780e98d4d3c917668c47b33ba51445591efacb0df2a922f88e7dfbb5fc7d"), + new TransactionHash("c2eb62b28cc7320da2292d87944c5424a70e1f443323c138c1affada7f6e9705"), + new TransactionHash("98e913c2a78cafdf4fa7f0113c1285fb29c2409bd7a746bb6f5506ad76841d54"), + new TransactionHash("5b05945be8ba2635e7c13d792ad727533494358308b5fcf36a816e52b5b272b8"), + new TransactionHash("47b089b5f0220299a017359003694a01fd75d075100166b8072c418d5143fe06"), + new TransactionHash("85021f20b06662240d8302d62f68031bbf7261bacb53b84e3dc9346c0f10a8e7") + ]; + + for (const hash of hashes) { + let apiResponse = await apiProvider.getTransactionStatus(hash); + let proxyResponse = await proxyProvider.getTransactionStatus(hash); + assert.deepEqual(apiResponse, proxyResponse, `transaction: ${hash}`); + } + }); + it("should have same response for getDefinitionOfFungibleToken()", async function () { this.timeout(10000); diff --git a/src-network-providers/networkProvider/transactions.ts b/src-network-providers/networkProvider/transactions.ts index fd46e4fb..91ae09bb 100644 --- a/src-network-providers/networkProvider/transactions.ts +++ b/src-network-providers/networkProvider/transactions.ts @@ -1,12 +1,14 @@ import { Address } from "../address"; import { Balance } from "../balance"; import { Hash } from "../hash"; -import { ITransactionOnNetwork } from "../interface.networkProvider"; +import { IContractResults, ITransactionOnNetwork } from "../interface.networkProvider"; import { GasLimit, GasPrice } from "../networkParams"; import { Nonce } from "../nonce"; import { Signature } from "../signature"; import { TransactionHash, TransactionStatus } from "../transaction"; +import { TransactionLogs } from "../transactionLogs"; import { TransactionPayload } from "../transactionPayload"; +import { ContractResults } from "./contractResults"; export class TransactionOnNetwork implements ITransactionOnNetwork { hash: TransactionHash = new TransactionHash(""); @@ -27,50 +29,46 @@ import { TransactionPayload } from "../transactionPayload"; hyperblockNonce: Nonce = new Nonce(0); hyperblockHash: Hash = Hash.empty(); - static fromProxyHttpResponse(txHash: TransactionHash, response: any): TransactionOnNetwork { - let transactionOnNetwork = new TransactionOnNetwork(); - - transactionOnNetwork.hash = txHash; - transactionOnNetwork.nonce = new Nonce(response.nonce || 0); - transactionOnNetwork.round = response.round; - transactionOnNetwork.epoch = response.epoch || 0; - transactionOnNetwork.value = Balance.fromString(response.value); - transactionOnNetwork.sender = Address.fromBech32(response.sender); - transactionOnNetwork.receiver = Address.fromBech32(response.receiver); - transactionOnNetwork.gasPrice = new GasPrice(response.gasPrice); - transactionOnNetwork.gasLimit = new GasLimit(response.gasLimit); - transactionOnNetwork.data = TransactionPayload.fromEncoded(response.data); - transactionOnNetwork.status = new TransactionStatus(response.status); - transactionOnNetwork.timestamp = response.timestamp || 0; + logs: TransactionLogs = TransactionLogs.empty(); + contractResults: IContractResults = ContractResults.empty(); - transactionOnNetwork.blockNonce = new Nonce(response.blockNonce || 0); - transactionOnNetwork.hyperblockNonce = new Nonce(response.hyperblockNonce || 0); - transactionOnNetwork.hyperblockHash = new Hash(response.hyperblockHash); - - return transactionOnNetwork; + static fromProxyHttpResponse(txHash: TransactionHash, response: any): TransactionOnNetwork { + let result = TransactionOnNetwork.fromHttpResponse(txHash, response); + result.contractResults = ContractResults.fromProxyHttpResponse(response.smartContractResults || []); + // TODO: uniformize transaction status + return result; } static fromApiHttpResponse(txHash: TransactionHash, response: any): TransactionOnNetwork { - let transactionOnNetwork = new TransactionOnNetwork(); + let result = TransactionOnNetwork.fromHttpResponse(txHash, response); + result.contractResults = ContractResults.fromApiHttpResponse(response.results || []); + // TODO: uniformize transaction status + return result; + } + + private static fromHttpResponse(txHash: TransactionHash, response: any): TransactionOnNetwork { + let result = new TransactionOnNetwork(); + + result.hash = txHash; + result.nonce = new Nonce(response.nonce || 0); + result.round = response.round; + result.epoch = response.epoch || 0; + result.value = Balance.fromString(response.value); + result.sender = Address.fromBech32(response.sender); + result.receiver = Address.fromBech32(response.receiver); + result.gasPrice = new GasPrice(response.gasPrice); + result.gasLimit = new GasLimit(response.gasLimit); + result.data = TransactionPayload.fromEncoded(response.data); + result.status = new TransactionStatus(response.status); + result.timestamp = response.timestamp || 0; - transactionOnNetwork.hash = txHash; - transactionOnNetwork.nonce = new Nonce(response.nonce || 0); - transactionOnNetwork.round = response.round; - transactionOnNetwork.epoch = response.epoch || 0; - transactionOnNetwork.value = Balance.fromString(response.value); - transactionOnNetwork.sender = Address.fromBech32(response.sender); - transactionOnNetwork.receiver = Address.fromBech32(response.receiver); - transactionOnNetwork.gasPrice = new GasPrice(response.gasPrice); - transactionOnNetwork.gasLimit = new GasLimit(response.gasLimit); - transactionOnNetwork.data = TransactionPayload.fromEncoded(response.data); - transactionOnNetwork.status = new TransactionStatus(response.status); - transactionOnNetwork.timestamp = response.timestamp || 0; + result.blockNonce = new Nonce(response.blockNonce || 0); + result.hyperblockNonce = new Nonce(response.hyperblockNonce || 0); + result.hyperblockHash = new Hash(response.hyperblockHash); - transactionOnNetwork.blockNonce = new Nonce(response.blockNonce || 0); - transactionOnNetwork.hyperblockNonce = new Nonce(response.hyperblockNonce || 0); - transactionOnNetwork.hyperblockHash = new Hash(response.hyperblockHash); + result.logs = TransactionLogs.fromHttpResponse(response.logs || {}); - return transactionOnNetwork; + return result; } getDateTime(): Date { From 4958a0c2375399bb936ce34f1f2bf3b99f110a04 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 23 Feb 2022 16:45:05 +0200 Subject: [PATCH 012/133] Fix after self-review. --- .../networkProvider/apiNetworkProvider.ts | 7 ------- src-network-providers/networkProvider/index.ts | 4 ++-- .../networkProvider/providers.dev.net.spec.ts | 15 +++++++++++++++ .../networkProvider/proxyNetworkProvider.ts | 5 ----- .../networkProvider/tokenDefinitions.ts | 2 +- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index 1b87925c..d297e213 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -23,11 +23,6 @@ export class ApiNetworkProvider implements INetworkProvider { private config: AxiosRequestConfig; private backingProxyNetworkProvider; - /** - * Creates a new ApiProvider. - * @param url the URL of the Elrond Api - * @param config axios request config options - */ constructor(url: string, config?: AxiosRequestConfig) { this.url = url; this.config = { ...defaultConfig, ...config }; @@ -110,7 +105,6 @@ export class ApiNetworkProvider implements INetworkProvider { async sendTransaction(tx: Transaction): Promise { let response = await this.doPostGeneric("transactions", tx.toSendable()); - // Also see: https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/transactions/entities/transaction.send.result.ts let hash = new TransactionHash(response.txHash); return hash; } @@ -162,7 +156,6 @@ export class ApiNetworkProvider implements INetworkProvider { try { let url = `${this.url}/${resourceUrl}`; let response = await axios.get(url, this.config); - return response.data; } catch (error) { this.handleApiError(error, resourceUrl); diff --git a/src-network-providers/networkProvider/index.ts b/src-network-providers/networkProvider/index.ts index a4276ae7..0c4e6aa0 100644 --- a/src-network-providers/networkProvider/index.ts +++ b/src-network-providers/networkProvider/index.ts @@ -1,5 +1,5 @@ export * from "./apiNetworkProvider"; export * from "./proxyNetworkProvider"; -// do not export "./tokens" (encapsulation) -// do not export "./transactions" (encapsulation) +// we do not export "./tokens" +// we do not export "./transactions" diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts index 280c66fe..8fb4c267 100644 --- a/src-network-providers/networkProvider/providers.dev.net.spec.ts +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -27,12 +27,14 @@ describe("test network providers on devnet: Proxy and API", function () { it("should have same response for getNetworkConfig()", async function () { let apiResponse = await apiProvider.getNetworkConfig(); let proxyResponse = await proxyProvider.getNetworkConfig(); + assert.deepEqual(apiResponse, proxyResponse); }); it("should have same response for getNetworkStatus()", async function () { let apiResponse = await apiProvider.getNetworkStatus(); let proxyResponse = await proxyProvider.getNetworkStatus(); + assert.deepEqual(apiResponse, proxyResponse); }); @@ -40,6 +42,7 @@ describe("test network providers on devnet: Proxy and API", function () { it.skip("should have same response for getNetworkStakeStatistics()", async function () { let apiResponse = await apiProvider.getNetworkStakeStatistics(); let proxyResponse = await proxyProvider.getNetworkStakeStatistics(); + assert.deepEqual(apiResponse, proxyResponse); }); @@ -47,6 +50,7 @@ describe("test network providers on devnet: Proxy and API", function () { it.skip("should have same response for getNetworkGeneralStatistics()", async function () { let apiResponse = await apiProvider.getNetworkGeneralStatistics(); let proxyResponse = await proxyProvider.getNetworkGeneralStatistics(); + assert.deepEqual(apiResponse, proxyResponse); }); @@ -54,6 +58,7 @@ describe("test network providers on devnet: Proxy and API", function () { for (const user of [bob, carol, dan]) { let apiResponse = await apiProvider.getAccount(user.address); let proxyResponse = await proxyProvider.getAccount(user.address); + assert.deepEqual(apiResponse, proxyResponse); } }); @@ -64,11 +69,13 @@ describe("test network providers on devnet: Proxy and API", function () { for (const user of [carol, dan]) { let apiResponse = await apiProvider.getFungibleTokensOfAccount(user.address); let proxyResponse = await proxyProvider.getFungibleTokensOfAccount(user.address); + assert.deepEqual(apiResponse.slice(0, 100), proxyResponse.slice(0, 100)); for (const item of apiResponse.slice(0, 5)) { let apiResponse = await apiProvider.getFungibleTokenOfAccount(user.address, item.identifier); let proxyResponse = await proxyProvider.getFungibleTokenOfAccount(user.address, item.identifier); + assert.deepEqual(apiResponse, proxyResponse, `user: ${user.address.bech32()}, token: ${item.identifier}`); } } @@ -80,11 +87,13 @@ describe("test network providers on devnet: Proxy and API", function () { for (const user of [alice, bob, carol, dan]) { let apiResponse = await apiProvider.getNonFungibleTokensOfAccount(user.address); let proxyResponse = await proxyProvider.getNonFungibleTokensOfAccount(user.address); + assert.deepEqual(apiResponse.slice(0, 100), proxyResponse.slice(0, 100)); for (const item of apiResponse.slice(0, 5)) { let apiResponse = await apiProvider.getNonFungibleTokenOfAccount(user.address, item.collection, item.nonce); let proxyResponse = await proxyProvider.getNonFungibleTokenOfAccount(user.address, item.collection, item.nonce); + assert.deepEqual(apiResponse, proxyResponse, `user: ${user.address.bech32()}, token: ${item.identifier}`); } } @@ -148,6 +157,7 @@ describe("test network providers on devnet: Proxy and API", function () { for (const hash of hashes) { let apiResponse = await apiProvider.getTransactionStatus(hash); let proxyResponse = await proxyProvider.getTransactionStatus(hash); + assert.deepEqual(apiResponse, proxyResponse, `transaction: ${hash}`); } }); @@ -175,6 +185,7 @@ describe("test network providers on devnet: Proxy and API", function () { for (const collection of collections) { let apiResponse = await apiProvider.getDefinitionOfTokenCollection(collection); + assert.equal(apiResponse.collection, collection); // TODO: Uncomment after implementing the function in the proxy provider. @@ -190,6 +201,7 @@ describe("test network providers on devnet: Proxy and API", function () { for (const token of tokens) { let apiResponse = await apiProvider.getNonFungibleToken(token.id, token.nonce); + assert.equal(apiResponse.collection, token.id); // TODO: Uncomment after implementing the function in the proxy provider. @@ -212,6 +224,7 @@ describe("test network providers on devnet: Proxy and API", function () { let apiResponse = await apiProvider.queryContract(query); let proxyResponse = await proxyProvider.queryContract(query); + assert.deepEqual(apiResponse, proxyResponse); assert.deepEqual(apiResponse.getOutputUntyped(), proxyResponse.getOutputUntyped()); @@ -224,6 +237,7 @@ describe("test network providers on devnet: Proxy and API", function () { apiResponse = await apiProvider.queryContract(query); proxyResponse = await proxyProvider.queryContract(query); + assert.deepEqual(apiResponse, proxyResponse); assert.deepEqual(apiResponse.getOutputUntyped(), proxyResponse.getOutputUntyped()); @@ -243,6 +257,7 @@ describe("test network providers on devnet: Proxy and API", function () { apiResponse = await apiProvider.queryContract(query); proxyResponse = await proxyProvider.queryContract(query); + assert.deepEqual(apiResponse, proxyResponse); assert.deepEqual(apiResponse.getOutputUntyped(), proxyResponse.getOutputUntyped()); }); diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index c9f1d348..45d6f644 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -20,11 +20,6 @@ export class ProxyNetworkProvider implements INetworkProvider { private url: string; private config: AxiosRequestConfig; - /** - * Creates a new {@link INetworkProvider} backed by an Elrond Proxy. - * @param url the URL of the Elrond Proxy - * @param config axios request config options - */ constructor(url: string, config?: AxiosRequestConfig) { this.url = url; this.config = { ...defaultConfig, ...config }; diff --git a/src-network-providers/networkProvider/tokenDefinitions.ts b/src-network-providers/networkProvider/tokenDefinitions.ts index 407e05d1..3e058109 100644 --- a/src-network-providers/networkProvider/tokenDefinitions.ts +++ b/src-network-providers/networkProvider/tokenDefinitions.ts @@ -1,6 +1,6 @@ import { BigNumber } from "bignumber.js"; import { Address } from "../address"; -import { IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INonFungibleTokenOfAccountOnNetwork } from "../interface.networkProvider"; +import { IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork } from "../interface.networkProvider"; export class DefinitionOfFungibleTokenOnNetwork implements IDefinitionOfFungibleTokenOnNetwork { identifier: string = ""; From 86480d61f92a0e124b3878a4163c3dd62225853c Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 23 Feb 2022 16:52:31 +0200 Subject: [PATCH 013/133] Fix after self-review. --- .../networkProvider/contractResults.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src-network-providers/networkProvider/contractResults.ts b/src-network-providers/networkProvider/contractResults.ts index ef719ef5..69e5f574 100644 --- a/src-network-providers/networkProvider/contractResults.ts +++ b/src-network-providers/networkProvider/contractResults.ts @@ -80,6 +80,16 @@ export class ContractResultItem implements IContractResultItem { return item; } + + getOutputUntyped(): Buffer[] { + // TODO: Decide how to parse "data" (immediate results vs. other results). + throw new Error("Method not implemented."); + } + + getOutputTyped(_endpointDefinition: EndpointDefinition): TypedValue[] { + // TODO: Decide how to parse "data" (immediate results vs. other results). + throw new Error("Method not implemented."); + } } export class ContractQueryResponse implements IContractQueryResponse { From 66fee8043308072ecd58cdc952e32bc751dbec43 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 24 Feb 2022 12:22:08 +0200 Subject: [PATCH 014/133] Fix after review. --- .../networkProvider/apiNetworkProvider.ts | 3 +- .../networkProvider/contractResults.ts | 2 +- .../networkProvider/interface.ts | 229 ++++++++++++++++++ .../networkProvider/providers.dev.net.spec.ts | 2 +- .../networkProvider/proxyNetworkProvider.ts | 3 +- .../networkProvider/tokenDefinitions.ts | 2 +- .../networkProvider/tokens.ts | 2 +- .../networkProvider/transactions.ts | 2 +- 8 files changed, 238 insertions(+), 7 deletions(-) create mode 100644 src-network-providers/networkProvider/interface.ts diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index d297e213..3d809404 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -3,7 +3,7 @@ import { AccountOnNetwork } from "../account"; import { Address } from "../address"; import { defaultConfig } from "../constants"; import { ErrNetworkProvider } from "../errors"; -import { IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, Pagination } from "../interface.networkProvider"; +import { IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, Pagination } from "./interface"; import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; @@ -18,6 +18,7 @@ import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwor import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; +// TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ApiNetworkProvider implements INetworkProvider { private url: string; private config: AxiosRequestConfig; diff --git a/src-network-providers/networkProvider/contractResults.ts b/src-network-providers/networkProvider/contractResults.ts index 69e5f574..c4b0126a 100644 --- a/src-network-providers/networkProvider/contractResults.ts +++ b/src-network-providers/networkProvider/contractResults.ts @@ -2,7 +2,7 @@ import { BigNumber } from "bignumber.js"; import { Address } from "../address"; import { Balance } from "../balance"; import { Hash } from "../hash"; -import { IContractQueryResponse, IContractResultItem, IContractResults } from "../interface.networkProvider"; +import { IContractQueryResponse, IContractResultItem, IContractResults } from "./interface"; import { GasLimit, GasPrice } from "../networkParams"; import { Nonce } from "../nonce"; import { ArgSerializer, EndpointDefinition, MaxUint64, ReturnCode, TypedValue } from "../smartcontracts"; diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/networkProvider/interface.ts new file mode 100644 index 00000000..a5f9689c --- /dev/null +++ b/src-network-providers/networkProvider/interface.ts @@ -0,0 +1,229 @@ +import { BigNumber } from "bignumber.js"; +import { Balance, GasLimit, GasPrice, Nonce, TransactionPayload } from ".."; +import { AccountOnNetwork } from "../account"; +import { Address } from "../address"; +import { Hash } from "../hash"; +import { NetworkConfig } from "../networkConfig"; +import { NetworkStake } from "../networkStake"; +import { NetworkStatus } from "../networkStatus"; +import { Signature } from "../signature"; +import { EndpointDefinition, Query, ReturnCode, TypedValue } from "../smartcontracts"; +import { Stats } from "../stats"; +import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; +import { TransactionLogs } from "../transactionLogs"; + +/** + * An interface that defines the endpoints of an HTTP API Provider. + */ +export interface INetworkProvider { + /** + * Fetches the Network configuration. + */ + getNetworkConfig(): Promise; + + /** + * Fetches the Network status. + */ + getNetworkStatus(): Promise; + + /** + * Fetches stake statistics. + */ + getNetworkStakeStatistics(): Promise; + + /** + * Fetches general statistics. + */ + getNetworkGeneralStatistics(): Promise; + + /** + * Fetches the state of an {@link Account}. + */ + getAccount(address: Address): Promise; + + /** + * Fetches data about the fungible tokens held by an account. + */ + getFungibleTokensOfAccount(address: Address, pagination?: Pagination): Promise; + + /** + * Fetches data about the non-fungible tokens held by account. + */ + getNonFungibleTokensOfAccount(address: Address, pagination?: Pagination): Promise; + + /** + * Fetches data about a specific fungible token held by an account. + */ + getFungibleTokenOfAccount(address: Address, tokenIdentifier: string): Promise; + + /** + * Fetches data about a specific non-fungible token (instance) held by an account. + */ + getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: Nonce): Promise; + + /** + * Fetches the state of a {@link Transaction}. + */ + getTransaction(txHash: TransactionHash): Promise; + + /** + * Queries the status of a {@link Transaction}. + */ + getTransactionStatus(txHash: TransactionHash): Promise; + + /** + * Broadcasts an already-signed {@link Transaction}. + */ + sendTransaction(tx: Transaction): Promise; + + /** + * Simulates the processing of an already-signed {@link Transaction}. + * + */ + simulateTransaction(tx: Transaction): Promise; + + /** + * Queries a Smart Contract - runs a pure function defined by the contract and returns its results. + */ + queryContract(query: Query): Promise; + + /** + * Fetches the definition of a fungible token. + * + */ + getDefinitionOfFungibleToken(tokenIdentifier: string): Promise; + + /** + * Fetches the definition of a SFT (including Meta ESDT) or NFT. + * + */ + getDefinitionOfTokenCollection(collection: string): Promise; + + /** + * Fetches data about a specific non-fungible token (instance). + */ + getNonFungibleToken(collection: string, nonce: Nonce): Promise; + + /** + * Performs a generic GET action against the provider (useful for new HTTP endpoints, not yet supported by erdjs). + */ + doGetGeneric(resourceUrl: string): Promise; + + /** + * Performs a generic POST action against the provider (useful for new HTTP endpoints, not yet supported by erdjs). + */ + doPostGeneric(resourceUrl: string, payload: any): Promise; +} + +export interface IFungibleTokenOfAccountOnNetwork { + identifier: string; + balance: BigNumber; +} + +export interface INonFungibleTokenOfAccountOnNetwork { + identifier: string; + collection: string; + attributes: Buffer; + balance: BigNumber; + nonce: Nonce; + creator: Address; + royalties: BigNumber; +} + + +export interface IDefinitionOfFungibleTokenOnNetwork { + identifier: string; + name: string; + ticker: string; + owner: Address; + decimals: number; + supply: BigNumber; + isPaused: boolean; + canUpgrade: boolean; + canMint: boolean; + canBurn: boolean; + canChangeOwner: boolean; + canPause: boolean; + canFreeze: boolean; + canWipe: boolean; + canAddSpecialRoles: boolean; +} + +export interface IDefinitionOfTokenCollectionOnNetwork { + collection: string; + type: string; + name: string; + ticker: string; + owner: Address; + decimals: number; + canPause: boolean; + canFreeze: boolean; + canWipe: boolean; + canTransferRole: boolean; + // TODO: add "assets", "roles" +} + +export interface ITransactionOnNetwork { + hash: TransactionHash; + nonce: Nonce; + round: number; + epoch: number; + value: Balance; + receiver: Address; + sender: Address; + gasPrice: GasPrice; + gasLimit: GasLimit; + data: TransactionPayload; + signature: Signature; + status: TransactionStatus; + timestamp: number; + blockNonce: Nonce; + hyperblockNonce: Nonce; + hyperblockHash: Hash; + logs: TransactionLogs; + contractResults: IContractResults; +} + +export interface IContractResults { + items: IContractResultItem[]; +} + +export interface IContractResultItem { + hash: Hash; + nonce: Nonce; + value: Balance; + receiver: Address; + sender: Address; + data: string; + previousHash: Hash; + originalHash: Hash; + gasLimit: GasLimit; + gasPrice: GasPrice; + callType: number; + returnMessage: string; + + getOutputUntyped(): Buffer[]; + getOutputTyped(endpointDefinition: EndpointDefinition): TypedValue[]; +} + +export interface IContractQueryResponse { + returnData: string[]; + returnCode: ReturnCode; + returnMessage: string; + gasUsed: GasLimit; + + getOutputUntyped(): Buffer[]; + getOutputTyped(endpointDefinition: EndpointDefinition): TypedValue[]; +} + +export interface IContractSimulation { +} + +export class Pagination { + from: number = 0; + size: number = 100; + + static default(): Pagination { + return { from: 0, size: 100 }; + } +} diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts index 8fb4c267..7c953b5b 100644 --- a/src-network-providers/networkProvider/providers.dev.net.spec.ts +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -1,7 +1,7 @@ import { assert } from "chai"; import { ApiNetworkProvider, ProxyNetworkProvider } from "."; import { Hash } from "../hash"; -import { INetworkProvider, ITransactionOnNetwork } from "../interface.networkProvider"; +import { INetworkProvider, ITransactionOnNetwork } from "./interface"; import { Address } from "../address"; import { loadTestWallets, TestWallet } from "../testutils"; import { TransactionHash, TransactionStatus } from "../transaction"; diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index 45d6f644..57f5b238 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -3,7 +3,7 @@ import { AccountOnNetwork } from "../account"; import { Address } from "../address"; import { defaultConfig } from "../constants"; import { ErrNetworkProvider } from "../errors"; -import { IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, Pagination } from "../interface.networkProvider"; +import { IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, Pagination } from "./interface"; import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; @@ -16,6 +16,7 @@ import { ContractQueryResponse } from "./contractResults"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; +// TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ProxyNetworkProvider implements INetworkProvider { private url: string; private config: AxiosRequestConfig; diff --git a/src-network-providers/networkProvider/tokenDefinitions.ts b/src-network-providers/networkProvider/tokenDefinitions.ts index 3e058109..77b784e6 100644 --- a/src-network-providers/networkProvider/tokenDefinitions.ts +++ b/src-network-providers/networkProvider/tokenDefinitions.ts @@ -1,6 +1,6 @@ import { BigNumber } from "bignumber.js"; import { Address } from "../address"; -import { IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork } from "../interface.networkProvider"; +import { IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork } from "./interface"; export class DefinitionOfFungibleTokenOnNetwork implements IDefinitionOfFungibleTokenOnNetwork { identifier: string = ""; diff --git a/src-network-providers/networkProvider/tokens.ts b/src-network-providers/networkProvider/tokens.ts index 716de777..303fdb7c 100644 --- a/src-network-providers/networkProvider/tokens.ts +++ b/src-network-providers/networkProvider/tokens.ts @@ -1,6 +1,6 @@ import { BigNumber } from "bignumber.js"; import { Address } from "../address"; -import { IFungibleTokenOfAccountOnNetwork, INonFungibleTokenOfAccountOnNetwork } from "../interface.networkProvider"; +import { IFungibleTokenOfAccountOnNetwork, INonFungibleTokenOfAccountOnNetwork } from "./interface"; import { Nonce } from "../nonce"; export class FungibleTokenOfAccountOnNetwork implements IFungibleTokenOfAccountOnNetwork { diff --git a/src-network-providers/networkProvider/transactions.ts b/src-network-providers/networkProvider/transactions.ts index 91ae09bb..6fd3c906 100644 --- a/src-network-providers/networkProvider/transactions.ts +++ b/src-network-providers/networkProvider/transactions.ts @@ -1,7 +1,7 @@ import { Address } from "../address"; import { Balance } from "../balance"; import { Hash } from "../hash"; -import { IContractResults, ITransactionOnNetwork } from "../interface.networkProvider"; +import { IContractResults, ITransactionOnNetwork } from "./interface"; import { GasLimit, GasPrice } from "../networkParams"; import { Nonce } from "../nonce"; import { Signature } from "../signature"; From 790a3528f152fa5fba4421d51bfad0b65223d3cf Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 14 Mar 2022 11:04:14 +0200 Subject: [PATCH 015/133] Fix remaining imports. --- src-network-providers/networkProvider/interface.ts | 5 ++++- .../networkProvider/providers.dev.net.spec.ts | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/networkProvider/interface.ts index a5f9689c..287fd791 100644 --- a/src-network-providers/networkProvider/interface.ts +++ b/src-network-providers/networkProvider/interface.ts @@ -1,16 +1,19 @@ import { BigNumber } from "bignumber.js"; -import { Balance, GasLimit, GasPrice, Nonce, TransactionPayload } from ".."; import { AccountOnNetwork } from "../account"; import { Address } from "../address"; +import { Balance } from "../balance"; import { Hash } from "../hash"; import { NetworkConfig } from "../networkConfig"; +import { GasLimit, GasPrice } from "../networkParams"; import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; +import { Nonce } from "../nonce"; import { Signature } from "../signature"; import { EndpointDefinition, Query, ReturnCode, TypedValue } from "../smartcontracts"; import { Stats } from "../stats"; import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; import { TransactionLogs } from "../transactionLogs"; +import { TransactionPayload } from "../transactionPayload"; /** * An interface that defines the endpoints of an HTTP API Provider. diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts index 7c953b5b..8ee0031b 100644 --- a/src-network-providers/networkProvider/providers.dev.net.spec.ts +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -1,5 +1,4 @@ import { assert } from "chai"; -import { ApiNetworkProvider, ProxyNetworkProvider } from "."; import { Hash } from "../hash"; import { INetworkProvider, ITransactionOnNetwork } from "./interface"; import { Address } from "../address"; @@ -10,6 +9,8 @@ import { ContractFunction, Query } from "../smartcontracts"; import { BigUIntValue, U32Value, BytesValue, VariadicValue, VariadicType, CompositeType, BytesType, BooleanType } from "../smartcontracts/typesystem"; import { BigNumber } from "bignumber.js"; import { Balance } from "../balance"; +import { ApiNetworkProvider } from "./apiNetworkProvider"; +import { ProxyNetworkProvider } from "./proxyNetworkProvider"; describe("test network providers on devnet: Proxy and API", function () { let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 10000 }); From 41084c6739401a667c576ce985fb8473efbe87bf Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Sun, 20 Mar 2022 11:20:29 +0200 Subject: [PATCH 016/133] Refactor contract results (breaking change). --- .../networkProvider/contractResults.ts | 23 +++---------------- .../networkProvider/interface.ts | 10 +++----- .../networkProvider/providers.dev.net.spec.ts | 6 ++--- 3 files changed, 9 insertions(+), 30 deletions(-) diff --git a/src-network-providers/networkProvider/contractResults.ts b/src-network-providers/networkProvider/contractResults.ts index c4b0126a..8cebbb3e 100644 --- a/src-network-providers/networkProvider/contractResults.ts +++ b/src-network-providers/networkProvider/contractResults.ts @@ -5,7 +5,7 @@ import { Hash } from "../hash"; import { IContractQueryResponse, IContractResultItem, IContractResults } from "./interface"; import { GasLimit, GasPrice } from "../networkParams"; import { Nonce } from "../nonce"; -import { ArgSerializer, EndpointDefinition, MaxUint64, ReturnCode, TypedValue } from "../smartcontracts"; +import { MaxUint64, ReturnCode } from "../smartcontracts"; import { TransactionHash } from "../transaction"; export class ContractResults implements IContractResults { @@ -80,16 +80,6 @@ export class ContractResultItem implements IContractResultItem { return item; } - - getOutputUntyped(): Buffer[] { - // TODO: Decide how to parse "data" (immediate results vs. other results). - throw new Error("Method not implemented."); - } - - getOutputTyped(_endpointDefinition: EndpointDefinition): TypedValue[] { - // TODO: Decide how to parse "data" (immediate results vs. other results). - throw new Error("Method not implemented."); - } } export class ContractQueryResponse implements IContractQueryResponse { @@ -110,14 +100,7 @@ export class ContractQueryResponse implements IContractQueryResponse { return response; } - getOutputUntyped(): Buffer[] { - let buffers = this.returnData.map((item) => Buffer.from(item || "", "base64")); - return buffers; - } - - getOutputTyped(endpointDefinition: EndpointDefinition): TypedValue[] { - let buffers = this.getOutputUntyped(); - let values = new ArgSerializer().buffersToValues(buffers, endpointDefinition!.output); - return values; + getReturnDataParts(): Buffer[] { + return this.returnData.map((item) => Buffer.from(item || "")); } } diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/networkProvider/interface.ts index 287fd791..4f21dbe4 100644 --- a/src-network-providers/networkProvider/interface.ts +++ b/src-network-providers/networkProvider/interface.ts @@ -9,7 +9,7 @@ import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; import { Nonce } from "../nonce"; import { Signature } from "../signature"; -import { EndpointDefinition, Query, ReturnCode, TypedValue } from "../smartcontracts"; +import { Query, ReturnCode } from "../smartcontracts"; import { Stats } from "../stats"; import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; import { TransactionLogs } from "../transactionLogs"; @@ -204,9 +204,6 @@ export interface IContractResultItem { gasPrice: GasPrice; callType: number; returnMessage: string; - - getOutputUntyped(): Buffer[]; - getOutputTyped(endpointDefinition: EndpointDefinition): TypedValue[]; } export interface IContractQueryResponse { @@ -214,9 +211,8 @@ export interface IContractQueryResponse { returnCode: ReturnCode; returnMessage: string; gasUsed: GasLimit; - - getOutputUntyped(): Buffer[]; - getOutputTyped(endpointDefinition: EndpointDefinition): TypedValue[]; + + getReturnDataParts(): Buffer[]; } export interface IContractSimulation { diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts index 8ee0031b..affbd8d0 100644 --- a/src-network-providers/networkProvider/providers.dev.net.spec.ts +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -227,7 +227,7 @@ describe("test network providers on devnet: Proxy and API", function () { let proxyResponse = await proxyProvider.queryContract(query); assert.deepEqual(apiResponse, proxyResponse); - assert.deepEqual(apiResponse.getOutputUntyped(), proxyResponse.getOutputUntyped()); + assert.deepEqual(apiResponse.getReturnDataParts(), proxyResponse.getReturnDataParts()); // Query: increment counter query = new Query({ @@ -240,7 +240,7 @@ describe("test network providers on devnet: Proxy and API", function () { proxyResponse = await proxyProvider.queryContract(query); assert.deepEqual(apiResponse, proxyResponse); - assert.deepEqual(apiResponse.getOutputUntyped(), proxyResponse.getOutputUntyped()); + assert.deepEqual(apiResponse.getReturnDataParts(), proxyResponse.getReturnDataParts()); // Query: issue ESDT query = new Query({ @@ -260,6 +260,6 @@ describe("test network providers on devnet: Proxy and API", function () { proxyResponse = await proxyProvider.queryContract(query); assert.deepEqual(apiResponse, proxyResponse); - assert.deepEqual(apiResponse.getOutputUntyped(), proxyResponse.getOutputUntyped()); + assert.deepEqual(apiResponse.getReturnDataParts(), proxyResponse.getReturnDataParts()); }); }); From 9b645b648aa296f5c1c91ef9ff83b3b9aafc2b42 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 5 Apr 2022 18:05:28 +0300 Subject: [PATCH 017/133] Preparatory refactoring. --- .../networkProvider/contractResults.ts | 11 ++- .../networkProvider/interface.ts | 47 ++++++++++++- .../networkProvider/receipt.ts | 26 +++++++ .../transactionCompletionStrategy.ts | 68 +++++++++++++++++++ .../networkProvider/transactionEvents.ts | 58 ++++++++++++++++ .../networkProvider/transactionLogs.ts | 47 +++++++++++++ .../networkProvider/transactions.ts | 40 +++++++++-- 7 files changed, 288 insertions(+), 9 deletions(-) create mode 100644 src-network-providers/networkProvider/receipt.ts create mode 100644 src-network-providers/networkProvider/transactionCompletionStrategy.ts create mode 100644 src-network-providers/networkProvider/transactionEvents.ts create mode 100644 src-network-providers/networkProvider/transactionLogs.ts diff --git a/src-network-providers/networkProvider/contractResults.ts b/src-network-providers/networkProvider/contractResults.ts index 8cebbb3e..0defc915 100644 --- a/src-network-providers/networkProvider/contractResults.ts +++ b/src-network-providers/networkProvider/contractResults.ts @@ -2,11 +2,12 @@ import { BigNumber } from "bignumber.js"; import { Address } from "../address"; import { Balance } from "../balance"; import { Hash } from "../hash"; -import { IContractQueryResponse, IContractResultItem, IContractResults } from "./interface"; +import { IContractQueryResponse, IContractResultItem, IContractResults, ITransactionLogs } from "./interface"; import { GasLimit, GasPrice } from "../networkParams"; import { Nonce } from "../nonce"; import { MaxUint64, ReturnCode } from "../smartcontracts"; import { TransactionHash } from "../transaction"; +import { TransactionLogs } from "./transactionLogs"; export class ContractResults implements IContractResults { readonly items: IContractResultItem[]; @@ -47,6 +48,12 @@ export class ContractResultItem implements IContractResultItem { gasPrice: GasPrice = new GasPrice(0); callType: number = 0; returnMessage: string = ""; + logs: ITransactionLogs = TransactionLogs.empty(); + + constructor(init?: Partial) { + Object.assign(this, init); + } + static fromProxyHttpResponse(response: any): ContractResultItem { let item = ContractResultItem.fromHttpResponse(response); @@ -78,6 +85,8 @@ export class ContractResultItem implements IContractResultItem { item.callType = response.callType; item.returnMessage = response.returnMessage; + item.logs = TransactionLogs.fromHttpResponse(response.logs || {}); + return item; } } diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/networkProvider/interface.ts index 4f21dbe4..8a240de2 100644 --- a/src-network-providers/networkProvider/interface.ts +++ b/src-network-providers/networkProvider/interface.ts @@ -12,7 +12,6 @@ import { Signature } from "../signature"; import { Query, ReturnCode } from "../smartcontracts"; import { Stats } from "../stats"; import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; -import { TransactionLogs } from "../transactionLogs"; import { TransactionPayload } from "../transactionPayload"; /** @@ -168,6 +167,7 @@ export interface IDefinitionOfTokenCollectionOnNetwork { export interface ITransactionOnNetwork { hash: TransactionHash; + type: string; nonce: Nonce; round: number; epoch: number; @@ -181,10 +181,25 @@ export interface ITransactionOnNetwork { status: TransactionStatus; timestamp: number; blockNonce: Nonce; + // Not available on API. hyperblockNonce: Nonce; + // Not available on API. hyperblockHash: Hash; - logs: TransactionLogs; + // Not available on Gateway. + pendingResults: boolean; + receipt: ITransactionReceipt; contractResults: IContractResults; + logs: ITransactionLogs; + + isCompleted(): boolean; + getAllEvents(): ITransactionEvent[]; +} + +export interface ITransactionReceipt { + value: Balance; + sender: Address; + data: string; + hash: TransactionHash; } export interface IContractResults { @@ -198,12 +213,38 @@ export interface IContractResultItem { receiver: Address; sender: Address; data: string; + returnMessage: string; previousHash: Hash; originalHash: Hash; gasLimit: GasLimit; gasPrice: GasPrice; callType: number; - returnMessage: string; + logs: ITransactionLogs; +} + +export interface ITransactionLogs { + address: Address; + events: ITransactionEvent[]; + + findSingleOrNoneEvent(identifier: string, predicate?: (event: ITransactionEvent) => boolean): ITransactionEvent | undefined; + findFirstOrNoneEvent(identifier: string, predicate?: (event: ITransactionEvent) => boolean): ITransactionEvent | undefined; + findEvents(identifier: string, predicate?: (event: ITransactionEvent) => boolean): ITransactionEvent[]; +} + +export interface ITransactionEvent { + readonly address: Address; + readonly identifier: string; + readonly topics: ITransactionEventTopic[]; + readonly data: string; + + findFirstOrNoneTopic(predicate: (topic: ITransactionEventTopic) => boolean): ITransactionEventTopic | undefined; + getLastTopic(): ITransactionEventTopic; +} + +export interface ITransactionEventTopic { + toString(): string; + hex(): string; + valueOf(): Buffer; } export interface IContractQueryResponse { diff --git a/src-network-providers/networkProvider/receipt.ts b/src-network-providers/networkProvider/receipt.ts new file mode 100644 index 00000000..64b45c96 --- /dev/null +++ b/src-network-providers/networkProvider/receipt.ts @@ -0,0 +1,26 @@ +import { Address } from "../address"; +import { Balance } from "../balance"; +import { TransactionHash } from "../transaction"; + +export class Receipt { + value: Balance = Balance.Zero(); + sender: Address = new Address(); + data: string = ""; + hash: TransactionHash = TransactionHash.empty(); + + static fromHttpResponse(response: { + value: string, + sender: string, + data: string, + txHash: string + }): Receipt { + let receipt = new Receipt(); + + receipt.value = Balance.fromString(response.value); + receipt.sender = new Address(response.sender); + receipt.data = response.data; + receipt.hash = new TransactionHash(response.txHash); + + return receipt; + } +} diff --git a/src-network-providers/networkProvider/transactionCompletionStrategy.ts b/src-network-providers/networkProvider/transactionCompletionStrategy.ts new file mode 100644 index 00000000..2a50bdd1 --- /dev/null +++ b/src-network-providers/networkProvider/transactionCompletionStrategy.ts @@ -0,0 +1,68 @@ +import { ITransactionLogs } from "./interface"; +import { Nonce } from "../nonce"; +import { TransactionStatus } from "../transaction"; +import { TransactionPayload } from "../transactionPayload"; +import { isPaddedHex } from "../utils.codec"; + +/** + * Internal interface: a transaction, as seen from the perspective of a {@link TransactionCompletionStrategy}. + */ +interface ITransactionOnNetwork { + logs: ITransactionLogs; + status: TransactionStatus; + hyperblockNonce: Nonce; + data: TransactionPayload; +} + +const WellKnownCompletionEvents = ["completedTxEvent", "SCDeploy", "signalError"]; + +/** + * Algorithm for detecting transaction completion. + * Based on some heuristics (a bit imprecise therefore, at this moment). + */ +export class TransactionCompletionStrategy { + isCompleted(transaction: ITransactionOnNetwork): boolean { + if (transaction.status.isPending()) { + // Certainly not completed. + return false; + } + + // Handle gateway mechanics: + for (const completionEvent of WellKnownCompletionEvents) { + if (transaction.logs.findFirstOrNoneEvent(completionEvent)) { + // Certainly completed. + console.debug("TransactionCompletionStrategy.isCompleted(), found event:", completionEvent); + return true; + } + } + + if (this.isCertainlyMoveBalance(transaction.data.toString())) { + return transaction.status.isExecuted(); + } + + let hyperblockNonce = transaction.hyperblockNonce.valueOf(); + + // Imprecise condition, uncertain completion (usually sufficient, though). + // This is WRONG when (at least): timeOf(block with execution at destination is notarized) < timeOf(the "completedTxEvent" occurs). + if (hyperblockNonce > 0) { + console.debug("TransactionCompletionStrategy.isCompleted(), found hyperblock nonce:", hyperblockNonce); + return true; + } + + return false; + } + + private isCertainlyMoveBalance(transactionData: string): boolean { + let parts = transactionData.split("@"); + let prefix = parts[0]; + let otherParts = parts.slice(1); + let emptyPrefix = !prefix; + let somePartsAreNotValidArguments = !otherParts.every(this.looksLikeValidArgument); + + return emptyPrefix || somePartsAreNotValidArguments; + } + + private looksLikeValidArgument(arg: string) { + return isPaddedHex(arg); + } +} diff --git a/src-network-providers/networkProvider/transactionEvents.ts b/src-network-providers/networkProvider/transactionEvents.ts new file mode 100644 index 00000000..5fb723ac --- /dev/null +++ b/src-network-providers/networkProvider/transactionEvents.ts @@ -0,0 +1,58 @@ +import { Address } from "../address"; +import { ITransactionEventTopic } from "./interface"; + +export class TransactionEvent { + readonly address: Address; + readonly identifier: string; + readonly topics: ITransactionEventTopic[]; + readonly data: string; + + constructor(address: Address, identifier: string, topics: ITransactionEventTopic[], data: string) { + this.address = address; + this.identifier = identifier; + this.topics = topics; + this.data = data; + } + + static fromHttpResponse(responsePart: { + address: string, + identifier: string, + topics: string[], + data: string + }): TransactionEvent { + let topics = (responsePart.topics || []).map(topic => new TransactionEventTopic(topic)); + let address = new Address(responsePart.address); + let identifier = responsePart.identifier || ""; + let data = Buffer.from(responsePart.data || "", "base64").toString(); + let event = new TransactionEvent(address, identifier, topics, data); + return event; + } + + findFirstOrNoneTopic(predicate: (topic: ITransactionEventTopic) => boolean): ITransactionEventTopic | undefined { + return this.topics.filter(topic => predicate(topic))[0]; + } + + getLastTopic(): ITransactionEventTopic { + return this.topics[this.topics.length - 1]; + } +} + +export class TransactionEventTopic { + private readonly raw: Buffer; + + constructor(topic: string) { + this.raw = Buffer.from(topic || "", "base64"); + } + + toString(): string { + return this.raw.toString("utf8"); + } + + hex(): string { + return this.raw.toString("hex"); + } + + valueOf(): Buffer { + return this.raw; + } +} diff --git a/src-network-providers/networkProvider/transactionLogs.ts b/src-network-providers/networkProvider/transactionLogs.ts new file mode 100644 index 00000000..21be82b4 --- /dev/null +++ b/src-network-providers/networkProvider/transactionLogs.ts @@ -0,0 +1,47 @@ +import { Address } from "../address"; +import { ErrUnexpectedCondition } from "../errors"; +import { TransactionEvent } from "./transactionEvents"; + +export class TransactionLogs { + readonly address: Address; + readonly events: TransactionEvent[]; + + constructor(address: Address, events: TransactionEvent[]) { + this.address = address; + this.events = events; + } + + static empty(): TransactionLogs { + return new TransactionLogs(new Address(), []); + } + + static fromHttpResponse(logs: any): TransactionLogs { + let address = new Address(logs.address); + let events = (logs.events || []).map((event: any) => TransactionEvent.fromHttpResponse(event)); + return new TransactionLogs(address, events); + } + + findSingleOrNoneEvent(identifier: string, predicate?: (event: TransactionEvent) => boolean): TransactionEvent | undefined { + let events = this.findEvents(identifier, predicate); + + if (events.length > 1) { + throw new ErrUnexpectedCondition(`more than one event of type ${identifier}`); + } + + return events[0]; + } + + findFirstOrNoneEvent(identifier: string, predicate?: (event: TransactionEvent) => boolean): TransactionEvent | undefined { + return this.findEvents(identifier, predicate)[0]; + } + + findEvents(identifier: string, predicate?: (event: TransactionEvent) => boolean): TransactionEvent[] { + let events = this.events.filter(event => event.identifier == identifier); + + if (predicate) { + events = events.filter(event => predicate(event)); + } + + return events; + } +} diff --git a/src-network-providers/networkProvider/transactions.ts b/src-network-providers/networkProvider/transactions.ts index 6fd3c906..94bdd060 100644 --- a/src-network-providers/networkProvider/transactions.ts +++ b/src-network-providers/networkProvider/transactions.ts @@ -1,17 +1,20 @@ import { Address } from "../address"; import { Balance } from "../balance"; import { Hash } from "../hash"; -import { IContractResults, ITransactionOnNetwork } from "./interface"; +import { IContractResults, ITransactionEvent, ITransactionLogs, ITransactionOnNetwork, ITransactionReceipt } from "./interface"; import { GasLimit, GasPrice } from "../networkParams"; import { Nonce } from "../nonce"; import { Signature } from "../signature"; import { TransactionHash, TransactionStatus } from "../transaction"; -import { TransactionLogs } from "../transactionLogs"; import { TransactionPayload } from "../transactionPayload"; import { ContractResults } from "./contractResults"; +import { TransactionCompletionStrategy } from "./transactionCompletionStrategy"; +import { TransactionLogs } from "./transactionLogs"; +import { Receipt } from "./receipt"; export class TransactionOnNetwork implements ITransactionOnNetwork { hash: TransactionHash = new TransactionHash(""); + type: string = ""; nonce: Nonce = new Nonce(0); round: number = 0; epoch: number = 0; @@ -28,21 +31,29 @@ import { ContractResults } from "./contractResults"; blockNonce: Nonce = new Nonce(0); hyperblockNonce: Nonce = new Nonce(0); hyperblockHash: Hash = Hash.empty(); + pendingResults: boolean = false; - logs: TransactionLogs = TransactionLogs.empty(); + receipt: ITransactionReceipt = new Receipt(); contractResults: IContractResults = ContractResults.empty(); + logs: ITransactionLogs = TransactionLogs.empty(); + + constructor(init?: Partial) { + Object.assign(this, init); + } static fromProxyHttpResponse(txHash: TransactionHash, response: any): TransactionOnNetwork { let result = TransactionOnNetwork.fromHttpResponse(txHash, response); result.contractResults = ContractResults.fromProxyHttpResponse(response.smartContractResults || []); - // TODO: uniformize transaction status + // TODO: uniformize transaction status. + // TODO: Use specific completion detection strategy. return result; } static fromApiHttpResponse(txHash: TransactionHash, response: any): TransactionOnNetwork { let result = TransactionOnNetwork.fromHttpResponse(txHash, response); result.contractResults = ContractResults.fromApiHttpResponse(response.results || []); - // TODO: uniformize transaction status + // TODO: uniformize transaction status. + // TODO: Use specific completion detection strategy. return result; } @@ -50,6 +61,7 @@ import { ContractResults } from "./contractResults"; let result = new TransactionOnNetwork(); result.hash = txHash; + result.type = response.type || ""; result.nonce = new Nonce(response.nonce || 0); result.round = response.round; result.epoch = response.epoch || 0; @@ -65,7 +77,9 @@ import { ContractResults } from "./contractResults"; result.blockNonce = new Nonce(response.blockNonce || 0); result.hyperblockNonce = new Nonce(response.hyperblockNonce || 0); result.hyperblockHash = new Hash(response.hyperblockHash); + result.pendingResults = response.pendingResults || false; + result.receipt = Receipt.fromHttpResponse(response.receipt || {}); result.logs = TransactionLogs.fromHttpResponse(response.logs || {}); return result; @@ -74,5 +88,21 @@ import { ContractResults } from "./contractResults"; getDateTime(): Date { return new Date(this.timestamp * 1000); } + + isCompleted(): boolean { + // TODO: When using separate constructors of TransactionOnNetwork (for API response vs. for Gateway response, see package "networkProvider"), + // we will be able to use different transaction completion strategies. + return new TransactionCompletionStrategy().isCompleted(this); + } + + getAllEvents(): ITransactionEvent[] { + let result = [...this.logs.events]; + + for (const resultItem of this.contractResults.items) { + result.push(...resultItem.logs.events); + } + + return result; + } } From 49f2cdc016c21402d6f93c78942b97ca199bb44e Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 5 Apr 2022 18:11:39 +0300 Subject: [PATCH 018/133] Fix circular dependency. --- src-network-providers/networkProvider/contractResults.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src-network-providers/networkProvider/contractResults.ts b/src-network-providers/networkProvider/contractResults.ts index 0defc915..e1a1acda 100644 --- a/src-network-providers/networkProvider/contractResults.ts +++ b/src-network-providers/networkProvider/contractResults.ts @@ -5,9 +5,10 @@ import { Hash } from "../hash"; import { IContractQueryResponse, IContractResultItem, IContractResults, ITransactionLogs } from "./interface"; import { GasLimit, GasPrice } from "../networkParams"; import { Nonce } from "../nonce"; -import { MaxUint64, ReturnCode } from "../smartcontracts"; import { TransactionHash } from "../transaction"; import { TransactionLogs } from "./transactionLogs"; +import { ReturnCode } from "../smartcontracts/returnCode"; +import { MaxUint64 } from "../smartcontracts/query"; export class ContractResults implements IContractResults { readonly items: IContractResultItem[]; From 6da4cfcad1b5c0c9f75e7460b78f51d28cb13fbe Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 5 Apr 2022 20:12:17 +0300 Subject: [PATCH 019/133] Move interfaces to where they are used. --- .../networkProvider/apiNetworkProvider.ts | 4 +- .../networkProvider/contractResults.ts | 17 ++-- .../networkProvider/interface.ts | 91 +------------------ .../networkProvider/providers.dev.net.spec.ts | 5 +- .../networkProvider/proxyNetworkProvider.ts | 4 +- .../transactionCompletionStrategy.ts | 4 +- .../networkProvider/transactionEvents.ts | 9 +- .../{receipt.ts => transactionReceipt.ts} | 6 +- .../networkProvider/transactions.ts | 16 ++-- 9 files changed, 35 insertions(+), 121 deletions(-) rename src-network-providers/networkProvider/{receipt.ts => transactionReceipt.ts} (85%) diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index 3d809404..6e4e12fb 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -3,7 +3,7 @@ import { AccountOnNetwork } from "../account"; import { Address } from "../address"; import { defaultConfig } from "../constants"; import { ErrNetworkProvider } from "../errors"; -import { IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, Pagination } from "./interface"; +import { IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, Pagination } from "./interface"; import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; @@ -92,7 +92,7 @@ export class ApiNetworkProvider implements INetworkProvider { return tokenData; } - async getTransaction(txHash: TransactionHash): Promise { + async getTransaction(txHash: TransactionHash): Promise { let response = await this.doGetGeneric(`transactions/${txHash.toString()}`); let transaction = TransactionOnNetwork.fromApiHttpResponse(txHash, response); return transaction; diff --git a/src-network-providers/networkProvider/contractResults.ts b/src-network-providers/networkProvider/contractResults.ts index e1a1acda..57c625e4 100644 --- a/src-network-providers/networkProvider/contractResults.ts +++ b/src-network-providers/networkProvider/contractResults.ts @@ -2,7 +2,7 @@ import { BigNumber } from "bignumber.js"; import { Address } from "../address"; import { Balance } from "../balance"; import { Hash } from "../hash"; -import { IContractQueryResponse, IContractResultItem, IContractResults, ITransactionLogs } from "./interface"; +import { IContractQueryResponse } from "./interface"; import { GasLimit, GasPrice } from "../networkParams"; import { Nonce } from "../nonce"; import { TransactionHash } from "../transaction"; @@ -10,13 +10,13 @@ import { TransactionLogs } from "./transactionLogs"; import { ReturnCode } from "../smartcontracts/returnCode"; import { MaxUint64 } from "../smartcontracts/query"; -export class ContractResults implements IContractResults { - readonly items: IContractResultItem[]; +export class ContractResults { + readonly items: ContractResultItem[]; - constructor(items: IContractResultItem[]) { + constructor(items: ContractResultItem[]) { this.items = items; - this.items.sort(function (a: IContractResultItem, b: IContractResultItem) { + this.items.sort(function (a: ContractResultItem, b: ContractResultItem) { return a.nonce.valueOf() - b.nonce.valueOf(); }); } @@ -36,7 +36,7 @@ export class ContractResults implements IContractResults { } } -export class ContractResultItem implements IContractResultItem { +export class ContractResultItem { hash: Hash = Hash.empty(); nonce: Nonce = new Nonce(0); value: Balance = Balance.Zero(); @@ -49,13 +49,12 @@ export class ContractResultItem implements IContractResultItem { gasPrice: GasPrice = new GasPrice(0); callType: number = 0; returnMessage: string = ""; - logs: ITransactionLogs = TransactionLogs.empty(); + logs: TransactionLogs = TransactionLogs.empty(); - constructor(init?: Partial) { + constructor(init?: Partial) { Object.assign(this, init); } - static fromProxyHttpResponse(response: any): ContractResultItem { let item = ContractResultItem.fromHttpResponse(response); return item; diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/networkProvider/interface.ts index 8a240de2..6d2e0bf6 100644 --- a/src-network-providers/networkProvider/interface.ts +++ b/src-network-providers/networkProvider/interface.ts @@ -1,18 +1,15 @@ import { BigNumber } from "bignumber.js"; import { AccountOnNetwork } from "../account"; import { Address } from "../address"; -import { Balance } from "../balance"; -import { Hash } from "../hash"; import { NetworkConfig } from "../networkConfig"; -import { GasLimit, GasPrice } from "../networkParams"; +import { GasLimit } from "../networkParams"; import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; import { Nonce } from "../nonce"; -import { Signature } from "../signature"; import { Query, ReturnCode } from "../smartcontracts"; import { Stats } from "../stats"; import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; -import { TransactionPayload } from "../transactionPayload"; +import { TransactionOnNetwork } from "./transactions"; /** * An interface that defines the endpoints of an HTTP API Provider. @@ -66,7 +63,7 @@ export interface INetworkProvider { /** * Fetches the state of a {@link Transaction}. */ - getTransaction(txHash: TransactionHash): Promise; + getTransaction(txHash: TransactionHash): Promise; /** * Queries the status of a {@link Transaction}. @@ -165,88 +162,6 @@ export interface IDefinitionOfTokenCollectionOnNetwork { // TODO: add "assets", "roles" } -export interface ITransactionOnNetwork { - hash: TransactionHash; - type: string; - nonce: Nonce; - round: number; - epoch: number; - value: Balance; - receiver: Address; - sender: Address; - gasPrice: GasPrice; - gasLimit: GasLimit; - data: TransactionPayload; - signature: Signature; - status: TransactionStatus; - timestamp: number; - blockNonce: Nonce; - // Not available on API. - hyperblockNonce: Nonce; - // Not available on API. - hyperblockHash: Hash; - // Not available on Gateway. - pendingResults: boolean; - receipt: ITransactionReceipt; - contractResults: IContractResults; - logs: ITransactionLogs; - - isCompleted(): boolean; - getAllEvents(): ITransactionEvent[]; -} - -export interface ITransactionReceipt { - value: Balance; - sender: Address; - data: string; - hash: TransactionHash; -} - -export interface IContractResults { - items: IContractResultItem[]; -} - -export interface IContractResultItem { - hash: Hash; - nonce: Nonce; - value: Balance; - receiver: Address; - sender: Address; - data: string; - returnMessage: string; - previousHash: Hash; - originalHash: Hash; - gasLimit: GasLimit; - gasPrice: GasPrice; - callType: number; - logs: ITransactionLogs; -} - -export interface ITransactionLogs { - address: Address; - events: ITransactionEvent[]; - - findSingleOrNoneEvent(identifier: string, predicate?: (event: ITransactionEvent) => boolean): ITransactionEvent | undefined; - findFirstOrNoneEvent(identifier: string, predicate?: (event: ITransactionEvent) => boolean): ITransactionEvent | undefined; - findEvents(identifier: string, predicate?: (event: ITransactionEvent) => boolean): ITransactionEvent[]; -} - -export interface ITransactionEvent { - readonly address: Address; - readonly identifier: string; - readonly topics: ITransactionEventTopic[]; - readonly data: string; - - findFirstOrNoneTopic(predicate: (topic: ITransactionEventTopic) => boolean): ITransactionEventTopic | undefined; - getLastTopic(): ITransactionEventTopic; -} - -export interface ITransactionEventTopic { - toString(): string; - hex(): string; - valueOf(): Buffer; -} - export interface IContractQueryResponse { returnData: string[]; returnCode: ReturnCode; diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts index affbd8d0..f376feed 100644 --- a/src-network-providers/networkProvider/providers.dev.net.spec.ts +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -1,6 +1,6 @@ import { assert } from "chai"; import { Hash } from "../hash"; -import { INetworkProvider, ITransactionOnNetwork } from "./interface"; +import { INetworkProvider } from "./interface"; import { Address } from "../address"; import { loadTestWallets, TestWallet } from "../testutils"; import { TransactionHash, TransactionStatus } from "../transaction"; @@ -11,6 +11,7 @@ import { BigNumber } from "bignumber.js"; import { Balance } from "../balance"; import { ApiNetworkProvider } from "./apiNetworkProvider"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; +import { TransactionOnNetwork } from "./transactions"; describe("test network providers on devnet: Proxy and API", function () { let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 10000 }); @@ -127,7 +128,7 @@ describe("test network providers on devnet: Proxy and API", function () { }); // TODO: Strive to have as little differences as possible between Proxy and API. - function ignoreKnownTransactionDifferencesBetweenProviders(apiResponse: ITransactionOnNetwork, proxyResponse: ITransactionOnNetwork) { + function ignoreKnownTransactionDifferencesBetweenProviders(apiResponse: TransactionOnNetwork, proxyResponse: TransactionOnNetwork) { // TODO: Remove this once "tx.status" is uniformized. apiResponse.status = proxyResponse.status = new TransactionStatus("ignore"); diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index 57f5b238..54e5ee85 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -3,7 +3,7 @@ import { AccountOnNetwork } from "../account"; import { Address } from "../address"; import { defaultConfig } from "../constants"; import { ErrNetworkProvider } from "../errors"; -import { IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, Pagination } from "./interface"; +import { IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, Pagination } from "./interface"; import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; @@ -94,7 +94,7 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokenData; } - async getTransaction(txHash: TransactionHash): Promise { + async getTransaction(txHash: TransactionHash): Promise { let url = this.buildUrlWithQueryParameters(`transaction/${txHash.toString()}`, { withResults: "true" }); let response = await this.doGetGeneric(url); let transaction = TransactionOnNetwork.fromProxyHttpResponse(txHash, response.transaction); diff --git a/src-network-providers/networkProvider/transactionCompletionStrategy.ts b/src-network-providers/networkProvider/transactionCompletionStrategy.ts index 2a50bdd1..e95673b7 100644 --- a/src-network-providers/networkProvider/transactionCompletionStrategy.ts +++ b/src-network-providers/networkProvider/transactionCompletionStrategy.ts @@ -1,14 +1,14 @@ -import { ITransactionLogs } from "./interface"; import { Nonce } from "../nonce"; import { TransactionStatus } from "../transaction"; import { TransactionPayload } from "../transactionPayload"; import { isPaddedHex } from "../utils.codec"; +import { TransactionLogs } from "./transactionLogs"; /** * Internal interface: a transaction, as seen from the perspective of a {@link TransactionCompletionStrategy}. */ interface ITransactionOnNetwork { - logs: ITransactionLogs; + logs: TransactionLogs; status: TransactionStatus; hyperblockNonce: Nonce; data: TransactionPayload; diff --git a/src-network-providers/networkProvider/transactionEvents.ts b/src-network-providers/networkProvider/transactionEvents.ts index 5fb723ac..60c8e75b 100644 --- a/src-network-providers/networkProvider/transactionEvents.ts +++ b/src-network-providers/networkProvider/transactionEvents.ts @@ -1,13 +1,12 @@ import { Address } from "../address"; -import { ITransactionEventTopic } from "./interface"; export class TransactionEvent { readonly address: Address; readonly identifier: string; - readonly topics: ITransactionEventTopic[]; + readonly topics: TransactionEventTopic[]; readonly data: string; - constructor(address: Address, identifier: string, topics: ITransactionEventTopic[], data: string) { + constructor(address: Address, identifier: string, topics: TransactionEventTopic[], data: string) { this.address = address; this.identifier = identifier; this.topics = topics; @@ -28,11 +27,11 @@ export class TransactionEvent { return event; } - findFirstOrNoneTopic(predicate: (topic: ITransactionEventTopic) => boolean): ITransactionEventTopic | undefined { + findFirstOrNoneTopic(predicate: (topic: TransactionEventTopic) => boolean): TransactionEventTopic | undefined { return this.topics.filter(topic => predicate(topic))[0]; } - getLastTopic(): ITransactionEventTopic { + getLastTopic(): TransactionEventTopic { return this.topics[this.topics.length - 1]; } } diff --git a/src-network-providers/networkProvider/receipt.ts b/src-network-providers/networkProvider/transactionReceipt.ts similarity index 85% rename from src-network-providers/networkProvider/receipt.ts rename to src-network-providers/networkProvider/transactionReceipt.ts index 64b45c96..8a6e6ec2 100644 --- a/src-network-providers/networkProvider/receipt.ts +++ b/src-network-providers/networkProvider/transactionReceipt.ts @@ -2,7 +2,7 @@ import { Address } from "../address"; import { Balance } from "../balance"; import { TransactionHash } from "../transaction"; -export class Receipt { +export class TransactionReceipt { value: Balance = Balance.Zero(); sender: Address = new Address(); data: string = ""; @@ -13,8 +13,8 @@ export class Receipt { sender: string, data: string, txHash: string - }): Receipt { - let receipt = new Receipt(); + }): TransactionReceipt { + let receipt = new TransactionReceipt(); receipt.value = Balance.fromString(response.value); receipt.sender = new Address(response.sender); diff --git a/src-network-providers/networkProvider/transactions.ts b/src-network-providers/networkProvider/transactions.ts index 94bdd060..840b6725 100644 --- a/src-network-providers/networkProvider/transactions.ts +++ b/src-network-providers/networkProvider/transactions.ts @@ -1,7 +1,6 @@ import { Address } from "../address"; import { Balance } from "../balance"; import { Hash } from "../hash"; -import { IContractResults, ITransactionEvent, ITransactionLogs, ITransactionOnNetwork, ITransactionReceipt } from "./interface"; import { GasLimit, GasPrice } from "../networkParams"; import { Nonce } from "../nonce"; import { Signature } from "../signature"; @@ -9,10 +8,11 @@ import { TransactionHash, TransactionStatus } from "../transaction"; import { TransactionPayload } from "../transactionPayload"; import { ContractResults } from "./contractResults"; import { TransactionCompletionStrategy } from "./transactionCompletionStrategy"; +import { TransactionEvent } from "./transactionEvents"; import { TransactionLogs } from "./transactionLogs"; -import { Receipt } from "./receipt"; +import { TransactionReceipt } from "./transactionReceipt"; - export class TransactionOnNetwork implements ITransactionOnNetwork { + export class TransactionOnNetwork { hash: TransactionHash = new TransactionHash(""); type: string = ""; nonce: Nonce = new Nonce(0); @@ -33,9 +33,9 @@ import { Receipt } from "./receipt"; hyperblockHash: Hash = Hash.empty(); pendingResults: boolean = false; - receipt: ITransactionReceipt = new Receipt(); - contractResults: IContractResults = ContractResults.empty(); - logs: ITransactionLogs = TransactionLogs.empty(); + receipt: TransactionReceipt = new TransactionReceipt(); + contractResults: ContractResults = ContractResults.empty(); + logs: TransactionLogs = TransactionLogs.empty(); constructor(init?: Partial) { Object.assign(this, init); @@ -79,7 +79,7 @@ import { Receipt } from "./receipt"; result.hyperblockHash = new Hash(response.hyperblockHash); result.pendingResults = response.pendingResults || false; - result.receipt = Receipt.fromHttpResponse(response.receipt || {}); + result.receipt = TransactionReceipt.fromHttpResponse(response.receipt || {}); result.logs = TransactionLogs.fromHttpResponse(response.logs || {}); return result; @@ -95,7 +95,7 @@ import { Receipt } from "./receipt"; return new TransactionCompletionStrategy().isCompleted(this); } - getAllEvents(): ITransactionEvent[] { + getAllEvents(): TransactionEvent[] { let result = [...this.logs.events]; for (const resultItem of this.contractResults.items) { From 5e24e20d29a8cdccb6aa89b66d8f56f49fd5159d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Tue, 5 Apr 2022 20:47:36 +0300 Subject: [PATCH 020/133] Make ./networkProvider less dependent on outside definitions. --- .../networkProvider/providers.dev.net.spec.ts | 7 +++--- .../transactionCompletionStrategy.ts | 5 ++-- .../networkProvider/transactions.ts | 25 ++++++++----------- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts index f376feed..5903b9a3 100644 --- a/src-network-providers/networkProvider/providers.dev.net.spec.ts +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -1,5 +1,4 @@ import { assert } from "chai"; -import { Hash } from "../hash"; import { INetworkProvider } from "./interface"; import { Address } from "../address"; import { loadTestWallets, TestWallet } from "../testutils"; @@ -134,9 +133,9 @@ describe("test network providers on devnet: Proxy and API", function () { // Ignore fields which are not present on API response: proxyResponse.epoch = 0; - proxyResponse.blockNonce = new Nonce(0); - proxyResponse.hyperblockNonce = new Nonce(0); - proxyResponse.hyperblockHash = new Hash(""); + proxyResponse.blockNonce = 0; + proxyResponse.hyperblockNonce = 0; + proxyResponse.hyperblockHash = ""; } // TODO: Fix differences of "tx.status", then enable this test. diff --git a/src-network-providers/networkProvider/transactionCompletionStrategy.ts b/src-network-providers/networkProvider/transactionCompletionStrategy.ts index e95673b7..59823688 100644 --- a/src-network-providers/networkProvider/transactionCompletionStrategy.ts +++ b/src-network-providers/networkProvider/transactionCompletionStrategy.ts @@ -1,4 +1,3 @@ -import { Nonce } from "../nonce"; import { TransactionStatus } from "../transaction"; import { TransactionPayload } from "../transactionPayload"; import { isPaddedHex } from "../utils.codec"; @@ -10,7 +9,7 @@ import { TransactionLogs } from "./transactionLogs"; interface ITransactionOnNetwork { logs: TransactionLogs; status: TransactionStatus; - hyperblockNonce: Nonce; + hyperblockNonce: number; data: TransactionPayload; } @@ -40,7 +39,7 @@ export class TransactionCompletionStrategy { return transaction.status.isExecuted(); } - let hyperblockNonce = transaction.hyperblockNonce.valueOf(); + let hyperblockNonce = transaction.hyperblockNonce; // Imprecise condition, uncertain completion (usually sufficient, though). // This is WRONG when (at least): timeOf(block with execution at destination is notarized) < timeOf(the "completedTxEvent" occurs). diff --git a/src-network-providers/networkProvider/transactions.ts b/src-network-providers/networkProvider/transactions.ts index 840b6725..7298e664 100644 --- a/src-network-providers/networkProvider/transactions.ts +++ b/src-network-providers/networkProvider/transactions.ts @@ -1,9 +1,6 @@ import { Address } from "../address"; import { Balance } from "../balance"; -import { Hash } from "../hash"; -import { GasLimit, GasPrice } from "../networkParams"; import { Nonce } from "../nonce"; -import { Signature } from "../signature"; import { TransactionHash, TransactionStatus } from "../transaction"; import { TransactionPayload } from "../transactionPayload"; import { ContractResults } from "./contractResults"; @@ -21,16 +18,16 @@ import { TransactionReceipt } from "./transactionReceipt"; value: Balance = Balance.Zero(); receiver: Address = new Address(); sender: Address = new Address(); - gasPrice: GasPrice = new GasPrice(0); - gasLimit: GasLimit = new GasLimit(0); + gasPrice: number = 0; + gasLimit: number = 0; data: TransactionPayload = new TransactionPayload(); - signature: Signature = Signature.empty(); + signature: string = ""; status: TransactionStatus = TransactionStatus.createUnknown(); timestamp: number = 0; - blockNonce: Nonce = new Nonce(0); - hyperblockNonce: Nonce = new Nonce(0); - hyperblockHash: Hash = Hash.empty(); + blockNonce: number = 0; + hyperblockNonce: number = 0; + hyperblockHash: string = ""; pendingResults: boolean = false; receipt: TransactionReceipt = new TransactionReceipt(); @@ -68,15 +65,15 @@ import { TransactionReceipt } from "./transactionReceipt"; result.value = Balance.fromString(response.value); result.sender = Address.fromBech32(response.sender); result.receiver = Address.fromBech32(response.receiver); - result.gasPrice = new GasPrice(response.gasPrice); - result.gasLimit = new GasLimit(response.gasLimit); + result.gasPrice = response.gasPrice || 0; + result.gasLimit = response.gasLimit || 0; result.data = TransactionPayload.fromEncoded(response.data); result.status = new TransactionStatus(response.status); result.timestamp = response.timestamp || 0; - result.blockNonce = new Nonce(response.blockNonce || 0); - result.hyperblockNonce = new Nonce(response.hyperblockNonce || 0); - result.hyperblockHash = new Hash(response.hyperblockHash); + result.blockNonce = response.blockNonce || 0; + result.hyperblockNonce = response.hyperblockNonce || 0; + result.hyperblockHash = response.hyperblockHash; result.pendingResults = response.pendingResults || false; result.receipt = TransactionReceipt.fromHttpResponse(response.receipt || {}); From 3c572343f656fbea5726d654da3cae48ee530a46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Tue, 5 Apr 2022 22:26:50 +0300 Subject: [PATCH 021/133] Prepare extraction of networkProvider. WIP. --- .../networkProvider/apiNetworkProvider.ts | 19 ++-- .../networkProvider/interface.ts | 15 +++- .../networkProvider/primitives.ts | 61 +++++++++++++ .../networkProvider/providers.dev.net.spec.ts | 3 +- .../networkProvider/proxyNetworkProvider.ts | 14 +-- .../transactionCompletionStrategy.ts | 6 +- .../networkProvider/transactionStatus.ts | 87 +++++++++++++++++++ .../networkProvider/transactions.ts | 34 ++++---- 8 files changed, 198 insertions(+), 41 deletions(-) create mode 100644 src-network-providers/networkProvider/primitives.ts create mode 100644 src-network-providers/networkProvider/transactionStatus.ts diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index 6e4e12fb..bcca7cce 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -3,20 +3,21 @@ import { AccountOnNetwork } from "../account"; import { Address } from "../address"; import { defaultConfig } from "../constants"; import { ErrNetworkProvider } from "../errors"; -import { IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, Pagination } from "./interface"; +import { IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, IHexable, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, Pagination } from "./interface"; import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; -import { Nonce } from "../nonce"; import { Query } from "../smartcontracts"; import { Stats } from "../stats"; -import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; +import { Transaction } from "../transaction"; import { ContractQueryResponse } from "./contractResults"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; +import { TransactionStatus } from "./transactionStatus"; +import { Hash } from "./primitives"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ApiNetworkProvider implements INetworkProvider { @@ -86,27 +87,27 @@ export class ApiNetworkProvider implements INetworkProvider { return tokenData; } - async getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: Nonce): Promise { + async getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: IHexable): Promise { let response = await this.doGetGeneric(`accounts/${address.bech32()}/nfts/${collection}-${nonce.hex()}`); let tokenData = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response); return tokenData; } - async getTransaction(txHash: TransactionHash): Promise { + async getTransaction(txHash: IHash): Promise { let response = await this.doGetGeneric(`transactions/${txHash.toString()}`); let transaction = TransactionOnNetwork.fromApiHttpResponse(txHash, response); return transaction; } - async getTransactionStatus(txHash: TransactionHash): Promise { + async getTransactionStatus(txHash: IHash): Promise { let response = await this.doGetGeneric(`transactions/${txHash.toString()}?fields=status`); let status = new TransactionStatus(response.status); return status; } - async sendTransaction(tx: Transaction): Promise { + async sendTransaction(tx: Transaction): Promise { let response = await this.doPostGeneric("transactions", tx.toSendable()); - let hash = new TransactionHash(response.txHash); + let hash = new Hash(response.txHash); return hash; } @@ -133,7 +134,7 @@ export class ApiNetworkProvider implements INetworkProvider { return definition; } - async getNonFungibleToken(collection: string, nonce: Nonce): Promise { + async getNonFungibleToken(collection: string, nonce: IHexable): Promise { let response = await this.doGetGeneric(`nfts/${collection}-${nonce.hex()}`); let token = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response); return token; diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/networkProvider/interface.ts index 6d2e0bf6..145a7887 100644 --- a/src-network-providers/networkProvider/interface.ts +++ b/src-network-providers/networkProvider/interface.ts @@ -8,8 +8,9 @@ import { NetworkStatus } from "../networkStatus"; import { Nonce } from "../nonce"; import { Query, ReturnCode } from "../smartcontracts"; import { Stats } from "../stats"; -import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; +import { Transaction } from "../transaction"; import { TransactionOnNetwork } from "./transactions"; +import { TransactionStatus } from "./transactionStatus"; /** * An interface that defines the endpoints of an HTTP API Provider. @@ -63,17 +64,17 @@ export interface INetworkProvider { /** * Fetches the state of a {@link Transaction}. */ - getTransaction(txHash: TransactionHash): Promise; + getTransaction(txHash: IHash): Promise; /** * Queries the status of a {@link Transaction}. */ - getTransactionStatus(txHash: TransactionHash): Promise; + getTransactionStatus(txHash: IHash): Promise; /** * Broadcasts an already-signed {@link Transaction}. */ - sendTransaction(tx: Transaction): Promise; + sendTransaction(tx: Transaction): Promise; /** * Simulates the processing of an already-signed {@link Transaction}. @@ -182,3 +183,9 @@ export class Pagination { return { from: 0, size: 100 }; } } + +export interface IHash { hex(): string; } +export interface IAddress { bech32(): string; } +export interface INonce { valueOf(): number; } +export interface IHexable { hex(): string } +export interface ITransactionPayload { encoded(): string; } diff --git a/src-network-providers/networkProvider/primitives.ts b/src-network-providers/networkProvider/primitives.ts new file mode 100644 index 00000000..1c9bfe0e --- /dev/null +++ b/src-network-providers/networkProvider/primitives.ts @@ -0,0 +1,61 @@ +import { IAddress, IHash, INonce, ITransactionPayload } from "./interface"; + +export class Hash implements IHash { + private readonly value: string; + + constructor(value: string) { + this.value = value; + } + + hex(): string { + return this.value; + } +} + +export class Address implements IAddress { + private readonly value: string; + + constructor(value: string) { + this.value = value; + } + + bech32(): string { + return this.value; + } +} + +export class Nonce implements INonce { + private readonly value: number; + + constructor(value: number) { + this.value = value; + } + + valueOf(): number { + return this.value; + } +} + +export class TransactionValue { + private readonly value: string; + + constructor(value: string) { + this.value = value; + } + + toString(): string { + return this.value; + } +} + +export class TransactionPayload implements ITransactionPayload { + private readonly base64: string; + + constructor(base64: string) { + this.base64 = base64; + } + + encoded(): string { + return this.base64; + } +} diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts index 5903b9a3..479fd40b 100644 --- a/src-network-providers/networkProvider/providers.dev.net.spec.ts +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -2,7 +2,7 @@ import { assert } from "chai"; import { INetworkProvider } from "./interface"; import { Address } from "../address"; import { loadTestWallets, TestWallet } from "../testutils"; -import { TransactionHash, TransactionStatus } from "../transaction"; +import { TransactionHash } from "../transaction"; import { Nonce } from "../nonce"; import { ContractFunction, Query } from "../smartcontracts"; import { BigUIntValue, U32Value, BytesValue, VariadicValue, VariadicType, CompositeType, BytesType, BooleanType } from "../smartcontracts/typesystem"; @@ -11,6 +11,7 @@ import { Balance } from "../balance"; import { ApiNetworkProvider } from "./apiNetworkProvider"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { TransactionOnNetwork } from "./transactions"; +import { TransactionStatus } from "./transactionStatus"; describe("test network providers on devnet: Proxy and API", function () { let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 10000 }); diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index 54e5ee85..2a0786a2 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -3,7 +3,7 @@ import { AccountOnNetwork } from "../account"; import { Address } from "../address"; import { defaultConfig } from "../constants"; import { ErrNetworkProvider } from "../errors"; -import { IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, Pagination } from "./interface"; +import { IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, Pagination } from "./interface"; import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; @@ -11,10 +11,12 @@ import { NetworkStatus } from "../networkStatus"; import { Nonce } from "../nonce"; import { Query } from "../smartcontracts"; import { Stats } from "../stats"; -import { Transaction, TransactionHash, TransactionStatus } from "../transaction"; +import { Transaction } from "../transaction"; import { ContractQueryResponse } from "./contractResults"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; +import { TransactionStatus } from "./transactionStatus"; +import { Hash } from "./primitives"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ProxyNetworkProvider implements INetworkProvider { @@ -94,22 +96,22 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokenData; } - async getTransaction(txHash: TransactionHash): Promise { + async getTransaction(txHash: IHash): Promise { let url = this.buildUrlWithQueryParameters(`transaction/${txHash.toString()}`, { withResults: "true" }); let response = await this.doGetGeneric(url); let transaction = TransactionOnNetwork.fromProxyHttpResponse(txHash, response.transaction); return transaction; } - async getTransactionStatus(txHash: TransactionHash): Promise { + async getTransactionStatus(txHash: IHash): Promise { let response = await this.doGetGeneric(`transaction/${txHash.toString()}/status`); let status = new TransactionStatus(response.status); return status; } - async sendTransaction(tx: Transaction): Promise { + async sendTransaction(tx: Transaction): Promise { let response = await this.doPostGeneric("transaction/send", tx.toSendable()); - let hash = new TransactionHash(response.txHash); + let hash = new Hash(response.txHash); return hash; } diff --git a/src-network-providers/networkProvider/transactionCompletionStrategy.ts b/src-network-providers/networkProvider/transactionCompletionStrategy.ts index 59823688..afdff564 100644 --- a/src-network-providers/networkProvider/transactionCompletionStrategy.ts +++ b/src-network-providers/networkProvider/transactionCompletionStrategy.ts @@ -1,6 +1,6 @@ -import { TransactionStatus } from "../transaction"; -import { TransactionPayload } from "../transactionPayload"; +import { TransactionStatus } from "./transactionStatus"; import { isPaddedHex } from "../utils.codec"; +import { ITransactionPayload } from "./interface"; import { TransactionLogs } from "./transactionLogs"; /** @@ -10,7 +10,7 @@ interface ITransactionOnNetwork { logs: TransactionLogs; status: TransactionStatus; hyperblockNonce: number; - data: TransactionPayload; + data: ITransactionPayload; } const WellKnownCompletionEvents = ["completedTxEvent", "SCDeploy", "signalError"]; diff --git a/src-network-providers/networkProvider/transactionStatus.ts b/src-network-providers/networkProvider/transactionStatus.ts new file mode 100644 index 00000000..e7346cf8 --- /dev/null +++ b/src-network-providers/networkProvider/transactionStatus.ts @@ -0,0 +1,87 @@ +/** + * An abstraction for handling and interpreting the "status" field of a transaction. + */ +export class TransactionStatus { + /** + * The raw status, as fetched from the Network. + */ + readonly status: string; + + /** + * Creates a new TransactionStatus object. + */ + constructor(status: string) { + this.status = (status || "").toLowerCase(); + } + + /** + * Creates an unknown status. + */ + static createUnknown(): TransactionStatus { + return new TransactionStatus("unknown"); + } + + /** + * Returns whether the transaction is pending (e.g. in mempool). + */ + isPending(): boolean { + return ( + this.status == "received" || + this.status == "pending" || + this.status == "partially-executed" + ); + } + + /** + * Returns whether the transaction has been executed (not necessarily with success). + */ + isExecuted(): boolean { + return this.isSuccessful() || this.isFailed() || this.isInvalid(); + } + + /** + * Returns whether the transaction has been executed successfully. + */ + isSuccessful(): boolean { + return ( + this.status == "executed" || + this.status == "success" || + this.status == "successful" + ); + } + + /** + * Returns whether the transaction has been executed, but with a failure. + */ + isFailed(): boolean { + return ( + this.status == "fail" || + this.status == "failed" || + this.status == "unsuccessful" || + this.isInvalid() + ); + } + + /** + * Returns whether the transaction has been executed, but marked as invalid (e.g. due to "insufficient funds"). + */ + isInvalid(): boolean { + return this.status == "invalid"; + } + + toString(): string { + return this.status; + } + + valueOf(): string { + return this.status; + } + + equals(other: TransactionStatus) { + if (!other) { + return false; + } + + return this.status == other.status; + } +} diff --git a/src-network-providers/networkProvider/transactions.ts b/src-network-providers/networkProvider/transactions.ts index 7298e664..60d73e6e 100644 --- a/src-network-providers/networkProvider/transactions.ts +++ b/src-network-providers/networkProvider/transactions.ts @@ -1,26 +1,24 @@ -import { Address } from "../address"; -import { Balance } from "../balance"; -import { Nonce } from "../nonce"; -import { TransactionHash, TransactionStatus } from "../transaction"; -import { TransactionPayload } from "../transactionPayload"; +import { TransactionStatus } from "./transactionStatus"; import { ContractResults } from "./contractResults"; +import { Address, Hash, Nonce, TransactionValue, TransactionPayload } from "./primitives"; +import { IAddress, IHash, INonce, ITransactionPayload } from "./interface"; import { TransactionCompletionStrategy } from "./transactionCompletionStrategy"; import { TransactionEvent } from "./transactionEvents"; import { TransactionLogs } from "./transactionLogs"; import { TransactionReceipt } from "./transactionReceipt"; export class TransactionOnNetwork { - hash: TransactionHash = new TransactionHash(""); + hash: IHash = new Hash(""); type: string = ""; - nonce: Nonce = new Nonce(0); + nonce: INonce = new Nonce(0); round: number = 0; epoch: number = 0; - value: Balance = Balance.Zero(); - receiver: Address = new Address(); - sender: Address = new Address(); + value: TransactionValue = new TransactionValue(""); + receiver: IAddress = new Address(""); + sender: IAddress = new Address(""); gasPrice: number = 0; gasLimit: number = 0; - data: TransactionPayload = new TransactionPayload(); + data: ITransactionPayload = new TransactionPayload(""); signature: string = ""; status: TransactionStatus = TransactionStatus.createUnknown(); timestamp: number = 0; @@ -38,7 +36,7 @@ import { TransactionReceipt } from "./transactionReceipt"; Object.assign(this, init); } - static fromProxyHttpResponse(txHash: TransactionHash, response: any): TransactionOnNetwork { + static fromProxyHttpResponse(txHash: IHash, response: any): TransactionOnNetwork { let result = TransactionOnNetwork.fromHttpResponse(txHash, response); result.contractResults = ContractResults.fromProxyHttpResponse(response.smartContractResults || []); // TODO: uniformize transaction status. @@ -46,7 +44,7 @@ import { TransactionReceipt } from "./transactionReceipt"; return result; } - static fromApiHttpResponse(txHash: TransactionHash, response: any): TransactionOnNetwork { + static fromApiHttpResponse(txHash: IHash, response: any): TransactionOnNetwork { let result = TransactionOnNetwork.fromHttpResponse(txHash, response); result.contractResults = ContractResults.fromApiHttpResponse(response.results || []); // TODO: uniformize transaction status. @@ -54,7 +52,7 @@ import { TransactionReceipt } from "./transactionReceipt"; return result; } - private static fromHttpResponse(txHash: TransactionHash, response: any): TransactionOnNetwork { + private static fromHttpResponse(txHash: IHash, response: any): TransactionOnNetwork { let result = new TransactionOnNetwork(); result.hash = txHash; @@ -62,12 +60,12 @@ import { TransactionReceipt } from "./transactionReceipt"; result.nonce = new Nonce(response.nonce || 0); result.round = response.round; result.epoch = response.epoch || 0; - result.value = Balance.fromString(response.value); - result.sender = Address.fromBech32(response.sender); - result.receiver = Address.fromBech32(response.receiver); + result.value = new TransactionValue(response.value); + result.sender = new Address(response.sender); + result.receiver = new Address(response.receiver); result.gasPrice = response.gasPrice || 0; result.gasLimit = response.gasLimit || 0; - result.data = TransactionPayload.fromEncoded(response.data); + result.data = new TransactionPayload(response.data); result.status = new TransactionStatus(response.status); result.timestamp = response.timestamp || 0; From 3041339c8e5a215353fdc449d645d27141b47eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Tue, 5 Apr 2022 22:51:49 +0300 Subject: [PATCH 022/133] Continue decoupling of package networkProvider. --- .../networkProvider/apiNetworkProvider.ts | 17 +++++------ .../networkProvider/errors.ts | 30 +++++++++++++++++++ .../networkProvider/interface.ts | 30 +++++++++---------- .../networkProvider/primitives.ts | 25 ++++++++++++++++ .../networkProvider/proxyNetworkProvider.ts | 18 +++++------ .../networkProvider/tokenDefinitions.ts | 8 ++--- .../networkProvider/tokens.ts | 9 +++--- .../transactionCompletionStrategy.ts | 4 +-- .../networkProvider/transactionEvents.ts | 7 +++-- .../networkProvider/transactionLogs.ts | 11 +++---- .../networkProvider/transactionReceipt.ts | 15 +++++----- 11 files changed, 112 insertions(+), 62 deletions(-) create mode 100644 src-network-providers/networkProvider/errors.ts diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index bcca7cce..57a65d5c 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -1,9 +1,7 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "../account"; -import { Address } from "../address"; import { defaultConfig } from "../constants"; -import { ErrNetworkProvider } from "../errors"; -import { IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, IHexable, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, Pagination } from "./interface"; +import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, Pagination } from "./interface"; import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; @@ -18,6 +16,7 @@ import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } f import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { Hash } from "./primitives"; +import { ErrNetworkProvider } from "./errors"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ApiNetworkProvider implements INetworkProvider { @@ -51,13 +50,13 @@ export class ApiNetworkProvider implements INetworkProvider { return stats; } - async getAccount(address: Address): Promise { + async getAccount(address: IAddress): Promise { let response = await this.doGetGeneric(`accounts/${address.bech32()}`); let account = AccountOnNetwork.fromHttpResponse(response); return account; } - async getFungibleTokensOfAccount(address: Address, pagination?: Pagination): Promise { + async getFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise { pagination = pagination || Pagination.default(); let url = `accounts/${address.bech32()}/tokens?${this.buildPaginationParams(pagination)}`; @@ -69,7 +68,7 @@ export class ApiNetworkProvider implements INetworkProvider { return tokens; } - async getNonFungibleTokensOfAccount(address: Address, pagination?: Pagination): Promise { + async getNonFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise { pagination = pagination || Pagination.default(); let url = `accounts/${address.bech32()}/nfts?${this.buildPaginationParams(pagination)}`; @@ -81,13 +80,13 @@ export class ApiNetworkProvider implements INetworkProvider { return tokens; } - async getFungibleTokenOfAccount(address: Address, tokenIdentifier: string): Promise { + async getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise { let response = await this.doGetGeneric(`accounts/${address.bech32()}/tokens/${tokenIdentifier}`); let tokenData = FungibleTokenOfAccountOnNetwork.fromHttpResponse(response); return tokenData; } - async getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: IHexable): Promise { + async getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: INonce): Promise { let response = await this.doGetGeneric(`accounts/${address.bech32()}/nfts/${collection}-${nonce.hex()}`); let tokenData = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response); return tokenData; @@ -134,7 +133,7 @@ export class ApiNetworkProvider implements INetworkProvider { return definition; } - async getNonFungibleToken(collection: string, nonce: IHexable): Promise { + async getNonFungibleToken(collection: string, nonce: INonce): Promise { let response = await this.doGetGeneric(`nfts/${collection}-${nonce.hex()}`); let token = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response); return token; diff --git a/src-network-providers/networkProvider/errors.ts b/src-network-providers/networkProvider/errors.ts new file mode 100644 index 00000000..586e5cf8 --- /dev/null +++ b/src-network-providers/networkProvider/errors.ts @@ -0,0 +1,30 @@ +/** + * The base class for exceptions (errors). + */ +export class Err extends Error { + inner: Error | undefined = undefined; + + public constructor(message: string, inner?: Error) { + super(message); + this.inner = inner; + } +} + +/** + * Signals an unexpected condition. + */ +export class ErrUnexpectedCondition extends Err { + public constructor(message: string) { + super(`Unexpected condition: [${message}]`); + } +} + +/** + * Signals an error that happened during a request against the Network. + */ +export class ErrNetworkProvider extends Err { + public constructor(url: string, error: string, inner?: Error) { + let message = `Request error on url [${url}]: [${error}]`; + super(message, inner); + } +} diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/networkProvider/interface.ts index 145a7887..0b822b68 100644 --- a/src-network-providers/networkProvider/interface.ts +++ b/src-network-providers/networkProvider/interface.ts @@ -1,11 +1,9 @@ import { BigNumber } from "bignumber.js"; import { AccountOnNetwork } from "../account"; -import { Address } from "../address"; import { NetworkConfig } from "../networkConfig"; import { GasLimit } from "../networkParams"; import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; -import { Nonce } from "../nonce"; import { Query, ReturnCode } from "../smartcontracts"; import { Stats } from "../stats"; import { Transaction } from "../transaction"; @@ -39,27 +37,27 @@ export interface INetworkProvider { /** * Fetches the state of an {@link Account}. */ - getAccount(address: Address): Promise; + getAccount(address: IAddress): Promise; /** * Fetches data about the fungible tokens held by an account. */ - getFungibleTokensOfAccount(address: Address, pagination?: Pagination): Promise; + getFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise; /** * Fetches data about the non-fungible tokens held by account. */ - getNonFungibleTokensOfAccount(address: Address, pagination?: Pagination): Promise; + getNonFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise; /** * Fetches data about a specific fungible token held by an account. */ - getFungibleTokenOfAccount(address: Address, tokenIdentifier: string): Promise; + getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise; /** * Fetches data about a specific non-fungible token (instance) held by an account. */ - getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: Nonce): Promise; + getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: INonce): Promise; /** * Fetches the state of a {@link Transaction}. @@ -102,7 +100,7 @@ export interface INetworkProvider { /** * Fetches data about a specific non-fungible token (instance). */ - getNonFungibleToken(collection: string, nonce: Nonce): Promise; + getNonFungibleToken(collection: string, nonce: INonce): Promise; /** * Performs a generic GET action against the provider (useful for new HTTP endpoints, not yet supported by erdjs). @@ -125,8 +123,8 @@ export interface INonFungibleTokenOfAccountOnNetwork { collection: string; attributes: Buffer; balance: BigNumber; - nonce: Nonce; - creator: Address; + nonce: INonce; + creator: IAddress; royalties: BigNumber; } @@ -135,7 +133,7 @@ export interface IDefinitionOfFungibleTokenOnNetwork { identifier: string; name: string; ticker: string; - owner: Address; + owner: IAddress; decimals: number; supply: BigNumber; isPaused: boolean; @@ -154,7 +152,7 @@ export interface IDefinitionOfTokenCollectionOnNetwork { type: string; name: string; ticker: string; - owner: Address; + owner: IAddress; decimals: number; canPause: boolean; canFreeze: boolean; @@ -168,7 +166,7 @@ export interface IContractQueryResponse { returnCode: ReturnCode; returnMessage: string; gasUsed: GasLimit; - + getReturnDataParts(): Buffer[]; } @@ -184,8 +182,8 @@ export class Pagination { } } -export interface IHash { hex(): string; } -export interface IAddress { bech32(): string; } -export interface INonce { valueOf(): number; } export interface IHexable { hex(): string } +export interface IHash extends IHexable { }; +export interface IAddress { bech32(): string; } +export interface INonce extends IHexable { valueOf(): number; } export interface ITransactionPayload { encoded(): string; } diff --git a/src-network-providers/networkProvider/primitives.ts b/src-network-providers/networkProvider/primitives.ts index 1c9bfe0e..30efe13a 100644 --- a/src-network-providers/networkProvider/primitives.ts +++ b/src-network-providers/networkProvider/primitives.ts @@ -34,6 +34,10 @@ export class Nonce implements INonce { valueOf(): number { return this.value; } + + hex(): string { + return numberToPaddedHex(this.value); + } } export class TransactionValue { @@ -59,3 +63,24 @@ export class TransactionPayload implements ITransactionPayload { return this.base64; } } + +export function numberToPaddedHex(value: number) { + let hex = value.toString(16); + return zeroPadStringIfOddLength(hex); +} + +export function isPaddedHex(input: string) { + input = input || ""; + let decodedThenEncoded = Buffer.from(input, "hex").toString("hex"); + return input.toUpperCase() == decodedThenEncoded.toUpperCase(); +} + +export function zeroPadStringIfOddLength(input: string): string { + input = input || ""; + + if (input.length % 2 == 1) { + return "0" + input; + } + + return input; +} diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index 2a0786a2..cba920d8 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -1,14 +1,11 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "../account"; -import { Address } from "../address"; import { defaultConfig } from "../constants"; -import { ErrNetworkProvider } from "../errors"; -import { IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, Pagination } from "./interface"; +import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, Pagination } from "./interface"; import { Logger } from "../logger"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; -import { Nonce } from "../nonce"; import { Query } from "../smartcontracts"; import { Stats } from "../stats"; import { Transaction } from "../transaction"; @@ -17,6 +14,7 @@ import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } f import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { Hash } from "./primitives"; +import { ErrNetworkProvider } from "./errors"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ProxyNetworkProvider implements INetworkProvider { @@ -52,13 +50,13 @@ export class ProxyNetworkProvider implements INetworkProvider { throw new Error("Method not implemented."); } - async getAccount(address: Address): Promise { + async getAccount(address: IAddress): Promise { let response = await this.doGetGeneric(`address/${address.bech32()}`); let account = AccountOnNetwork.fromHttpResponse(response.account); return account; } - async getFungibleTokensOfAccount(address: Address, _pagination?: Pagination): Promise { + async getFungibleTokensOfAccount(address: IAddress, _pagination?: Pagination): Promise { let url = `address/${address.bech32()}/esdt`; let response = await this.doGetGeneric(url); let responseItems: any[] = Object.values(response.esdts); @@ -71,7 +69,7 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokens; } - async getNonFungibleTokensOfAccount(address: Address, _pagination?: Pagination): Promise { + async getNonFungibleTokensOfAccount(address: IAddress, _pagination?: Pagination): Promise { let url = `address/${address.bech32()}/esdt`; let response = await this.doGetGeneric(url); let responseItems: any[] = Object.values(response.esdts); @@ -84,13 +82,13 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokens; } - async getFungibleTokenOfAccount(address: Address, tokenIdentifier: string): Promise { + async getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise { let response = await this.doGetGeneric(`address/${address.bech32()}/esdt/${tokenIdentifier}`); let tokenData = FungibleTokenOfAccountOnNetwork.fromHttpResponse(response.tokenData); return tokenData; } - async getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: Nonce): Promise { + async getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: INonce): Promise { let response = await this.doGetGeneric(`address/${address.bech32()}/nft/${collection}/nonce/${nonce.valueOf()}`); let tokenData = NonFungibleTokenOfAccountOnNetwork.fromProxyHttpResponseByNonce(response.tokenData); return tokenData; @@ -140,7 +138,7 @@ export class ProxyNetworkProvider implements INetworkProvider { throw new Error("Method not implemented."); } - async getNonFungibleToken(_collection: string, _nonce: Nonce): Promise { + async getNonFungibleToken(_collection: string, _nonce: INonce): Promise { throw new Error("Method not implemented."); } diff --git a/src-network-providers/networkProvider/tokenDefinitions.ts b/src-network-providers/networkProvider/tokenDefinitions.ts index 77b784e6..c1064485 100644 --- a/src-network-providers/networkProvider/tokenDefinitions.ts +++ b/src-network-providers/networkProvider/tokenDefinitions.ts @@ -1,12 +1,12 @@ import { BigNumber } from "bignumber.js"; -import { Address } from "../address"; -import { IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork } from "./interface"; +import { Address } from "./primitives"; +import { IAddress, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork } from "./interface"; export class DefinitionOfFungibleTokenOnNetwork implements IDefinitionOfFungibleTokenOnNetwork { identifier: string = ""; name: string = ""; ticker: string = ""; - owner: Address = new Address(); + owner: IAddress = new Address(""); decimals: number = 0; supply: BigNumber = new BigNumber(0); isPaused: boolean = false; @@ -47,7 +47,7 @@ export class DefinitionOfTokenCollectionOnNetwork implements IDefinitionOfTokenC type: string = ""; name: string = ""; ticker: string = ""; - owner: Address = new Address(); + owner: IAddress = new Address(""); decimals: number = 0; canPause: boolean = false; canFreeze: boolean = false; diff --git a/src-network-providers/networkProvider/tokens.ts b/src-network-providers/networkProvider/tokens.ts index 303fdb7c..3223f178 100644 --- a/src-network-providers/networkProvider/tokens.ts +++ b/src-network-providers/networkProvider/tokens.ts @@ -1,7 +1,6 @@ import { BigNumber } from "bignumber.js"; -import { Address } from "../address"; -import { IFungibleTokenOfAccountOnNetwork, INonFungibleTokenOfAccountOnNetwork } from "./interface"; -import { Nonce } from "../nonce"; +import { Address, Nonce } from "./primitives"; +import { IAddress, IFungibleTokenOfAccountOnNetwork, INonce, INonFungibleTokenOfAccountOnNetwork } from "./interface"; export class FungibleTokenOfAccountOnNetwork implements IFungibleTokenOfAccountOnNetwork { identifier: string = ""; @@ -22,8 +21,8 @@ export class NonFungibleTokenOfAccountOnNetwork implements INonFungibleTokenOfAc collection: string = ""; attributes: Buffer = Buffer.from([]); balance: BigNumber = new BigNumber(0); - nonce: Nonce = new Nonce(0); - creator: Address = new Address(""); + nonce: INonce = new Nonce(0); + creator: IAddress = new Address(""); royalties: BigNumber = new BigNumber(0); static fromProxyHttpResponse(payload: any): NonFungibleTokenOfAccountOnNetwork { diff --git a/src-network-providers/networkProvider/transactionCompletionStrategy.ts b/src-network-providers/networkProvider/transactionCompletionStrategy.ts index afdff564..60de758e 100644 --- a/src-network-providers/networkProvider/transactionCompletionStrategy.ts +++ b/src-network-providers/networkProvider/transactionCompletionStrategy.ts @@ -1,7 +1,7 @@ import { TransactionStatus } from "./transactionStatus"; -import { isPaddedHex } from "../utils.codec"; import { ITransactionPayload } from "./interface"; import { TransactionLogs } from "./transactionLogs"; +import { isPaddedHex } from "./primitives"; /** * Internal interface: a transaction, as seen from the perspective of a {@link TransactionCompletionStrategy}. @@ -56,7 +56,7 @@ export class TransactionCompletionStrategy { let prefix = parts[0]; let otherParts = parts.slice(1); let emptyPrefix = !prefix; - let somePartsAreNotValidArguments = !otherParts.every(this.looksLikeValidArgument); + let somePartsAreNotValidArguments = !otherParts.every(part => this.looksLikeValidArgument(part)); return emptyPrefix || somePartsAreNotValidArguments; } diff --git a/src-network-providers/networkProvider/transactionEvents.ts b/src-network-providers/networkProvider/transactionEvents.ts index 60c8e75b..3ff2a5c4 100644 --- a/src-network-providers/networkProvider/transactionEvents.ts +++ b/src-network-providers/networkProvider/transactionEvents.ts @@ -1,12 +1,13 @@ -import { Address } from "../address"; +import { IAddress } from "./interface"; +import { Address } from "./primitives"; export class TransactionEvent { - readonly address: Address; + readonly address: IAddress; readonly identifier: string; readonly topics: TransactionEventTopic[]; readonly data: string; - constructor(address: Address, identifier: string, topics: TransactionEventTopic[], data: string) { + constructor(address: IAddress, identifier: string, topics: TransactionEventTopic[], data: string) { this.address = address; this.identifier = identifier; this.topics = topics; diff --git a/src-network-providers/networkProvider/transactionLogs.ts b/src-network-providers/networkProvider/transactionLogs.ts index 21be82b4..91586ef0 100644 --- a/src-network-providers/networkProvider/transactionLogs.ts +++ b/src-network-providers/networkProvider/transactionLogs.ts @@ -1,18 +1,19 @@ -import { Address } from "../address"; -import { ErrUnexpectedCondition } from "../errors"; +import { ErrUnexpectedCondition } from "./errors"; +import { IAddress } from "./interface"; +import { Address } from "./primitives"; import { TransactionEvent } from "./transactionEvents"; export class TransactionLogs { - readonly address: Address; + readonly address: IAddress; readonly events: TransactionEvent[]; - constructor(address: Address, events: TransactionEvent[]) { + constructor(address: IAddress, events: TransactionEvent[]) { this.address = address; this.events = events; } static empty(): TransactionLogs { - return new TransactionLogs(new Address(), []); + return new TransactionLogs(new Address(""), []); } static fromHttpResponse(logs: any): TransactionLogs { diff --git a/src-network-providers/networkProvider/transactionReceipt.ts b/src-network-providers/networkProvider/transactionReceipt.ts index 8a6e6ec2..35866169 100644 --- a/src-network-providers/networkProvider/transactionReceipt.ts +++ b/src-network-providers/networkProvider/transactionReceipt.ts @@ -1,12 +1,11 @@ -import { Address } from "../address"; -import { Balance } from "../balance"; -import { TransactionHash } from "../transaction"; +import { IAddress, IHash } from "./interface"; +import { Address, Hash, TransactionValue } from "./primitives"; export class TransactionReceipt { - value: Balance = Balance.Zero(); - sender: Address = new Address(); + value: TransactionValue = new TransactionValue(""); + sender: IAddress = new Address(""); data: string = ""; - hash: TransactionHash = TransactionHash.empty(); + hash: IHash = new Hash(""); static fromHttpResponse(response: { value: string, @@ -16,10 +15,10 @@ export class TransactionReceipt { }): TransactionReceipt { let receipt = new TransactionReceipt(); - receipt.value = Balance.fromString(response.value); + receipt.value = new TransactionValue(response.value); receipt.sender = new Address(response.sender); receipt.data = response.data; - receipt.hash = new TransactionHash(response.txHash); + receipt.hash = new Hash(response.txHash); return receipt; } From f6cbf031744a28b18d6107959550922fc914caa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Tue, 5 Apr 2022 23:04:44 +0300 Subject: [PATCH 023/133] Continue decoupling. --- .../networkProvider/apiNetworkProvider.ts | 14 +++--- .../networkProvider/config.ts | 11 +++++ .../networkProvider/contractResults.ts | 43 ++++++++----------- .../networkProvider/interface.ts | 10 ++++- .../networkProvider/proxyNetworkProvider.ts | 14 +++--- .../networkProvider/transactions.ts | 6 +-- 6 files changed, 53 insertions(+), 45 deletions(-) create mode 100644 src-network-providers/networkProvider/config.ts diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index 57a65d5c..6bed3490 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -1,14 +1,11 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "../account"; -import { defaultConfig } from "../constants"; -import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, Pagination } from "./interface"; -import { Logger } from "../logger"; +import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; import { Query } from "../smartcontracts"; import { Stats } from "../stats"; -import { Transaction } from "../transaction"; import { ContractQueryResponse } from "./contractResults"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; @@ -17,6 +14,7 @@ import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { Hash } from "./primitives"; import { ErrNetworkProvider } from "./errors"; +import { defaultAxiosConfig } from "./config"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ApiNetworkProvider implements INetworkProvider { @@ -26,7 +24,7 @@ export class ApiNetworkProvider implements INetworkProvider { constructor(url: string, config?: AxiosRequestConfig) { this.url = url; - this.config = { ...defaultConfig, ...config }; + this.config = { ...defaultAxiosConfig, ...config }; this.backingProxyNetworkProvider = new ProxyNetworkProvider(url, config); } @@ -104,13 +102,13 @@ export class ApiNetworkProvider implements INetworkProvider { return status; } - async sendTransaction(tx: Transaction): Promise { + async sendTransaction(tx: ITransaction): Promise { let response = await this.doPostGeneric("transactions", tx.toSendable()); let hash = new Hash(response.txHash); return hash; } - async simulateTransaction(tx: Transaction): Promise { + async simulateTransaction(tx: ITransaction): Promise { return await this.backingProxyNetworkProvider.simulateTransaction(tx); } @@ -181,7 +179,7 @@ export class ApiNetworkProvider implements INetworkProvider { private handleApiError(error: any, resourceUrl: string) { if (!error.response) { - Logger.warn(error); + console.warn(error); throw new ErrNetworkProvider(resourceUrl, error.toString(), error); } diff --git a/src-network-providers/networkProvider/config.ts b/src-network-providers/networkProvider/config.ts new file mode 100644 index 00000000..9d352c9d --- /dev/null +++ b/src-network-providers/networkProvider/config.ts @@ -0,0 +1,11 @@ +const JSONbig = require("json-bigint"); + +export const defaultAxiosConfig = { + timeout: 1000, + // See: https://github.com/axios/axios/issues/983 regarding transformResponse + transformResponse: [ + function (data: any) { + return JSONbig.parse(data); + } + ] +}; diff --git a/src-network-providers/networkProvider/contractResults.ts b/src-network-providers/networkProvider/contractResults.ts index 57c625e4..9f388027 100644 --- a/src-network-providers/networkProvider/contractResults.ts +++ b/src-network-providers/networkProvider/contractResults.ts @@ -1,14 +1,9 @@ import { BigNumber } from "bignumber.js"; -import { Address } from "../address"; -import { Balance } from "../balance"; -import { Hash } from "../hash"; -import { IContractQueryResponse } from "./interface"; -import { GasLimit, GasPrice } from "../networkParams"; -import { Nonce } from "../nonce"; -import { TransactionHash } from "../transaction"; +import { IAddress, IContractQueryResponse, IGasLimit, IGasPrice, IHash, INonce } from "./interface"; import { TransactionLogs } from "./transactionLogs"; import { ReturnCode } from "../smartcontracts/returnCode"; import { MaxUint64 } from "../smartcontracts/query"; +import { Address, Hash, Nonce, TransactionValue } from "./primitives"; export class ContractResults { readonly items: ContractResultItem[]; @@ -37,16 +32,16 @@ export class ContractResults { } export class ContractResultItem { - hash: Hash = Hash.empty(); - nonce: Nonce = new Nonce(0); - value: Balance = Balance.Zero(); - receiver: Address = new Address(); - sender: Address = new Address(); + hash: IHash = new Hash("") + nonce: INonce = new Nonce(0); + value: TransactionValue = new TransactionValue(""); + receiver: IAddress = new Address(""); + sender: IAddress = new Address(""); data: string = ""; - previousHash: Hash = Hash.empty(); - originalHash: Hash = Hash.empty(); - gasLimit: GasLimit = new GasLimit(0); - gasPrice: GasPrice = new GasPrice(0); + previousHash: Hash = new Hash(""); + originalHash: Hash = new Hash(""); + gasLimit: IGasLimit = 0; + gasPrice: IGasPrice = 0; callType: number = 0; returnMessage: string = ""; logs: TransactionLogs = TransactionLogs.empty(); @@ -72,15 +67,15 @@ export class ContractResultItem { private static fromHttpResponse(response: any): ContractResultItem { let item = new ContractResultItem(); - item.hash = new TransactionHash(response.hash); + item.hash = new Hash(response.hash); item.nonce = new Nonce(response.nonce || 0); - item.value = Balance.fromString(response.value); + item.value = new TransactionValue(response.value || ""); item.receiver = new Address(response.receiver); item.sender = new Address(response.sender); - item.previousHash = new TransactionHash(response.prevTxHash); - item.originalHash = new TransactionHash(response.originalTxHash); - item.gasLimit = new GasLimit(response.gasLimit); - item.gasPrice = new GasPrice(response.gasPrice); + item.previousHash = new Hash(response.prevTxHash); + item.originalHash = new Hash(response.originalTxHash); + item.gasLimit = response.gasLimit || 0; + item.gasPrice = response.gasPrice || 0; item.data = response.data || ""; item.callType = response.callType; item.returnMessage = response.returnMessage; @@ -95,7 +90,7 @@ export class ContractQueryResponse implements IContractQueryResponse { returnData: string[] = []; returnCode: ReturnCode = ReturnCode.None; returnMessage: string = ""; - gasUsed: GasLimit = new GasLimit(0); + gasUsed: IGasLimit = 0; static fromHttpResponse(payload: any): ContractQueryResponse { let response = new ContractQueryResponse(); @@ -104,7 +99,7 @@ export class ContractQueryResponse implements IContractQueryResponse { response.returnData = payload["returnData"] || []; response.returnCode = payload["returnCode"] || ""; response.returnMessage = payload["returnMessage"] || ""; - response.gasUsed = new GasLimit(MaxUint64.minus(gasRemaining).toNumber()); + response.gasUsed = MaxUint64.minus(gasRemaining).toNumber(); return response; } diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/networkProvider/interface.ts index 0b822b68..9bfb7744 100644 --- a/src-network-providers/networkProvider/interface.ts +++ b/src-network-providers/networkProvider/interface.ts @@ -165,7 +165,7 @@ export interface IContractQueryResponse { returnData: string[]; returnCode: ReturnCode; returnMessage: string; - gasUsed: GasLimit; + gasUsed: IGasLimit; getReturnDataParts(): Buffer[]; } @@ -182,8 +182,14 @@ export class Pagination { } } +export interface ITransaction { + toSendable(): any; +} + export interface IHexable { hex(): string } -export interface IHash extends IHexable { }; +export interface IHash extends IHexable { } export interface IAddress { bech32(): string; } export interface INonce extends IHexable { valueOf(): number; } export interface ITransactionPayload { encoded(): string; } +export interface IGasLimit { valueOf(): number; } +export interface IGasPrice { valueOf(): number; } diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index cba920d8..00201c28 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -1,20 +1,18 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "../account"; -import { defaultConfig } from "../constants"; -import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, Pagination } from "./interface"; -import { Logger } from "../logger"; +import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; import { Query } from "../smartcontracts"; import { Stats } from "../stats"; -import { Transaction } from "../transaction"; import { ContractQueryResponse } from "./contractResults"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { Hash } from "./primitives"; import { ErrNetworkProvider } from "./errors"; +import { defaultAxiosConfig } from "./config"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ProxyNetworkProvider implements INetworkProvider { @@ -23,7 +21,7 @@ export class ProxyNetworkProvider implements INetworkProvider { constructor(url: string, config?: AxiosRequestConfig) { this.url = url; - this.config = { ...defaultConfig, ...config }; + this.config = { ...defaultAxiosConfig, ...config }; } async getNetworkConfig(): Promise { @@ -107,13 +105,13 @@ export class ProxyNetworkProvider implements INetworkProvider { return status; } - async sendTransaction(tx: Transaction): Promise { + async sendTransaction(tx: ITransaction): Promise { let response = await this.doPostGeneric("transaction/send", tx.toSendable()); let hash = new Hash(response.txHash); return hash; } - async simulateTransaction(tx: Transaction): Promise { + async simulateTransaction(tx: ITransaction): Promise { let response = await this.doPostGeneric("transaction/simulate", tx.toSendable()); return response; } @@ -193,7 +191,7 @@ export class ProxyNetworkProvider implements INetworkProvider { private handleApiError(error: any, resourceUrl: string) { if (!error.response) { - Logger.warn(error); + console.warn(error); throw new ErrNetworkProvider(resourceUrl, error.toString(), error); } diff --git a/src-network-providers/networkProvider/transactions.ts b/src-network-providers/networkProvider/transactions.ts index 60d73e6e..632c19f8 100644 --- a/src-network-providers/networkProvider/transactions.ts +++ b/src-network-providers/networkProvider/transactions.ts @@ -1,7 +1,7 @@ import { TransactionStatus } from "./transactionStatus"; import { ContractResults } from "./contractResults"; import { Address, Hash, Nonce, TransactionValue, TransactionPayload } from "./primitives"; -import { IAddress, IHash, INonce, ITransactionPayload } from "./interface"; +import { IAddress, IGasLimit, IGasPrice, IHash, INonce, ITransactionPayload } from "./interface"; import { TransactionCompletionStrategy } from "./transactionCompletionStrategy"; import { TransactionEvent } from "./transactionEvents"; import { TransactionLogs } from "./transactionLogs"; @@ -16,8 +16,8 @@ import { TransactionReceipt } from "./transactionReceipt"; value: TransactionValue = new TransactionValue(""); receiver: IAddress = new Address(""); sender: IAddress = new Address(""); - gasPrice: number = 0; - gasLimit: number = 0; + gasLimit: IGasLimit = 0; + gasPrice: IGasPrice = 0; data: ITransactionPayload = new TransactionPayload(""); signature: string = ""; status: TransactionStatus = TransactionStatus.createUnknown(); From 2aa4f2cc2abdae91fd611eaa669701f3291ac806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Tue, 5 Apr 2022 23:16:47 +0300 Subject: [PATCH 024/133] Continue decoupling. --- .../networkProvider/contractResults.ts | 9 ++++----- src-network-providers/networkProvider/interface.ts | 14 ++++++++------ .../networkProvider/primitives.ts | 12 ++++++++++++ .../networkProvider/providers.dev.net.spec.ts | 6 ++---- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src-network-providers/networkProvider/contractResults.ts b/src-network-providers/networkProvider/contractResults.ts index 9f388027..71f12e0c 100644 --- a/src-network-providers/networkProvider/contractResults.ts +++ b/src-network-providers/networkProvider/contractResults.ts @@ -1,9 +1,8 @@ import { BigNumber } from "bignumber.js"; -import { IAddress, IContractQueryResponse, IGasLimit, IGasPrice, IHash, INonce } from "./interface"; +import { IAddress, IContractQueryResponse, IContractReturnCode, IGasLimit, IGasPrice, IHash, INonce } from "./interface"; import { TransactionLogs } from "./transactionLogs"; -import { ReturnCode } from "../smartcontracts/returnCode"; import { MaxUint64 } from "../smartcontracts/query"; -import { Address, Hash, Nonce, TransactionValue } from "./primitives"; +import { Address, ContractReturnCode, Hash, Nonce, TransactionValue } from "./primitives"; export class ContractResults { readonly items: ContractResultItem[]; @@ -88,7 +87,7 @@ export class ContractResultItem { export class ContractQueryResponse implements IContractQueryResponse { returnData: string[] = []; - returnCode: ReturnCode = ReturnCode.None; + returnCode: IContractReturnCode = new ContractReturnCode(""); returnMessage: string = ""; gasUsed: IGasLimit = 0; @@ -97,7 +96,7 @@ export class ContractQueryResponse implements IContractQueryResponse { let gasRemaining = new BigNumber(payload["gasRemaining"] || payload["GasRemaining"] || 0); response.returnData = payload["returnData"] || []; - response.returnCode = payload["returnCode"] || ""; + response.returnCode = new ContractReturnCode(payload["returnCode"] || ""); response.returnMessage = payload["returnMessage"] || ""; response.gasUsed = MaxUint64.minus(gasRemaining).toNumber(); diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/networkProvider/interface.ts index 9bfb7744..5d4a2c45 100644 --- a/src-network-providers/networkProvider/interface.ts +++ b/src-network-providers/networkProvider/interface.ts @@ -1,12 +1,10 @@ import { BigNumber } from "bignumber.js"; import { AccountOnNetwork } from "../account"; import { NetworkConfig } from "../networkConfig"; -import { GasLimit } from "../networkParams"; import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; -import { Query, ReturnCode } from "../smartcontracts"; +import { Query } from "../smartcontracts"; import { Stats } from "../stats"; -import { Transaction } from "../transaction"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; @@ -72,13 +70,13 @@ export interface INetworkProvider { /** * Broadcasts an already-signed {@link Transaction}. */ - sendTransaction(tx: Transaction): Promise; + sendTransaction(tx: ITransaction): Promise; /** * Simulates the processing of an already-signed {@link Transaction}. * */ - simulateTransaction(tx: Transaction): Promise; + simulateTransaction(tx: ITransaction): Promise; /** * Queries a Smart Contract - runs a pure function defined by the contract and returns its results. @@ -163,13 +161,17 @@ export interface IDefinitionOfTokenCollectionOnNetwork { export interface IContractQueryResponse { returnData: string[]; - returnCode: ReturnCode; + returnCode: IContractReturnCode; returnMessage: string; gasUsed: IGasLimit; getReturnDataParts(): Buffer[]; } +export interface IContractReturnCode { + toString(): string; +} + export interface IContractSimulation { } diff --git a/src-network-providers/networkProvider/primitives.ts b/src-network-providers/networkProvider/primitives.ts index 30efe13a..25d4e519 100644 --- a/src-network-providers/networkProvider/primitives.ts +++ b/src-network-providers/networkProvider/primitives.ts @@ -64,6 +64,18 @@ export class TransactionPayload implements ITransactionPayload { } } +export class ContractReturnCode { + private readonly value: string; + + constructor(value: string) { + this.value = value; + } + + toString() { + return this.value; + } +} + export function numberToPaddedHex(value: number) { let hex = value.toString(16); return zeroPadStringIfOddLength(hex); diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts index 479fd40b..2c8d8787 100644 --- a/src-network-providers/networkProvider/providers.dev.net.spec.ts +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -1,17 +1,15 @@ import { assert } from "chai"; import { INetworkProvider } from "./interface"; -import { Address } from "../address"; import { loadTestWallets, TestWallet } from "../testutils"; import { TransactionHash } from "../transaction"; -import { Nonce } from "../nonce"; import { ContractFunction, Query } from "../smartcontracts"; import { BigUIntValue, U32Value, BytesValue, VariadicValue, VariadicType, CompositeType, BytesType, BooleanType } from "../smartcontracts/typesystem"; import { BigNumber } from "bignumber.js"; -import { Balance } from "../balance"; import { ApiNetworkProvider } from "./apiNetworkProvider"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; +import { Address, Nonce, TransactionValue } from "./primitives"; describe("test network providers on devnet: Proxy and API", function () { let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 10000 }); @@ -247,7 +245,7 @@ describe("test network providers on devnet: Proxy and API", function () { query = new Query({ address: new Address("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"), func: new ContractFunction("issue"), - value: Balance.egld(0.05), + value: new TransactionValue("42"), args: [ BytesValue.fromUTF8("FOO"), BytesValue.fromUTF8("FOO"), From 52dfa3190d53fff7f00c4ab1d60bdc95682489c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Tue, 5 Apr 2022 23:36:45 +0300 Subject: [PATCH 025/133] Fix after self review. --- src-network-providers/networkProvider/transactions.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src-network-providers/networkProvider/transactions.ts b/src-network-providers/networkProvider/transactions.ts index 632c19f8..6df35186 100644 --- a/src-network-providers/networkProvider/transactions.ts +++ b/src-network-providers/networkProvider/transactions.ts @@ -85,8 +85,7 @@ import { TransactionReceipt } from "./transactionReceipt"; } isCompleted(): boolean { - // TODO: When using separate constructors of TransactionOnNetwork (for API response vs. for Gateway response, see package "networkProvider"), - // we will be able to use different transaction completion strategies. + // TODO: use different transaction completion strategies - API / Proxy. return new TransactionCompletionStrategy().isCompleted(this); } From f1efc27094d97648661fb13056b1c33f695a5d6d Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 6 Apr 2022 10:17:35 +0300 Subject: [PATCH 026/133] Fixes (upon running the tests). --- src-network-providers/networkProvider/primitives.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src-network-providers/networkProvider/primitives.ts b/src-network-providers/networkProvider/primitives.ts index 25d4e519..2f77a876 100644 --- a/src-network-providers/networkProvider/primitives.ts +++ b/src-network-providers/networkProvider/primitives.ts @@ -53,14 +53,18 @@ export class TransactionValue { } export class TransactionPayload implements ITransactionPayload { - private readonly base64: string; + private readonly decoded: Buffer; - constructor(base64: string) { - this.base64 = base64; + constructor(encoded: string) { + this.decoded = Buffer.from(encoded || "", "base64"); } encoded(): string { - return this.base64; + return this.decoded.toString("base64"); + } + + toString() { + return this.decoded.toString(); } } From 68c29465c694f985b244f3eef541b1bd19a7db5e Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 6 Apr 2022 10:50:45 +0300 Subject: [PATCH 027/133] Tests and fixes. --- .../networkProvider/contractResults.ts | 6 +-- .../networkProvider/providers.dev.net.spec.ts | 39 +++++++------------ .../networkProvider/transactions.ts | 4 +- 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/src-network-providers/networkProvider/contractResults.ts b/src-network-providers/networkProvider/contractResults.ts index 71f12e0c..3d9b4299 100644 --- a/src-network-providers/networkProvider/contractResults.ts +++ b/src-network-providers/networkProvider/contractResults.ts @@ -68,13 +68,13 @@ export class ContractResultItem { item.hash = new Hash(response.hash); item.nonce = new Nonce(response.nonce || 0); - item.value = new TransactionValue(response.value || ""); + item.value = new TransactionValue((response.value || 0).toString()); item.receiver = new Address(response.receiver); item.sender = new Address(response.sender); item.previousHash = new Hash(response.prevTxHash); item.originalHash = new Hash(response.originalTxHash); - item.gasLimit = response.gasLimit || 0; - item.gasPrice = response.gasPrice || 0; + item.gasLimit = Number(response.gasLimit || 0); + item.gasPrice = Number(response.gasPrice || 0); item.data = response.data || ""; item.callType = response.callType; item.returnMessage = response.returnMessage; diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/networkProvider/providers.dev.net.spec.ts index 2c8d8787..0b21855a 100644 --- a/src-network-providers/networkProvider/providers.dev.net.spec.ts +++ b/src-network-providers/networkProvider/providers.dev.net.spec.ts @@ -103,17 +103,12 @@ describe("test network providers on devnet: Proxy and API", function () { this.timeout(20000); let hashes = [ - new TransactionHash("b41f5fc39e96b1f194d07761c6efd6cb92278b95f5012ab12cbc910058ca8b54"), - new TransactionHash("7757397a59378e9d0f6d5f08cc934c260e33a50ae0d73fdf869f7c02b6b47b33"), - new TransactionHash("b87238089e81527158a6daee520280324bc7e5322ba54d1b3c9a5678abe953ea"), - new TransactionHash("b45dd5e598bc85ba71639f2cbce8c5dff2fbe93159e637852fddeb16c0e84a48"), - new TransactionHash("83db780e98d4d3c917668c47b33ba51445591efacb0df2a922f88e7dfbb5fc7d"), - new TransactionHash("c2eb62b28cc7320da2292d87944c5424a70e1f443323c138c1affada7f6e9705"), - // TODO: Uncomment once the Gateway returns all SCRs in this case, as well. - // new TransactionHash("98e913c2a78cafdf4fa7f0113c1285fb29c2409bd7a746bb6f5506ad76841d54"), - new TransactionHash("5b05945be8ba2635e7c13d792ad727533494358308b5fcf36a816e52b5b272b8"), - new TransactionHash("47b089b5f0220299a017359003694a01fd75d075100166b8072c418d5143fe06"), - new TransactionHash("85021f20b06662240d8302d62f68031bbf7261bacb53b84e3dc9346c0f10a8e7") + new TransactionHash("a069c663831002651fd542479869cc61103465f3284dace772e7480f81429fa8"), + new TransactionHash("de3bc87f3e057e28ea6a625acd6d6d332e24f35ea73e820462b71256c8ecffb7"), + new TransactionHash("dbefa0299fe6b2336eb0bc3123fa623845c276e5c6e2a175adf1a562d5e77718"), + new TransactionHash("2a8ccbd91b7d9460a86174b5a8d4e6aa073b38674d1ee8107e728980a66f0676"), + // TODO: uncomment after fix (SCR missing on API) + // new TransactionHash("be7914b1eb4c6bd352ba1d86991959b443e446e0ad49fb796be3495c287b2472") ]; for (const hash of hashes) { @@ -131,6 +126,7 @@ describe("test network providers on devnet: Proxy and API", function () { apiResponse.status = proxyResponse.status = new TransactionStatus("ignore"); // Ignore fields which are not present on API response: + proxyResponse.type = ""; proxyResponse.epoch = 0; proxyResponse.blockNonce = 0; proxyResponse.hyperblockNonce = 0; @@ -142,16 +138,11 @@ describe("test network providers on devnet: Proxy and API", function () { this.timeout(20000); let hashes = [ - new TransactionHash("b41f5fc39e96b1f194d07761c6efd6cb92278b95f5012ab12cbc910058ca8b54"), - new TransactionHash("7757397a59378e9d0f6d5f08cc934c260e33a50ae0d73fdf869f7c02b6b47b33"), - new TransactionHash("b87238089e81527158a6daee520280324bc7e5322ba54d1b3c9a5678abe953ea"), - new TransactionHash("b45dd5e598bc85ba71639f2cbce8c5dff2fbe93159e637852fddeb16c0e84a48"), - new TransactionHash("83db780e98d4d3c917668c47b33ba51445591efacb0df2a922f88e7dfbb5fc7d"), - new TransactionHash("c2eb62b28cc7320da2292d87944c5424a70e1f443323c138c1affada7f6e9705"), - new TransactionHash("98e913c2a78cafdf4fa7f0113c1285fb29c2409bd7a746bb6f5506ad76841d54"), - new TransactionHash("5b05945be8ba2635e7c13d792ad727533494358308b5fcf36a816e52b5b272b8"), - new TransactionHash("47b089b5f0220299a017359003694a01fd75d075100166b8072c418d5143fe06"), - new TransactionHash("85021f20b06662240d8302d62f68031bbf7261bacb53b84e3dc9346c0f10a8e7") + new TransactionHash("a069c663831002651fd542479869cc61103465f3284dace772e7480f81429fa8"), + new TransactionHash("de3bc87f3e057e28ea6a625acd6d6d332e24f35ea73e820462b71256c8ecffb7"), + new TransactionHash("dbefa0299fe6b2336eb0bc3123fa623845c276e5c6e2a175adf1a562d5e77718"), + new TransactionHash("2a8ccbd91b7d9460a86174b5a8d4e6aa073b38674d1ee8107e728980a66f0676"), + new TransactionHash("be7914b1eb4c6bd352ba1d86991959b443e446e0ad49fb796be3495c287b2472") ]; for (const hash of hashes) { @@ -165,7 +156,7 @@ describe("test network providers on devnet: Proxy and API", function () { it("should have same response for getDefinitionOfFungibleToken()", async function () { this.timeout(10000); - let identifiers = ["MEX-b6bb7d", "WEGLD-88600a", "RIDE-482531", "USDC-a32906"]; + let identifiers = ["FOO-b6f543", "BAR-c80d29", "COUNTER-b7401d"]; for (const identifier of identifiers) { let apiResponse = await apiProvider.getDefinitionOfFungibleToken(identifier); @@ -181,7 +172,7 @@ describe("test network providers on devnet: Proxy and API", function () { it("should have same response for getDefinitionOfTokenCollection()", async function () { this.timeout(10000); - let collections = ["LKMEX-9acade", "LKFARM-c20c1c", "MEXFARM-bab93a", "ART-264971", "MOS-ff0040"]; + let collections = ["ERDJS-38f249"]; for (const collection of collections) { let apiResponse = await apiProvider.getDefinitionOfTokenCollection(collection); @@ -197,7 +188,7 @@ describe("test network providers on devnet: Proxy and API", function () { it("should have same response for getNonFungibleToken()", async function () { this.timeout(10000); - let tokens = [{ id: "ERDJSNFT-4a5669", nonce: new Nonce(1) }]; + let tokens = [{ id: "ERDJS-38f249", nonce: new Nonce(1) }]; for (const token of tokens) { let apiResponse = await apiProvider.getNonFungibleToken(token.id, token.nonce); diff --git a/src-network-providers/networkProvider/transactions.ts b/src-network-providers/networkProvider/transactions.ts index 6df35186..4cd351cb 100644 --- a/src-network-providers/networkProvider/transactions.ts +++ b/src-network-providers/networkProvider/transactions.ts @@ -60,7 +60,7 @@ import { TransactionReceipt } from "./transactionReceipt"; result.nonce = new Nonce(response.nonce || 0); result.round = response.round; result.epoch = response.epoch || 0; - result.value = new TransactionValue(response.value); + result.value = new TransactionValue((response.value || 0).toString()); result.sender = new Address(response.sender); result.receiver = new Address(response.receiver); result.gasPrice = response.gasPrice || 0; @@ -71,7 +71,7 @@ import { TransactionReceipt } from "./transactionReceipt"; result.blockNonce = response.blockNonce || 0; result.hyperblockNonce = response.hyperblockNonce || 0; - result.hyperblockHash = response.hyperblockHash; + result.hyperblockHash = response.hyperblockHash || ""; result.pendingResults = response.pendingResults || false; result.receipt = TransactionReceipt.fromHttpResponse(response.receipt || {}); From dd1369038f9c484787c3028a9fddb3792a1f2782 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 6 Apr 2022 11:21:15 +0300 Subject: [PATCH 028/133] Remove deprecated status (fix after review). --- src-network-providers/networkProvider/transactionStatus.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src-network-providers/networkProvider/transactionStatus.ts b/src-network-providers/networkProvider/transactionStatus.ts index e7346cf8..bb509cbc 100644 --- a/src-network-providers/networkProvider/transactionStatus.ts +++ b/src-network-providers/networkProvider/transactionStatus.ts @@ -27,8 +27,7 @@ export class TransactionStatus { isPending(): boolean { return ( this.status == "received" || - this.status == "pending" || - this.status == "partially-executed" + this.status == "pending" ); } From 22640f35a296a769c228012f7ee7399cee59d47d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Wed, 6 Apr 2022 14:03:18 +0300 Subject: [PATCH 029/133] Move "accountOnNetwork" to "networkProvider". Further decoupling. --- .../networkProvider/accounts.ts | 30 +++++++++++++++++++ .../networkProvider/apiNetworkProvider.ts | 2 +- .../networkProvider/interface.ts | 3 +- .../networkProvider/primitives.ts | 12 ++++++++ .../networkProvider/proxyNetworkProvider.ts | 2 +- 5 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 src-network-providers/networkProvider/accounts.ts diff --git a/src-network-providers/networkProvider/accounts.ts b/src-network-providers/networkProvider/accounts.ts new file mode 100644 index 00000000..6c713358 --- /dev/null +++ b/src-network-providers/networkProvider/accounts.ts @@ -0,0 +1,30 @@ +import { IAccountBalance, IAddress, INonce } from "./interface"; +import { AccountBalance, Address, Nonce } from "./primitives"; + +/** + * A plain view of an account, as queried from the Network. + */ + export class AccountOnNetwork { + address: IAddress = new Address(""); + nonce: INonce = new Nonce(0); + balance: IAccountBalance = new AccountBalance(""); + code: string = ""; + userName: string = ""; + + constructor(init?: Partial) { + Object.assign(this, init); + } + + static fromHttpResponse(payload: any): AccountOnNetwork { + let result = new AccountOnNetwork(); + + result.address = new Address(payload["address"] || 0); + result.nonce = new Nonce(payload["nonce"] || 0); + result.balance = new AccountBalance(payload["balance"] || "0"); + result.code = payload["code"] || ""; + result.userName = payload["username"] || ""; + + return result; + } +} + diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index 6bed3490..4be146c4 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -1,5 +1,5 @@ import axios, { AxiosRequestConfig } from "axios"; -import { AccountOnNetwork } from "../account"; +import { AccountOnNetwork } from "./accounts"; import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/networkProvider/interface.ts index 5d4a2c45..6bd5232e 100644 --- a/src-network-providers/networkProvider/interface.ts +++ b/src-network-providers/networkProvider/interface.ts @@ -1,5 +1,5 @@ import { BigNumber } from "bignumber.js"; -import { AccountOnNetwork } from "../account"; +import { AccountOnNetwork } from "./accounts"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; import { NetworkStatus } from "../networkStatus"; @@ -195,3 +195,4 @@ export interface INonce extends IHexable { valueOf(): number; } export interface ITransactionPayload { encoded(): string; } export interface IGasLimit { valueOf(): number; } export interface IGasPrice { valueOf(): number; } +export interface IAccountBalance { toString(): string; } diff --git a/src-network-providers/networkProvider/primitives.ts b/src-network-providers/networkProvider/primitives.ts index 2f77a876..0adef98a 100644 --- a/src-network-providers/networkProvider/primitives.ts +++ b/src-network-providers/networkProvider/primitives.ts @@ -80,6 +80,18 @@ export class ContractReturnCode { } } +export class AccountBalance { + private readonly value: string; + + constructor(value: string) { + this.value = value; + } + + toString(): string { + return this.value; + } +} + export function numberToPaddedHex(value: number) { let hex = value.toString(16); return zeroPadStringIfOddLength(hex); diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index 00201c28..1d7ab16d 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -1,5 +1,5 @@ import axios, { AxiosRequestConfig } from "axios"; -import { AccountOnNetwork } from "../account"; +import { AccountOnNetwork } from "./accounts"; import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "../networkStake"; From d64729451b7fa244b9389f775ef7a950006c4b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Wed, 6 Apr 2022 14:29:03 +0300 Subject: [PATCH 030/133] Move networkStatus, networkStake to networkProvider package. --- .../networkProvider/apiNetworkProvider.ts | 4 +- .../networkProvider/interface.ts | 4 +- .../networkProvider/networkStake.ts | 47 +++++++++++ .../networkProvider/networkStatus.ts | 82 +++++++++++++++++++ .../networkProvider/proxyNetworkProvider.ts | 4 +- 5 files changed, 135 insertions(+), 6 deletions(-) create mode 100644 src-network-providers/networkProvider/networkStake.ts create mode 100644 src-network-providers/networkProvider/networkStatus.ts diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index 4be146c4..3e703c24 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -2,8 +2,7 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; import { NetworkConfig } from "../networkConfig"; -import { NetworkStake } from "../networkStake"; -import { NetworkStatus } from "../networkStatus"; +import { NetworkStake } from "./networkStake"; import { Query } from "../smartcontracts"; import { Stats } from "../stats"; import { ContractQueryResponse } from "./contractResults"; @@ -15,6 +14,7 @@ import { TransactionStatus } from "./transactionStatus"; import { Hash } from "./primitives"; import { ErrNetworkProvider } from "./errors"; import { defaultAxiosConfig } from "./config"; +import { NetworkStatus } from "./networkStatus"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ApiNetworkProvider implements INetworkProvider { diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/networkProvider/interface.ts index 6bd5232e..1c6c98f4 100644 --- a/src-network-providers/networkProvider/interface.ts +++ b/src-network-providers/networkProvider/interface.ts @@ -1,12 +1,12 @@ import { BigNumber } from "bignumber.js"; import { AccountOnNetwork } from "./accounts"; import { NetworkConfig } from "../networkConfig"; -import { NetworkStake } from "../networkStake"; -import { NetworkStatus } from "../networkStatus"; +import { NetworkStake } from "./networkStake"; import { Query } from "../smartcontracts"; import { Stats } from "../stats"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; +import { NetworkStatus } from "./networkStatus"; /** * An interface that defines the endpoints of an HTTP API Provider. diff --git a/src-network-providers/networkProvider/networkStake.ts b/src-network-providers/networkProvider/networkStake.ts new file mode 100644 index 00000000..cab48b60 --- /dev/null +++ b/src-network-providers/networkProvider/networkStake.ts @@ -0,0 +1,47 @@ +import BigNumber from "bignumber.js"; + +/** + * An object holding Network stake parameters. + */ +export class NetworkStake { + private static default: NetworkStake; + + /** + * The Total Validators Number. + */ + public TotalValidators: number; + + /** + * The Active Validators Number. + */ + public ActiveValidators: number; + /** + * The Queue Size. + */ + public QueueSize: number; + /** + * The Total Validators Number. + */ + public TotalStaked: BigNumber; + + constructor() { + this.TotalValidators = 0; + this.ActiveValidators = 0; + this.QueueSize = 0; + this.TotalStaked = new BigNumber(0); + } + + /** + * Constructs a configuration object from a HTTP response (as returned by the provider). + */ + static fromHttpResponse(payload: any): NetworkStake { + let networkStake = new NetworkStake(); + + networkStake.TotalValidators = Number(payload["totalValidators"]); + networkStake.ActiveValidators = Number(payload["activeValidators"]); + networkStake.QueueSize = Number(payload["queueSize"]); + networkStake.TotalStaked = new BigNumber(payload["totalStaked"]); + + return networkStake; + } +} diff --git a/src-network-providers/networkProvider/networkStatus.ts b/src-network-providers/networkProvider/networkStatus.ts new file mode 100644 index 00000000..ec42a479 --- /dev/null +++ b/src-network-providers/networkProvider/networkStatus.ts @@ -0,0 +1,82 @@ +/** + * An object holding network status configuration parameters. + */ +export class NetworkStatus { + private static default: NetworkStatus; + + /** + * The current round. + */ + public CurrentRound: number; + + /** + * The epoch number. + */ + public EpochNumber: number; + + /** + * The Highest final nonce. + */ + public HighestFinalNonce: number; + + /** + * The erd nonce. + */ + public Nonce: number; + + /** + * The nonce at epoch start. + */ + public NonceAtEpochStart: number; + + /** + * The nonces passed in current epoch. + */ + public NoncesPassedInCurrentEpoch: number; + + /** + * The round at epoch start + */ + public RoundAtEpochStart: number; + + /** + * The rounds passed in current epoch + */ + public RoundsPassedInCurrentEpoch: number; + + /** + * The rounds per epoch + */ + public RoundsPerEpoch: number; + + constructor() { + this.CurrentRound = 0; + this.EpochNumber = 0; + this.HighestFinalNonce = 0; + this.Nonce = 0; + this.NonceAtEpochStart = 0; + this.NoncesPassedInCurrentEpoch = 0; + this.RoundAtEpochStart = 0; + this.RoundsPassedInCurrentEpoch = 0; + this.RoundsPerEpoch = 0; + } + + /** + * Constructs a configuration object from a HTTP response (as returned by the provider). + */ + static fromHttpResponse(payload: any): NetworkStatus { + let networkStatus = new NetworkStatus(); + + networkStatus.CurrentRound = Number(payload["erd_current_round"]); + networkStatus.EpochNumber = Number(payload["erd_epoch_number"]); + networkStatus.HighestFinalNonce = Number(payload["erd_highest_final_nonce"]); + networkStatus.Nonce = Number(payload["erd_nonce"]); + networkStatus.NonceAtEpochStart = Number(payload["erd_nonce_at_epoch_start"]); + networkStatus.NoncesPassedInCurrentEpoch = Number(payload["erd_nonces_passed_in_current_epoch"]); + networkStatus.RoundAtEpochStart = Number(payload["erd_round_at_epoch_start"]); + networkStatus.RoundsPassedInCurrentEpoch = Number(payload["erd_rounds_passed_in_current_epoch"]); + networkStatus.RoundsPerEpoch = Number(payload["erd_rounds_per_epoch"]); + + return networkStatus; + } +} diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index 1d7ab16d..21494b1b 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -2,8 +2,7 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; import { NetworkConfig } from "../networkConfig"; -import { NetworkStake } from "../networkStake"; -import { NetworkStatus } from "../networkStatus"; +import { NetworkStake } from "./networkStake"; import { Query } from "../smartcontracts"; import { Stats } from "../stats"; import { ContractQueryResponse } from "./contractResults"; @@ -13,6 +12,7 @@ import { TransactionStatus } from "./transactionStatus"; import { Hash } from "./primitives"; import { ErrNetworkProvider } from "./errors"; import { defaultAxiosConfig } from "./config"; +import { NetworkStatus } from "./networkStatus"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ProxyNetworkProvider implements INetworkProvider { From 96220918e368b5876fc9f7433dafcc0e161c4695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Wed, 6 Apr 2022 15:02:14 +0300 Subject: [PATCH 031/133] Move "stats" to networkProvider. --- .../networkProvider/apiNetworkProvider.ts | 2 +- .../networkProvider/interface.ts | 2 +- .../networkProvider/proxyNetworkProvider.ts | 2 +- .../networkProvider/stats.ts | 69 +++++++++++++++++++ 4 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 src-network-providers/networkProvider/stats.ts diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index 3e703c24..cf2bc428 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -4,7 +4,7 @@ import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "./networkStake"; import { Query } from "../smartcontracts"; -import { Stats } from "../stats"; +import { Stats } from "./stats"; import { ContractQueryResponse } from "./contractResults"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/networkProvider/interface.ts index 1c6c98f4..121821fe 100644 --- a/src-network-providers/networkProvider/interface.ts +++ b/src-network-providers/networkProvider/interface.ts @@ -3,7 +3,7 @@ import { AccountOnNetwork } from "./accounts"; import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "./networkStake"; import { Query } from "../smartcontracts"; -import { Stats } from "../stats"; +import { Stats } from "./stats"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { NetworkStatus } from "./networkStatus"; diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index 21494b1b..9912ef4a 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -4,7 +4,7 @@ import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, import { NetworkConfig } from "../networkConfig"; import { NetworkStake } from "./networkStake"; import { Query } from "../smartcontracts"; -import { Stats } from "../stats"; +import { Stats } from "./stats"; import { ContractQueryResponse } from "./contractResults"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; diff --git a/src-network-providers/networkProvider/stats.ts b/src-network-providers/networkProvider/stats.ts new file mode 100644 index 00000000..e2c63f96 --- /dev/null +++ b/src-network-providers/networkProvider/stats.ts @@ -0,0 +1,69 @@ +/** + * An object holding Network stats parameters. + */ +export class Stats { + private static default: Stats; + + /** + * The number of Shards. + */ + public Shards: number; + + /** + * The Number of Blocks. + */ + public Blocks: number; + /** + * The Number of Accounts. + */ + public Accounts: number; + /** + * The Number of transactions. + */ + public Transactions: number; + /** + * The Refresh rate. + */ + public RefreshRate: number; + /** + * The Number of the current Epoch. + */ + public Epoch: number; + /** + * The Number of rounds passed. + */ + public RoundsPassed: number; + /** + * The Number of Rounds per epoch. + */ + public RoundsPerEpoch: number; + + constructor() { + this.Shards = 0; + this.Blocks = 0; + this.Accounts = 0; + this.Transactions = 0; + this.RefreshRate = 0; + this.Epoch = 0; + this.RoundsPassed = 0; + this.RoundsPerEpoch = 0; + } + + /** + * Constructs a stats object from a HTTP response (as returned by the provider). + */ + static fromHttpResponse(payload: any): Stats { + let stats = new Stats(); + + stats.Shards = Number(payload["shards"]); + stats.Blocks = Number(payload["blocks"]); + stats.Accounts = Number(payload["accounts"]); + stats.Transactions = Number(payload["transactions"]); + stats.RefreshRate = Number(payload["refreshRate"]); + stats.Epoch = Number(payload["epoch"]); + stats.RoundsPassed = Number(payload["roundsPassed"]); + stats.RoundsPerEpoch = Number(payload["roundsPerEpoch"]); + + return stats; + } +} From 5edfba1162efd713f9fadd55eec3db371ab6eafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Wed, 6 Apr 2022 15:45:17 +0300 Subject: [PATCH 032/133] Move "networkConfig" to networkProvider. --- .../networkProvider/apiNetworkProvider.ts | 2 +- .../networkProvider/interface.ts | 5 +- .../networkProvider/networkConfig.ts | 88 +++++++++++++++++++ .../networkProvider/proxyNetworkProvider.ts | 2 +- 4 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 src-network-providers/networkProvider/networkConfig.ts diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index cf2bc428..e25a2679 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -1,7 +1,7 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; -import { NetworkConfig } from "../networkConfig"; +import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; import { Query } from "../smartcontracts"; import { Stats } from "./stats"; diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/networkProvider/interface.ts index 121821fe..bfbc8a26 100644 --- a/src-network-providers/networkProvider/interface.ts +++ b/src-network-providers/networkProvider/interface.ts @@ -1,6 +1,6 @@ import { BigNumber } from "bignumber.js"; import { AccountOnNetwork } from "./accounts"; -import { NetworkConfig } from "../networkConfig"; +import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; import { Query } from "../smartcontracts"; import { Stats } from "./stats"; @@ -195,4 +195,7 @@ export interface INonce extends IHexable { valueOf(): number; } export interface ITransactionPayload { encoded(): string; } export interface IGasLimit { valueOf(): number; } export interface IGasPrice { valueOf(): number; } +export interface IChainID { valueOf(): string; } +export interface IGasPriceModifier { valueOf(): number; } +export interface ITransactionVersion { valueOf(): number; } export interface IAccountBalance { toString(): string; } diff --git a/src-network-providers/networkProvider/networkConfig.ts b/src-network-providers/networkProvider/networkConfig.ts new file mode 100644 index 00000000..690609c4 --- /dev/null +++ b/src-network-providers/networkProvider/networkConfig.ts @@ -0,0 +1,88 @@ +import BigNumber from "bignumber.js"; +import { IChainID, IGasLimit, IGasPrice, IGasPriceModifier, ITransactionVersion } from "./interface"; + +/** + * An object holding Network configuration parameters. + */ +export class NetworkConfig { + /** + * The chain ID. E.g. "1" for the Mainnet. + */ + public ChainID: IChainID; + + /** + * The gas required by the Network to process a byte of the {@link TransactionPayload}. + */ + public GasPerDataByte: number; + /** + * The round duration. + */ + public RoundDuration: number; + /** + * The number of rounds per epoch. + */ + public RoundsPerEpoch: number; + + /** + * The Top Up Factor for APR calculation + */ + public TopUpFactor: number; + + /** + * The Top Up Factor for APR calculation + */ + public TopUpRewardsGradientPoint: BigNumber; + + /** + * + */ + public GasPriceModifier: IGasPriceModifier; + + /** + * The minimum gas limit required to be set when broadcasting a {@link Transaction}. + */ + public MinGasLimit: IGasLimit; + + /** + * The minimum gas price required to be set when broadcasting a {@link Transaction}. + */ + public MinGasPrice: IGasPrice; + + /** + * The oldest transaction version accepted by the Network. + */ + public MinTransactionVersion: ITransactionVersion; + + constructor() { + this.ChainID = "T"; + this.GasPerDataByte = 1500; + this.TopUpFactor = 0; + this.RoundDuration = 0; + this.RoundsPerEpoch = 0; + this.TopUpRewardsGradientPoint = new BigNumber(0); + this.MinGasLimit = 50000; + this.MinGasPrice = 1000000000; + this.GasPriceModifier = 1; + this.MinTransactionVersion = 1; + } + + /** + * Constructs a configuration object from a HTTP response (as returned by the provider). + */ + static fromHttpResponse(payload: any): NetworkConfig { + let networkConfig = new NetworkConfig(); + + networkConfig.ChainID = String(payload["erd_chain_id"]); + networkConfig.GasPerDataByte = Number(payload["erd_gas_per_data_byte"]); + networkConfig.TopUpFactor = Number(payload["erd_top_up_factor"]); + networkConfig.RoundDuration = Number(payload["erd_round_duration"]); + networkConfig.RoundsPerEpoch = Number(payload["erd_rounds_per_epoch"]); + networkConfig.TopUpRewardsGradientPoint = new BigNumber(payload["erd_rewards_top_up_gradient_point"]); + networkConfig.MinGasLimit = Number(payload["erd_min_gas_limit"]); + networkConfig.MinGasPrice = Number(payload["erd_min_gas_price"]); + networkConfig.MinTransactionVersion = Number(payload["erd_min_transaction_version"]); + networkConfig.GasPriceModifier = Number(payload["erd_gas_price_modifier"]); + + return networkConfig; + } +} diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index 9912ef4a..07318e17 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -1,7 +1,7 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; -import { NetworkConfig } from "../networkConfig"; +import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; import { Query } from "../smartcontracts"; import { Stats } from "./stats"; From 10945a9599d9a1962c735750df8b8bcbc3ce83d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Wed, 6 Apr 2022 17:46:25 +0300 Subject: [PATCH 033/133] Move "queryResponse" to "networkProvider". --- .../networkProvider/apiNetworkProvider.ts | 7 +-- .../networkProvider/constants.ts | 3 + .../networkProvider/contractQueryResponse.ts | 57 +++++++++++++++++++ .../networkProvider/contractResults.ts | 29 +--------- .../networkProvider/interface.ts | 14 ++--- .../networkProvider/primitives.ts | 6 ++ .../networkProvider/proxyNetworkProvider.ts | 7 +-- 7 files changed, 79 insertions(+), 44 deletions(-) create mode 100644 src-network-providers/networkProvider/constants.ts create mode 100644 src-network-providers/networkProvider/contractQueryResponse.ts diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index e25a2679..dc9df71b 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -1,11 +1,9 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; -import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; +import { IAddress, IContractQuery, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; -import { Query } from "../smartcontracts"; import { Stats } from "./stats"; -import { ContractQueryResponse } from "./contractResults"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; @@ -15,6 +13,7 @@ import { Hash } from "./primitives"; import { ErrNetworkProvider } from "./errors"; import { defaultAxiosConfig } from "./config"; import { NetworkStatus } from "./networkStatus"; +import { ContractQueryResponse } from "./contractQueryResponse"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ApiNetworkProvider implements INetworkProvider { @@ -112,7 +111,7 @@ export class ApiNetworkProvider implements INetworkProvider { return await this.backingProxyNetworkProvider.simulateTransaction(tx); } - async queryContract(query: Query): Promise { + async queryContract(query: IContractQuery): Promise { let data = query.toHttpRequest(); let response = await this.doPostGeneric("query", data); let queryResponse = ContractQueryResponse.fromHttpResponse(response); diff --git a/src-network-providers/networkProvider/constants.ts b/src-network-providers/networkProvider/constants.ts new file mode 100644 index 00000000..404af70a --- /dev/null +++ b/src-network-providers/networkProvider/constants.ts @@ -0,0 +1,3 @@ +import BigNumber from "bignumber.js"; + +export const MaxUint64 = new BigNumber("18446744073709551615"); diff --git a/src-network-providers/networkProvider/contractQueryResponse.ts b/src-network-providers/networkProvider/contractQueryResponse.ts new file mode 100644 index 00000000..51e858d1 --- /dev/null +++ b/src-network-providers/networkProvider/contractQueryResponse.ts @@ -0,0 +1,57 @@ +import BigNumber from "bignumber.js"; +import { MaxUint64 } from "./constants"; +import { IContractReturnCode, IGasLimit } from "./interface"; +import { ContractReturnCode } from "./primitives"; + +export class ContractQueryResponse { + returnData: string[]; + returnCode: IContractReturnCode; + returnMessage: string; + gasUsed: IGasLimit; + + constructor(init?: Partial) { + this.returnData = init?.returnData || []; + this.returnCode = init?.returnCode || new ContractReturnCode(""); + this.returnMessage = init?.returnMessage || ""; + this.gasUsed = init?.gasUsed || 0; + } + + /** + * Constructs a QueryResponse object from a HTTP response (as returned by the provider). + */ + static fromHttpResponse(payload: any): ContractQueryResponse { + let returnData = payload["returnData"] || payload["ReturnData"]; + let returnCode = payload["returnCode"] || payload["ReturnCode"]; + let returnMessage = payload["returnMessage"] || payload["ReturnMessage"]; + let gasRemaining = new BigNumber(payload["gasRemaining"] || payload["GasRemaining"] || 0); + let gasUsed = new Number(MaxUint64.minus(gasRemaining).toNumber()); + + return new ContractQueryResponse({ + returnData: returnData, + returnCode: new ContractReturnCode(returnCode), + returnMessage: returnMessage, + gasUsed: gasUsed, + }); + } + + getReturnDataParts(): Buffer[] { + return this.returnData.map((item) => Buffer.from(item || "", "base64")); + } + + isSuccess(): boolean { + return this.returnCode.isSuccess(); + } + + /** + * Converts the object to a pretty, plain JavaScript object. + */ + toJSON(): object { + return { + success: this.isSuccess(), + returnData: this.returnData, + returnCode: this.returnCode, + returnMessage: this.returnMessage, + gasUsed: this.gasUsed.valueOf(), + }; + } +} diff --git a/src-network-providers/networkProvider/contractResults.ts b/src-network-providers/networkProvider/contractResults.ts index 3d9b4299..8ecfeacf 100644 --- a/src-network-providers/networkProvider/contractResults.ts +++ b/src-network-providers/networkProvider/contractResults.ts @@ -1,8 +1,6 @@ -import { BigNumber } from "bignumber.js"; -import { IAddress, IContractQueryResponse, IContractReturnCode, IGasLimit, IGasPrice, IHash, INonce } from "./interface"; +import { IAddress, IGasLimit, IGasPrice, IHash, INonce } from "./interface"; import { TransactionLogs } from "./transactionLogs"; -import { MaxUint64 } from "../smartcontracts/query"; -import { Address, ContractReturnCode, Hash, Nonce, TransactionValue } from "./primitives"; +import { Address, Hash, Nonce, TransactionValue } from "./primitives"; export class ContractResults { readonly items: ContractResultItem[]; @@ -84,26 +82,3 @@ export class ContractResultItem { return item; } } - -export class ContractQueryResponse implements IContractQueryResponse { - returnData: string[] = []; - returnCode: IContractReturnCode = new ContractReturnCode(""); - returnMessage: string = ""; - gasUsed: IGasLimit = 0; - - static fromHttpResponse(payload: any): ContractQueryResponse { - let response = new ContractQueryResponse(); - let gasRemaining = new BigNumber(payload["gasRemaining"] || payload["GasRemaining"] || 0); - - response.returnData = payload["returnData"] || []; - response.returnCode = new ContractReturnCode(payload["returnCode"] || ""); - response.returnMessage = payload["returnMessage"] || ""; - response.gasUsed = MaxUint64.minus(gasRemaining).toNumber(); - - return response; - } - - getReturnDataParts(): Buffer[] { - return this.returnData.map((item) => Buffer.from(item || "")); - } -} diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/networkProvider/interface.ts index bfbc8a26..2bcae8e6 100644 --- a/src-network-providers/networkProvider/interface.ts +++ b/src-network-providers/networkProvider/interface.ts @@ -2,11 +2,11 @@ import { BigNumber } from "bignumber.js"; import { AccountOnNetwork } from "./accounts"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; -import { Query } from "../smartcontracts"; import { Stats } from "./stats"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { NetworkStatus } from "./networkStatus"; +import { ContractQueryResponse } from "./contractQueryResponse"; /** * An interface that defines the endpoints of an HTTP API Provider. @@ -81,7 +81,7 @@ export interface INetworkProvider { /** * Queries a Smart Contract - runs a pure function defined by the contract and returns its results. */ - queryContract(query: Query): Promise; + queryContract(query: IContractQuery): Promise; /** * Fetches the definition of a fungible token. @@ -159,17 +159,13 @@ export interface IDefinitionOfTokenCollectionOnNetwork { // TODO: add "assets", "roles" } -export interface IContractQueryResponse { - returnData: string[]; - returnCode: IContractReturnCode; - returnMessage: string; - gasUsed: IGasLimit; - - getReturnDataParts(): Buffer[]; +export interface IContractQuery { + toHttpRequest(): any; } export interface IContractReturnCode { toString(): string; + isSuccess(): boolean; } export interface IContractSimulation { diff --git a/src-network-providers/networkProvider/primitives.ts b/src-network-providers/networkProvider/primitives.ts index 0adef98a..1a32caa3 100644 --- a/src-network-providers/networkProvider/primitives.ts +++ b/src-network-providers/networkProvider/primitives.ts @@ -69,6 +69,8 @@ export class TransactionPayload implements ITransactionPayload { } export class ContractReturnCode { + private static OK: string = "ok"; + private readonly value: string; constructor(value: string) { @@ -78,6 +80,10 @@ export class ContractReturnCode { toString() { return this.value; } + + isSuccess(): boolean { + return this.value == ContractReturnCode.OK; + } } export class AccountBalance { diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index 07318e17..822e8be0 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -1,11 +1,9 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; -import { IAddress, IContractQueryResponse, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; +import { IAddress, IContractQuery, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; -import { Query } from "../smartcontracts"; import { Stats } from "./stats"; -import { ContractQueryResponse } from "./contractResults"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; @@ -13,6 +11,7 @@ import { Hash } from "./primitives"; import { ErrNetworkProvider } from "./errors"; import { defaultAxiosConfig } from "./config"; import { NetworkStatus } from "./networkStatus"; +import { ContractQueryResponse } from "./contractQueryResponse"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ProxyNetworkProvider implements INetworkProvider { @@ -116,7 +115,7 @@ export class ProxyNetworkProvider implements INetworkProvider { return response; } - async queryContract(query: Query): Promise { + async queryContract(query: IContractQuery): Promise { let data = query.toHttpRequest(); let response = await this.doPostGeneric("vm-values/query", data); let queryResponse = ContractQueryResponse.fromHttpResponse(response.data); From 65e4970cace2cf685aea8cb1b6f1d829be69445e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Wed, 6 Apr 2022 18:01:23 +0300 Subject: [PATCH 034/133] Fix after review. --- src-network-providers/networkProvider/constants.ts | 2 +- .../networkProvider/contractQueryResponse.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src-network-providers/networkProvider/constants.ts b/src-network-providers/networkProvider/constants.ts index 404af70a..f4ab70a0 100644 --- a/src-network-providers/networkProvider/constants.ts +++ b/src-network-providers/networkProvider/constants.ts @@ -1,3 +1,3 @@ import BigNumber from "bignumber.js"; -export const MaxUint64 = new BigNumber("18446744073709551615"); +export const MaxUint64AsBigNumber = new BigNumber("18446744073709551615"); diff --git a/src-network-providers/networkProvider/contractQueryResponse.ts b/src-network-providers/networkProvider/contractQueryResponse.ts index 51e858d1..404d9600 100644 --- a/src-network-providers/networkProvider/contractQueryResponse.ts +++ b/src-network-providers/networkProvider/contractQueryResponse.ts @@ -1,5 +1,5 @@ import BigNumber from "bignumber.js"; -import { MaxUint64 } from "./constants"; +import { MaxUint64AsBigNumber } from "./constants"; import { IContractReturnCode, IGasLimit } from "./interface"; import { ContractReturnCode } from "./primitives"; @@ -24,7 +24,7 @@ export class ContractQueryResponse { let returnCode = payload["returnCode"] || payload["ReturnCode"]; let returnMessage = payload["returnMessage"] || payload["ReturnMessage"]; let gasRemaining = new BigNumber(payload["gasRemaining"] || payload["GasRemaining"] || 0); - let gasUsed = new Number(MaxUint64.minus(gasRemaining).toNumber()); + let gasUsed = new Number(MaxUint64AsBigNumber.minus(gasRemaining).toNumber()); return new ContractQueryResponse({ returnData: returnData, From 3a3bbfe3da602f7126a592e99e0b53a60af583db Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 6 Apr 2022 20:53:46 +0300 Subject: [PATCH 035/133] Move old providers to networkProvider package. --- .../networkProvider/apiProvider.ts | 98 ++++++++++ .../networkProvider/nftToken.ts | 63 +++++++ .../networkProvider/proxyProvider.ts | 172 ++++++++++++++++++ 3 files changed, 333 insertions(+) create mode 100644 src-network-providers/networkProvider/apiProvider.ts create mode 100644 src-network-providers/networkProvider/nftToken.ts create mode 100644 src-network-providers/networkProvider/proxyProvider.ts diff --git a/src-network-providers/networkProvider/apiProvider.ts b/src-network-providers/networkProvider/apiProvider.ts new file mode 100644 index 00000000..ed5fd849 --- /dev/null +++ b/src-network-providers/networkProvider/apiProvider.ts @@ -0,0 +1,98 @@ +import axios, { AxiosRequestConfig } from "axios"; +import { IApiProvider, IHash } from "./interface"; +import * as errors from "./errors"; +import { Logger } from "./logger"; +import { Token } from "./token"; +import { NFTToken } from "./nftToken"; +import { defaultConfig } from "./constants"; +import { ApiNetworkProvider } from "./networkProvider/apiNetworkProvider"; +import { INetworkStake, INetworkStats, ITransactionOnNetwork, ITransactionStatus } from "./interfaceOfNetwork"; + +/** + * This is a temporary change, this will be the only provider used, ProxyProvider will be deprecated + */ +export class ApiProvider implements IApiProvider { + private url: string; + private config: AxiosRequestConfig; + /** + * @deprecated used only for preparatory refactoring (unifying network providers) + */ + private readonly backingProvider: ApiNetworkProvider; + + /** + * Creates a new ApiProvider. + * @param url the URL of the Elrond Api + * @param config axios request config options + */ + constructor(url: string, config?: AxiosRequestConfig) { + this.url = url; + this.config = {...defaultConfig, ...config}; + this.backingProvider = new ApiNetworkProvider(url, config); + } + + /** + * Fetches the Network Stake. + */ + async getNetworkStake(): Promise { + return await this.backingProvider.getNetworkStakeStatistics(); + } + + /** + * Fetches the Network Stats. + */ + async getNetworkStats(): Promise { + return await this.backingProvider.getNetworkGeneralStatistics(); + } + + /** + * Fetches the state of a {@link Transaction}. + */ + async getTransaction(txHash: IHash): Promise { + return await this.backingProvider.getTransaction(txHash); + } + + /** + * Queries the status of a {@link Transaction}. + */ + async getTransactionStatus(txHash: IHash): Promise { + return await this.backingProvider.getTransactionStatus(txHash); + } + + async getToken(tokenIdentifier: string): Promise { + return this.doGetGeneric(`tokens/${tokenIdentifier}`, (response) => Token.fromHttpResponse(response)); + } + + async getNFTToken(tokenIdentifier: string): Promise { + return this.doGetGeneric(`nfts/${tokenIdentifier}`, (response) => NFTToken.fromHttpResponse(response)); + } + + /** + * Get method that receives the resource url and on callback the method used to map the response. + */ + async doGetGeneric(resourceUrl: string, callback: (response: any) => any): Promise { + let response = await this.doGet(resourceUrl); + return callback(response); + } + + private async doGet(resourceUrl: string): Promise { + try { + let url = `${this.url}/${resourceUrl}`; + let response = await axios.get(url, this.config); + + return response.data; + } catch (error) { + this.handleApiError(error, resourceUrl); + } + } + + private handleApiError(error: any, resourceUrl: string) { + if (!error.response) { + Logger.warn(error); + throw new errors.ErrApiProviderGet(resourceUrl, error.toString(), error); + } + + let errorData = error.response.data; + let originalErrorMessage = errorData.error || errorData.message || JSON.stringify(errorData); + throw new errors.ErrApiProviderGet(resourceUrl, originalErrorMessage, error); + } +} diff --git a/src-network-providers/networkProvider/nftToken.ts b/src-network-providers/networkProvider/nftToken.ts new file mode 100644 index 00000000..3132eeae --- /dev/null +++ b/src-network-providers/networkProvider/nftToken.ts @@ -0,0 +1,63 @@ + +export class NFTToken { + token: string = ''; + name: string = ''; + type: string = ''; + owner: string = ''; + minted: string = ''; + burnt: string = ''; + decimals: number = 0; + isPaused: boolean = false; + canUpgrade: boolean = false; + canMint: boolean = false; + canBurn: boolean = false; + canChangeOwner: boolean = false; + canPause: boolean = false; + canFreeze: boolean = false; + canWipe: boolean = false; + canAddSpecialRoles: boolean = false; + canTransferNFTCreateRole: boolean = false; + NFTCreateStopped: boolean = false; + wiped: string = '0'; + + constructor(init?: Partial) { + Object.assign(this, init); + } + + static fromHttpResponse(response: { + token: string, + name: string, + type: string, + owner: string, + minted: string, + burnt: string, + decimals: number, + isPaused: boolean, + canUpgrade: boolean, + canMint: boolean, + canBurn: boolean, + canChangeOwner: boolean, + canPause: boolean, + canFreeze: boolean, + canWipe: boolean, + canAddSpecialRoles: boolean, + canTransferNFTCreateRole: boolean, + NFTCreateStopped: boolean, + wiped: string + }) { + let nftToken = new NFTToken(response); + return nftToken; + } + + getTokenName() { + return this.name; + } + + getTokenIdentifier() { + return this.token; + } + + getTokenType() { + return this.type; + } +} diff --git a/src-network-providers/networkProvider/proxyProvider.ts b/src-network-providers/networkProvider/proxyProvider.ts new file mode 100644 index 00000000..a47d128d --- /dev/null +++ b/src-network-providers/networkProvider/proxyProvider.ts @@ -0,0 +1,172 @@ +import axios, { AxiosRequestConfig } from "axios"; +import BigNumber from "bignumber.js"; + +import { IHash, IProvider } from "./interface"; +import { Transaction, TransactionHash } from "./transaction"; +import { Address } from "./address"; +import * as errors from "./errors"; +import { Query } from "./smartcontracts/query"; +import { Logger } from "./logger"; +import { defaultConfig } from "./constants"; +import { ProxyNetworkProvider } from "./networkProvider/proxyNetworkProvider"; +import { IAccountOnNetwork, IContractQueryResponse, IFungibleTokenOfAccountOnNetwork, INetworkConfig, INetworkStatus, ITransactionOnNetwork, ITransactionStatus } from "./interfaceOfNetwork"; + +export class ProxyProvider implements IProvider { + private url: string; + private config: AxiosRequestConfig; + /** + * @deprecated used only for preparatory refactoring (unifying network providers) + */ + private readonly backingProvider: ProxyNetworkProvider; + + /** + * Creates a new ProxyProvider. + * @param url the URL of the Elrond Proxy + * @param config axios request config options + */ + constructor(url: string, config?: AxiosRequestConfig) { + this.url = url; + this.config = {...defaultConfig, ...config}; + this.backingProvider = new ProxyNetworkProvider(url, config); + } + + /** + * Fetches the state of an account. + */ + async getAccount(address: Address): Promise { + return await this.backingProvider.getAccount(address); + } + + async getAddressEsdtList(address: Address): Promise { + return await this.backingProvider.getFungibleTokensOfAccount(address); + } + + async getAddressEsdt(address: Address, tokenIdentifier: string): Promise { + return this.doGetGeneric(`address/${address.bech32()}/esdt/${tokenIdentifier}`, (response) => + response.tokenData + ); + } + + async getAddressNft(address: Address, tokenIdentifier: string, nonce: BigNumber): Promise { + return this.doGetGeneric(`address/${address.bech32()}/nft/${tokenIdentifier}/nonce/${nonce}`, (response) => + response.tokenData + ); + } + + /** + * Queries a Smart Contract - runs a pure function defined by the contract and returns its results. + */ + async queryContract(query: Query): Promise { + return await this.backingProvider.queryContract(query); + } + + /** + * Broadcasts an already-signed {@link Transaction}. + */ + async sendTransaction(tx: Transaction): Promise { + return await this.backingProvider.sendTransaction(tx); + } + + /** + * Simulates the processing of an already-signed {@link Transaction}. + */ + async simulateTransaction(tx: Transaction): Promise { + return await this.backingProvider.simulateTransaction(tx); + } + + /** + * Fetches the state of a {@link Transaction}. + */ + async getTransaction( + txHash: TransactionHash + ): Promise { + return await this.backingProvider.getTransaction(txHash); + } + + /** + * Queries the status of a {@link Transaction}. + */ + async getTransactionStatus(txHash: TransactionHash): Promise { + return await this.backingProvider.getTransactionStatus(txHash); + } + + /** + * Fetches the Network configuration. + */ + async getNetworkConfig(): Promise { + return await this.backingProvider.getNetworkConfig(); + } + + /** + * Fetches the network status configuration. + */ + async getNetworkStatus(): Promise { + return await this.backingProvider.getNetworkStatus(); + } + + /** + * Get method that receives the resource url and on callback the method used to map the response. + */ + async doGetGeneric(resourceUrl: string, callback: (response: any) => any): Promise { + let response = await this.doGet(resourceUrl); + return callback(response); + } + + /** + * Post method that receives the resource url, the post payload and on callback the method used to map the response. + */ + async doPostGeneric(resourceUrl: string, payload: any, callback: (response: any) => any): Promise { + let response = await this.doPost(resourceUrl, payload); + return callback(response); + } + + private async doGet(resourceUrl: string): Promise { + try { + let url = `${this.url}/${resourceUrl}`; + let response = await axios.get(url, this.config); + let payload = response.data.data; + return payload; + } catch (error) { + this.handleApiError(error, resourceUrl); + } + } + + private async doPost(resourceUrl: string, payload: any): Promise { + try { + let url = `${this.url}/${resourceUrl}`; + let response = await axios.post(url, payload, { + ...this.config, + headers: { + "Content-Type": "application/json", + }, + }); + let responsePayload = response.data.data; + return responsePayload; + } catch (error) { + this.handleApiError(error, resourceUrl); + } + } + + private buildUrlWithQueryParameters(endpoint: string, params: Record): string { + let searchParams = new URLSearchParams(); + + for (let [key, value] of Object.entries(params)) { + if (value) { + searchParams.append(key, value); + } + } + + return `${endpoint}?${searchParams.toString()}`; + } + + private handleApiError(error: any, resourceUrl: string) { + if (!error.response) { + Logger.warn(error); + throw new errors.ErrApiProviderGet(resourceUrl, error.toString(), error); + } + + let errorData = error.response.data; + let originalErrorMessage = errorData.error || errorData.message || JSON.stringify(errorData); + throw new errors.ErrApiProviderGet(resourceUrl, originalErrorMessage, error); + } +} From 97394cd70ea8ed6168f9ad870f71719bfa804933 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 7 Apr 2022 10:43:35 +0300 Subject: [PATCH 036/133] Adjust implementation of old providers. --- .../networkProvider/apiProvider.ts | 38 ++--- .../networkProvider/errors.ts | 20 +++ .../networkProvider/index.ts | 4 + .../networkProvider/proxyProvider.ts | 133 +++++------------- 4 files changed, 81 insertions(+), 114 deletions(-) diff --git a/src-network-providers/networkProvider/apiProvider.ts b/src-network-providers/networkProvider/apiProvider.ts index ed5fd849..fee35878 100644 --- a/src-network-providers/networkProvider/apiProvider.ts +++ b/src-network-providers/networkProvider/apiProvider.ts @@ -1,17 +1,19 @@ import axios, { AxiosRequestConfig } from "axios"; -import { IApiProvider, IHash } from "./interface"; +import { IHash } from "./interface"; import * as errors from "./errors"; -import { Logger } from "./logger"; -import { Token } from "./token"; import { NFTToken } from "./nftToken"; -import { defaultConfig } from "./constants"; -import { ApiNetworkProvider } from "./networkProvider/apiNetworkProvider"; -import { INetworkStake, INetworkStats, ITransactionOnNetwork, ITransactionStatus } from "./interfaceOfNetwork"; +import { defaultAxiosConfig } from "./config"; +import { ApiNetworkProvider } from "./apiNetworkProvider"; +import { TransactionOnNetwork } from "./transactions"; +import { Stats } from "./stats"; +import { NetworkStake } from "./networkStake"; +import { TransactionStatus } from "./transactionStatus"; +import { DefinitionOfFungibleTokenOnNetwork } from "./tokenDefinitions"; /** - * This is a temporary change, this will be the only provider used, ProxyProvider will be deprecated + * @deprecated */ -export class ApiProvider implements IApiProvider { +export class ApiProvider { private url: string; private config: AxiosRequestConfig; /** @@ -26,40 +28,40 @@ export class ApiProvider implements IApiProvider { */ constructor(url: string, config?: AxiosRequestConfig) { this.url = url; - this.config = {...defaultConfig, ...config}; + this.config = {...defaultAxiosConfig, ...config}; this.backingProvider = new ApiNetworkProvider(url, config); } /** * Fetches the Network Stake. */ - async getNetworkStake(): Promise { + async getNetworkStake(): Promise { return await this.backingProvider.getNetworkStakeStatistics(); } /** * Fetches the Network Stats. */ - async getNetworkStats(): Promise { + async getNetworkStats(): Promise { return await this.backingProvider.getNetworkGeneralStatistics(); } /** - * Fetches the state of a {@link Transaction}. + * Fetches the state of a transaction. */ - async getTransaction(txHash: IHash): Promise { + async getTransaction(txHash: IHash): Promise { return await this.backingProvider.getTransaction(txHash); } /** - * Queries the status of a {@link Transaction}. + * Queries the status of a transaction. */ - async getTransactionStatus(txHash: IHash): Promise { + async getTransactionStatus(txHash: IHash): Promise { return await this.backingProvider.getTransactionStatus(txHash); } - async getToken(tokenIdentifier: string): Promise { - return this.doGetGeneric(`tokens/${tokenIdentifier}`, (response) => Token.fromHttpResponse(response)); + async getToken(tokenIdentifier: string): Promise { + return await this.backingProvider.getDefinitionOfFungibleToken(tokenIdentifier); } async getNFTToken(tokenIdentifier: string): Promise { @@ -87,7 +89,7 @@ export class ApiProvider implements IApiProvider { private handleApiError(error: any, resourceUrl: string) { if (!error.response) { - Logger.warn(error); + console.warn(error); throw new errors.ErrApiProviderGet(resourceUrl, error.toString(), error); } diff --git a/src-network-providers/networkProvider/errors.ts b/src-network-providers/networkProvider/errors.ts index 586e5cf8..bed8984f 100644 --- a/src-network-providers/networkProvider/errors.ts +++ b/src-network-providers/networkProvider/errors.ts @@ -28,3 +28,23 @@ export class ErrNetworkProvider extends Err { super(message, inner); } } + +/** + * Signals an error that happened during a HTTP GET request. + */ +export class ErrApiProviderGet extends Err { + public constructor(url: string, error: string, inner?: Error) { + let message = `Cannot GET ${url}: [${error}]`; + super(message, inner); + } +} + +/** + * Signals an error that happened during a HTTP POST request. + */ +export class ErrApiProviderPost extends Err { + public constructor(url: string, error: string, inner?: Error) { + let message = `Cannot POST ${url}: [${error}]`; + super(message, inner); + } +} diff --git a/src-network-providers/networkProvider/index.ts b/src-network-providers/networkProvider/index.ts index 0c4e6aa0..0bc03d2d 100644 --- a/src-network-providers/networkProvider/index.ts +++ b/src-network-providers/networkProvider/index.ts @@ -1,5 +1,9 @@ export * from "./apiNetworkProvider"; export * from "./proxyNetworkProvider"; +// The old providers. +export * from "./proxyProvider"; +export * from "./apiProvider"; + // we do not export "./tokens" // we do not export "./transactions" diff --git a/src-network-providers/networkProvider/proxyProvider.ts b/src-network-providers/networkProvider/proxyProvider.ts index a47d128d..53ae9783 100644 --- a/src-network-providers/networkProvider/proxyProvider.ts +++ b/src-network-providers/networkProvider/proxyProvider.ts @@ -1,19 +1,20 @@ -import axios, { AxiosRequestConfig } from "axios"; +import { AxiosRequestConfig } from "axios"; import BigNumber from "bignumber.js"; - -import { IHash, IProvider } from "./interface"; -import { Transaction, TransactionHash } from "./transaction"; -import { Address } from "./address"; -import * as errors from "./errors"; -import { Query } from "./smartcontracts/query"; -import { Logger } from "./logger"; -import { defaultConfig } from "./constants"; -import { ProxyNetworkProvider } from "./networkProvider/proxyNetworkProvider"; -import { IAccountOnNetwork, IContractQueryResponse, IFungibleTokenOfAccountOnNetwork, INetworkConfig, INetworkStatus, ITransactionOnNetwork, ITransactionStatus } from "./interfaceOfNetwork"; - -export class ProxyProvider implements IProvider { - private url: string; - private config: AxiosRequestConfig; +import { IAddress, IContractQuery, IHash, ITransaction } from "./interface"; +import { ProxyNetworkProvider } from "./proxyNetworkProvider"; +import { ContractQueryResponse } from "./contractQueryResponse"; +import { AccountOnNetwork } from "./accounts"; +import { FungibleTokenOfAccountOnNetwork } from "./tokens"; +import { TransactionStatus } from "./transactionStatus"; +import { TransactionOnNetwork } from "./transactions"; +import { NetworkConfig } from "./networkConfig"; +import { NetworkStatus } from "./networkStatus"; +import { Nonce } from "./primitives"; + +/** + * @deprecated + */ +export class ProxyProvider { /** * @deprecated used only for preparatory refactoring (unifying network providers) */ @@ -25,148 +26,88 @@ export class ProxyProvider implements IProvider { * @param config axios request config options */ constructor(url: string, config?: AxiosRequestConfig) { - this.url = url; - this.config = {...defaultConfig, ...config}; this.backingProvider = new ProxyNetworkProvider(url, config); } /** * Fetches the state of an account. */ - async getAccount(address: Address): Promise { + async getAccount(address: IAddress): Promise { return await this.backingProvider.getAccount(address); } - async getAddressEsdtList(address: Address): Promise { + async getAddressEsdtList(address: IAddress): Promise { return await this.backingProvider.getFungibleTokensOfAccount(address); } - async getAddressEsdt(address: Address, tokenIdentifier: string): Promise { - return this.doGetGeneric(`address/${address.bech32()}/esdt/${tokenIdentifier}`, (response) => - response.tokenData - ); + async getAddressEsdt(address: IAddress, tokenIdentifier: string): Promise { + return await this.backingProvider.getFungibleTokenOfAccount(address, tokenIdentifier); } - async getAddressNft(address: Address, tokenIdentifier: string, nonce: BigNumber): Promise { - return this.doGetGeneric(`address/${address.bech32()}/nft/${tokenIdentifier}/nonce/${nonce}`, (response) => - response.tokenData - ); + async getAddressNft(address: IAddress, tokenIdentifier: string, nonce: BigNumber): Promise { + return await this.backingProvider.getNonFungibleTokenOfAccount(address, tokenIdentifier, new Nonce(nonce.toNumber())); } /** * Queries a Smart Contract - runs a pure function defined by the contract and returns its results. */ - async queryContract(query: Query): Promise { + async queryContract(query: IContractQuery): Promise { return await this.backingProvider.queryContract(query); } /** - * Broadcasts an already-signed {@link Transaction}. + * Broadcasts an already-signed transaction. */ - async sendTransaction(tx: Transaction): Promise { + async sendTransaction(tx: ITransaction): Promise { return await this.backingProvider.sendTransaction(tx); } /** - * Simulates the processing of an already-signed {@link Transaction}. + * Simulates the processing of an already-signed transaction. */ - async simulateTransaction(tx: Transaction): Promise { + async simulateTransaction(tx: ITransaction): Promise { return await this.backingProvider.simulateTransaction(tx); } /** - * Fetches the state of a {@link Transaction}. + * Fetches the state of a transaction. */ - async getTransaction( - txHash: TransactionHash - ): Promise { + async getTransaction(txHash: IHash): Promise { return await this.backingProvider.getTransaction(txHash); } /** - * Queries the status of a {@link Transaction}. + * Queries the status of a transaction. */ - async getTransactionStatus(txHash: TransactionHash): Promise { + async getTransactionStatus(txHash: IHash): Promise { return await this.backingProvider.getTransactionStatus(txHash); } /** * Fetches the Network configuration. */ - async getNetworkConfig(): Promise { + async getNetworkConfig(): Promise { return await this.backingProvider.getNetworkConfig(); } /** * Fetches the network status configuration. */ - async getNetworkStatus(): Promise { + async getNetworkStatus(): Promise { return await this.backingProvider.getNetworkStatus(); } /** * Get method that receives the resource url and on callback the method used to map the response. */ - async doGetGeneric(resourceUrl: string, callback: (response: any) => any): Promise { - let response = await this.doGet(resourceUrl); - return callback(response); + async doGetGeneric(resourceUrl: string): Promise { + return await this.backingProvider.doGetGeneric(resourceUrl); } /** * Post method that receives the resource url, the post payload and on callback the method used to map the response. */ - async doPostGeneric(resourceUrl: string, payload: any, callback: (response: any) => any): Promise { - let response = await this.doPost(resourceUrl, payload); - return callback(response); - } - - private async doGet(resourceUrl: string): Promise { - try { - let url = `${this.url}/${resourceUrl}`; - let response = await axios.get(url, this.config); - let payload = response.data.data; - return payload; - } catch (error) { - this.handleApiError(error, resourceUrl); - } - } - - private async doPost(resourceUrl: string, payload: any): Promise { - try { - let url = `${this.url}/${resourceUrl}`; - let response = await axios.post(url, payload, { - ...this.config, - headers: { - "Content-Type": "application/json", - }, - }); - let responsePayload = response.data.data; - return responsePayload; - } catch (error) { - this.handleApiError(error, resourceUrl); - } - } - - private buildUrlWithQueryParameters(endpoint: string, params: Record): string { - let searchParams = new URLSearchParams(); - - for (let [key, value] of Object.entries(params)) { - if (value) { - searchParams.append(key, value); - } - } - - return `${endpoint}?${searchParams.toString()}`; - } - - private handleApiError(error: any, resourceUrl: string) { - if (!error.response) { - Logger.warn(error); - throw new errors.ErrApiProviderGet(resourceUrl, error.toString(), error); - } - - let errorData = error.response.data; - let originalErrorMessage = errorData.error || errorData.message || JSON.stringify(errorData); - throw new errors.ErrApiProviderGet(resourceUrl, originalErrorMessage, error); + async doPostGeneric(resourceUrl: string, payload: any): Promise { + return await this.backingProvider.doPostGeneric(resourceUrl, payload); } } From 1a49eb613b605a1cf28a47b2b4e595276dfd4206 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 7 Apr 2022 10:49:43 +0300 Subject: [PATCH 037/133] Rename files. --- ...piProvider.ts => deprecatedApiProvider.ts} | 2 +- ...Provider.ts => deprecatedProxyProvider.ts} | 40 +------------------ .../networkProvider/index.ts | 4 +- 3 files changed, 4 insertions(+), 42 deletions(-) rename src-network-providers/networkProvider/{apiProvider.ts => deprecatedApiProvider.ts} (98%) rename src-network-providers/networkProvider/{proxyProvider.ts => deprecatedProxyProvider.ts} (72%) diff --git a/src-network-providers/networkProvider/apiProvider.ts b/src-network-providers/networkProvider/deprecatedApiProvider.ts similarity index 98% rename from src-network-providers/networkProvider/apiProvider.ts rename to src-network-providers/networkProvider/deprecatedApiProvider.ts index fee35878..12246b25 100644 --- a/src-network-providers/networkProvider/apiProvider.ts +++ b/src-network-providers/networkProvider/deprecatedApiProvider.ts @@ -13,7 +13,7 @@ import { DefinitionOfFungibleTokenOnNetwork } from "./tokenDefinitions"; /** * @deprecated */ -export class ApiProvider { +export class DeprecatedApiProvider { private url: string; private config: AxiosRequestConfig; /** diff --git a/src-network-providers/networkProvider/proxyProvider.ts b/src-network-providers/networkProvider/deprecatedProxyProvider.ts similarity index 72% rename from src-network-providers/networkProvider/proxyProvider.ts rename to src-network-providers/networkProvider/deprecatedProxyProvider.ts index 53ae9783..e1ba0ca4 100644 --- a/src-network-providers/networkProvider/proxyProvider.ts +++ b/src-network-providers/networkProvider/deprecatedProxyProvider.ts @@ -14,24 +14,13 @@ import { Nonce } from "./primitives"; /** * @deprecated */ -export class ProxyProvider { - /** - * @deprecated used only for preparatory refactoring (unifying network providers) - */ +export class DeprecatedProxyProvider { private readonly backingProvider: ProxyNetworkProvider; - /** - * Creates a new ProxyProvider. - * @param url the URL of the Elrond Proxy - * @param config axios request config options - */ constructor(url: string, config?: AxiosRequestConfig) { this.backingProvider = new ProxyNetworkProvider(url, config); } - /** - * Fetches the state of an account. - */ async getAccount(address: IAddress): Promise { return await this.backingProvider.getAccount(address); } @@ -48,65 +37,38 @@ export class ProxyProvider { return await this.backingProvider.getNonFungibleTokenOfAccount(address, tokenIdentifier, new Nonce(nonce.toNumber())); } - /** - * Queries a Smart Contract - runs a pure function defined by the contract and returns its results. - */ async queryContract(query: IContractQuery): Promise { return await this.backingProvider.queryContract(query); } - /** - * Broadcasts an already-signed transaction. - */ async sendTransaction(tx: ITransaction): Promise { return await this.backingProvider.sendTransaction(tx); } - /** - * Simulates the processing of an already-signed transaction. - */ async simulateTransaction(tx: ITransaction): Promise { return await this.backingProvider.simulateTransaction(tx); } - /** - * Fetches the state of a transaction. - */ async getTransaction(txHash: IHash): Promise { return await this.backingProvider.getTransaction(txHash); } - /** - * Queries the status of a transaction. - */ async getTransactionStatus(txHash: IHash): Promise { return await this.backingProvider.getTransactionStatus(txHash); } - /** - * Fetches the Network configuration. - */ async getNetworkConfig(): Promise { return await this.backingProvider.getNetworkConfig(); } - /** - * Fetches the network status configuration. - */ async getNetworkStatus(): Promise { return await this.backingProvider.getNetworkStatus(); } - /** - * Get method that receives the resource url and on callback the method used to map the response. - */ async doGetGeneric(resourceUrl: string): Promise { return await this.backingProvider.doGetGeneric(resourceUrl); } - /** - * Post method that receives the resource url, the post payload and on callback the method used to map the response. - */ async doPostGeneric(resourceUrl: string, payload: any): Promise { return await this.backingProvider.doPostGeneric(resourceUrl, payload); } diff --git a/src-network-providers/networkProvider/index.ts b/src-network-providers/networkProvider/index.ts index 0bc03d2d..111212f9 100644 --- a/src-network-providers/networkProvider/index.ts +++ b/src-network-providers/networkProvider/index.ts @@ -2,8 +2,8 @@ export * from "./apiNetworkProvider"; export * from "./proxyNetworkProvider"; // The old providers. -export * from "./proxyProvider"; -export * from "./apiProvider"; +export * from "./deprecatedProxyProvider"; +export * from "./deprecatedApiProvider"; // we do not export "./tokens" // we do not export "./transactions" From c451acf3582f9caaffab5a30f4bff60e51b462cc Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 7 Apr 2022 11:08:20 +0300 Subject: [PATCH 038/133] Remove deprecated API provider. --- .../networkProvider/deprecatedApiProvider.ts | 100 ------------------ .../networkProvider/index.ts | 1 - .../networkProvider/nftToken.ts | 63 ----------- 3 files changed, 164 deletions(-) delete mode 100644 src-network-providers/networkProvider/deprecatedApiProvider.ts delete mode 100644 src-network-providers/networkProvider/nftToken.ts diff --git a/src-network-providers/networkProvider/deprecatedApiProvider.ts b/src-network-providers/networkProvider/deprecatedApiProvider.ts deleted file mode 100644 index 12246b25..00000000 --- a/src-network-providers/networkProvider/deprecatedApiProvider.ts +++ /dev/null @@ -1,100 +0,0 @@ -import axios, { AxiosRequestConfig } from "axios"; -import { IHash } from "./interface"; -import * as errors from "./errors"; -import { NFTToken } from "./nftToken"; -import { defaultAxiosConfig } from "./config"; -import { ApiNetworkProvider } from "./apiNetworkProvider"; -import { TransactionOnNetwork } from "./transactions"; -import { Stats } from "./stats"; -import { NetworkStake } from "./networkStake"; -import { TransactionStatus } from "./transactionStatus"; -import { DefinitionOfFungibleTokenOnNetwork } from "./tokenDefinitions"; - -/** - * @deprecated - */ -export class DeprecatedApiProvider { - private url: string; - private config: AxiosRequestConfig; - /** - * @deprecated used only for preparatory refactoring (unifying network providers) - */ - private readonly backingProvider: ApiNetworkProvider; - - /** - * Creates a new ApiProvider. - * @param url the URL of the Elrond Api - * @param config axios request config options - */ - constructor(url: string, config?: AxiosRequestConfig) { - this.url = url; - this.config = {...defaultAxiosConfig, ...config}; - this.backingProvider = new ApiNetworkProvider(url, config); - } - - /** - * Fetches the Network Stake. - */ - async getNetworkStake(): Promise { - return await this.backingProvider.getNetworkStakeStatistics(); - } - - /** - * Fetches the Network Stats. - */ - async getNetworkStats(): Promise { - return await this.backingProvider.getNetworkGeneralStatistics(); - } - - /** - * Fetches the state of a transaction. - */ - async getTransaction(txHash: IHash): Promise { - return await this.backingProvider.getTransaction(txHash); - } - - /** - * Queries the status of a transaction. - */ - async getTransactionStatus(txHash: IHash): Promise { - return await this.backingProvider.getTransactionStatus(txHash); - } - - async getToken(tokenIdentifier: string): Promise { - return await this.backingProvider.getDefinitionOfFungibleToken(tokenIdentifier); - } - - async getNFTToken(tokenIdentifier: string): Promise { - return this.doGetGeneric(`nfts/${tokenIdentifier}`, (response) => NFTToken.fromHttpResponse(response)); - } - - /** - * Get method that receives the resource url and on callback the method used to map the response. - */ - async doGetGeneric(resourceUrl: string, callback: (response: any) => any): Promise { - let response = await this.doGet(resourceUrl); - return callback(response); - } - - private async doGet(resourceUrl: string): Promise { - try { - let url = `${this.url}/${resourceUrl}`; - let response = await axios.get(url, this.config); - - return response.data; - } catch (error) { - this.handleApiError(error, resourceUrl); - } - } - - private handleApiError(error: any, resourceUrl: string) { - if (!error.response) { - console.warn(error); - throw new errors.ErrApiProviderGet(resourceUrl, error.toString(), error); - } - - let errorData = error.response.data; - let originalErrorMessage = errorData.error || errorData.message || JSON.stringify(errorData); - throw new errors.ErrApiProviderGet(resourceUrl, originalErrorMessage, error); - } -} diff --git a/src-network-providers/networkProvider/index.ts b/src-network-providers/networkProvider/index.ts index 111212f9..035453f6 100644 --- a/src-network-providers/networkProvider/index.ts +++ b/src-network-providers/networkProvider/index.ts @@ -3,7 +3,6 @@ export * from "./proxyNetworkProvider"; // The old providers. export * from "./deprecatedProxyProvider"; -export * from "./deprecatedApiProvider"; // we do not export "./tokens" // we do not export "./transactions" diff --git a/src-network-providers/networkProvider/nftToken.ts b/src-network-providers/networkProvider/nftToken.ts deleted file mode 100644 index 3132eeae..00000000 --- a/src-network-providers/networkProvider/nftToken.ts +++ /dev/null @@ -1,63 +0,0 @@ - -export class NFTToken { - token: string = ''; - name: string = ''; - type: string = ''; - owner: string = ''; - minted: string = ''; - burnt: string = ''; - decimals: number = 0; - isPaused: boolean = false; - canUpgrade: boolean = false; - canMint: boolean = false; - canBurn: boolean = false; - canChangeOwner: boolean = false; - canPause: boolean = false; - canFreeze: boolean = false; - canWipe: boolean = false; - canAddSpecialRoles: boolean = false; - canTransferNFTCreateRole: boolean = false; - NFTCreateStopped: boolean = false; - wiped: string = '0'; - - constructor(init?: Partial) { - Object.assign(this, init); - } - - static fromHttpResponse(response: { - token: string, - name: string, - type: string, - owner: string, - minted: string, - burnt: string, - decimals: number, - isPaused: boolean, - canUpgrade: boolean, - canMint: boolean, - canBurn: boolean, - canChangeOwner: boolean, - canPause: boolean, - canFreeze: boolean, - canWipe: boolean, - canAddSpecialRoles: boolean, - canTransferNFTCreateRole: boolean, - NFTCreateStopped: boolean, - wiped: string - }) { - let nftToken = new NFTToken(response); - return nftToken; - } - - getTokenName() { - return this.name; - } - - getTokenIdentifier() { - return this.token; - } - - getTokenType() { - return this.type; - } -} From 669dbe57b66a0549d0f9811dee295e41cc9d5d03 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 7 Apr 2022 11:08:35 +0300 Subject: [PATCH 039/133] Add missing fields on NFT token. --- .../networkProvider/interface.ts | 9 +++++++- .../networkProvider/tokens.ts | 23 +++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/networkProvider/interface.ts index 2bcae8e6..4a3913a2 100644 --- a/src-network-providers/networkProvider/interface.ts +++ b/src-network-providers/networkProvider/interface.ts @@ -119,11 +119,18 @@ export interface IFungibleTokenOfAccountOnNetwork { export interface INonFungibleTokenOfAccountOnNetwork { identifier: string; collection: string; + timestamp: number; attributes: Buffer; - balance: BigNumber; nonce: INonce; + type: string; + name: string; creator: IAddress; + isWhitelistedStorage: boolean; + supply: BigNumber; + decimals: number; royalties: BigNumber; + ticker: string; + assets: string[]; } diff --git a/src-network-providers/networkProvider/tokens.ts b/src-network-providers/networkProvider/tokens.ts index 3223f178..d089c9ed 100644 --- a/src-network-providers/networkProvider/tokens.ts +++ b/src-network-providers/networkProvider/tokens.ts @@ -19,11 +19,22 @@ export class FungibleTokenOfAccountOnNetwork implements IFungibleTokenOfAccountO export class NonFungibleTokenOfAccountOnNetwork implements INonFungibleTokenOfAccountOnNetwork { identifier: string = ""; collection: string = ""; + timestamp: number = 0; attributes: Buffer = Buffer.from([]); - balance: BigNumber = new BigNumber(0); nonce: INonce = new Nonce(0); + type: string = ""; + name: string = ""; creator: IAddress = new Address(""); + isWhitelistedStorage: boolean = false; + supply: BigNumber = new BigNumber(0); + decimals: number = 0; royalties: BigNumber = new BigNumber(0); + ticker: string = ""; + assets: string[] = []; + + constructor(init?: Partial) { + Object.assign(this, init); + } static fromProxyHttpResponse(payload: any): NonFungibleTokenOfAccountOnNetwork { let result = NonFungibleTokenOfAccountOnNetwork.fromHttpResponse(payload); @@ -54,14 +65,22 @@ export class NonFungibleTokenOfAccountOnNetwork implements INonFungibleTokenOfAc return result; } + // TODO: Compare results from Proxy and API and try to reconciliate them. private static fromHttpResponse(payload: any): NonFungibleTokenOfAccountOnNetwork { let result = new NonFungibleTokenOfAccountOnNetwork(); + result.timestamp = Number(payload.timestamp || 0); result.attributes = Buffer.from(payload.attributes || "", "base64"); - result.balance = new BigNumber(payload.balance || 1); result.nonce = new Nonce(payload.nonce || 0); + result.type = payload.type || ""; + result.name = payload.name || ""; result.creator = new Address(payload.creator || ""); + result.isWhitelistedStorage = payload.isWhitelistedStorage || false; + result.decimals = Number(payload.decimals || 0); + result.supply = new BigNumber(payload.balance || 1); result.royalties = new BigNumber(payload.royalties || 0); + result.ticker = payload.ticker || ""; + result.assets = payload.assets || []; return result; } From a66f6a0dc748b2dcc1ef009ceb5f7212272f2fd0 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 7 Apr 2022 11:25:35 +0300 Subject: [PATCH 040/133] Move deprecated proxy provider to contractWrappers (it depends on it). --- .../deprecatedProxyProvider.ts | 75 ------------------- .../networkProvider/index.ts | 3 - 2 files changed, 78 deletions(-) delete mode 100644 src-network-providers/networkProvider/deprecatedProxyProvider.ts diff --git a/src-network-providers/networkProvider/deprecatedProxyProvider.ts b/src-network-providers/networkProvider/deprecatedProxyProvider.ts deleted file mode 100644 index e1ba0ca4..00000000 --- a/src-network-providers/networkProvider/deprecatedProxyProvider.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { AxiosRequestConfig } from "axios"; -import BigNumber from "bignumber.js"; -import { IAddress, IContractQuery, IHash, ITransaction } from "./interface"; -import { ProxyNetworkProvider } from "./proxyNetworkProvider"; -import { ContractQueryResponse } from "./contractQueryResponse"; -import { AccountOnNetwork } from "./accounts"; -import { FungibleTokenOfAccountOnNetwork } from "./tokens"; -import { TransactionStatus } from "./transactionStatus"; -import { TransactionOnNetwork } from "./transactions"; -import { NetworkConfig } from "./networkConfig"; -import { NetworkStatus } from "./networkStatus"; -import { Nonce } from "./primitives"; - -/** - * @deprecated - */ -export class DeprecatedProxyProvider { - private readonly backingProvider: ProxyNetworkProvider; - - constructor(url: string, config?: AxiosRequestConfig) { - this.backingProvider = new ProxyNetworkProvider(url, config); - } - - async getAccount(address: IAddress): Promise { - return await this.backingProvider.getAccount(address); - } - - async getAddressEsdtList(address: IAddress): Promise { - return await this.backingProvider.getFungibleTokensOfAccount(address); - } - - async getAddressEsdt(address: IAddress, tokenIdentifier: string): Promise { - return await this.backingProvider.getFungibleTokenOfAccount(address, tokenIdentifier); - } - - async getAddressNft(address: IAddress, tokenIdentifier: string, nonce: BigNumber): Promise { - return await this.backingProvider.getNonFungibleTokenOfAccount(address, tokenIdentifier, new Nonce(nonce.toNumber())); - } - - async queryContract(query: IContractQuery): Promise { - return await this.backingProvider.queryContract(query); - } - - async sendTransaction(tx: ITransaction): Promise { - return await this.backingProvider.sendTransaction(tx); - } - - async simulateTransaction(tx: ITransaction): Promise { - return await this.backingProvider.simulateTransaction(tx); - } - - async getTransaction(txHash: IHash): Promise { - return await this.backingProvider.getTransaction(txHash); - } - - async getTransactionStatus(txHash: IHash): Promise { - return await this.backingProvider.getTransactionStatus(txHash); - } - - async getNetworkConfig(): Promise { - return await this.backingProvider.getNetworkConfig(); - } - - async getNetworkStatus(): Promise { - return await this.backingProvider.getNetworkStatus(); - } - - async doGetGeneric(resourceUrl: string): Promise { - return await this.backingProvider.doGetGeneric(resourceUrl); - } - - async doPostGeneric(resourceUrl: string, payload: any): Promise { - return await this.backingProvider.doPostGeneric(resourceUrl, payload); - } -} diff --git a/src-network-providers/networkProvider/index.ts b/src-network-providers/networkProvider/index.ts index 035453f6..0c4e6aa0 100644 --- a/src-network-providers/networkProvider/index.ts +++ b/src-network-providers/networkProvider/index.ts @@ -1,8 +1,5 @@ export * from "./apiNetworkProvider"; export * from "./proxyNetworkProvider"; -// The old providers. -export * from "./deprecatedProxyProvider"; - // we do not export "./tokens" // we do not export "./transactions" From 0b964bbdb0d8e9d0e4e3330d3095dc7c81bd7614 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 7 Apr 2022 11:43:19 +0300 Subject: [PATCH 041/133] Remove some interfaces. --- .../networkProvider/apiNetworkProvider.ts | 16 ++--- .../networkProvider/interface.ts | 72 +++---------------- .../networkProvider/proxyNetworkProvider.ts | 17 ++--- .../networkProvider/tokenDefinitions.ts | 6 +- .../networkProvider/tokens.ts | 6 +- 5 files changed, 32 insertions(+), 85 deletions(-) diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index dc9df71b..f8e407b7 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -1,6 +1,6 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; -import { IAddress, IContractQuery, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; +import { IAddress, IContractQuery, IHash, INetworkProvider, INonce, ITransaction, Pagination } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; import { Stats } from "./stats"; @@ -53,7 +53,7 @@ export class ApiNetworkProvider implements INetworkProvider { return account; } - async getFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise { + async getFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise { pagination = pagination || Pagination.default(); let url = `accounts/${address.bech32()}/tokens?${this.buildPaginationParams(pagination)}`; @@ -65,7 +65,7 @@ export class ApiNetworkProvider implements INetworkProvider { return tokens; } - async getNonFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise { + async getNonFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise { pagination = pagination || Pagination.default(); let url = `accounts/${address.bech32()}/nfts?${this.buildPaginationParams(pagination)}`; @@ -77,13 +77,13 @@ export class ApiNetworkProvider implements INetworkProvider { return tokens; } - async getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise { + async getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise { let response = await this.doGetGeneric(`accounts/${address.bech32()}/tokens/${tokenIdentifier}`); let tokenData = FungibleTokenOfAccountOnNetwork.fromHttpResponse(response); return tokenData; } - async getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: INonce): Promise { + async getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: INonce): Promise { let response = await this.doGetGeneric(`accounts/${address.bech32()}/nfts/${collection}-${nonce.hex()}`); let tokenData = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response); return tokenData; @@ -118,19 +118,19 @@ export class ApiNetworkProvider implements INetworkProvider { return queryResponse; } - async getDefinitionOfFungibleToken(tokenIdentifier: string): Promise { + async getDefinitionOfFungibleToken(tokenIdentifier: string): Promise { let response = await this.doGetGeneric(`tokens/${tokenIdentifier}`); let definition = DefinitionOfFungibleTokenOnNetwork.fromApiHttpResponse(response); return definition; } - async getDefinitionOfTokenCollection(collection: string): Promise { + async getDefinitionOfTokenCollection(collection: string): Promise { let response = await this.doGetGeneric(`collections/${collection}`); let definition = DefinitionOfTokenCollectionOnNetwork.fromApiHttpResponse(response); return definition; } - async getNonFungibleToken(collection: string, nonce: INonce): Promise { + async getNonFungibleToken(collection: string, nonce: INonce): Promise { let response = await this.doGetGeneric(`nfts/${collection}-${nonce.hex()}`); let token = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response); return token; diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/networkProvider/interface.ts index 4a3913a2..762c9504 100644 --- a/src-network-providers/networkProvider/interface.ts +++ b/src-network-providers/networkProvider/interface.ts @@ -1,4 +1,3 @@ -import { BigNumber } from "bignumber.js"; import { AccountOnNetwork } from "./accounts"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; @@ -7,6 +6,8 @@ import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { NetworkStatus } from "./networkStatus"; import { ContractQueryResponse } from "./contractQueryResponse"; +import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; +import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; /** * An interface that defines the endpoints of an HTTP API Provider. @@ -40,22 +41,22 @@ export interface INetworkProvider { /** * Fetches data about the fungible tokens held by an account. */ - getFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise; + getFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise; /** * Fetches data about the non-fungible tokens held by account. */ - getNonFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise; + getNonFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise; /** * Fetches data about a specific fungible token held by an account. */ - getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise; + getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise; /** * Fetches data about a specific non-fungible token (instance) held by an account. */ - getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: INonce): Promise; + getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: INonce): Promise; /** * Fetches the state of a {@link Transaction}. @@ -87,18 +88,18 @@ export interface INetworkProvider { * Fetches the definition of a fungible token. * */ - getDefinitionOfFungibleToken(tokenIdentifier: string): Promise; + getDefinitionOfFungibleToken(tokenIdentifier: string): Promise; /** * Fetches the definition of a SFT (including Meta ESDT) or NFT. * */ - getDefinitionOfTokenCollection(collection: string): Promise; + getDefinitionOfTokenCollection(collection: string): Promise; /** * Fetches data about a specific non-fungible token (instance). */ - getNonFungibleToken(collection: string, nonce: INonce): Promise; + getNonFungibleToken(collection: string, nonce: INonce): Promise; /** * Performs a generic GET action against the provider (useful for new HTTP endpoints, not yet supported by erdjs). @@ -111,61 +112,6 @@ export interface INetworkProvider { doPostGeneric(resourceUrl: string, payload: any): Promise; } -export interface IFungibleTokenOfAccountOnNetwork { - identifier: string; - balance: BigNumber; -} - -export interface INonFungibleTokenOfAccountOnNetwork { - identifier: string; - collection: string; - timestamp: number; - attributes: Buffer; - nonce: INonce; - type: string; - name: string; - creator: IAddress; - isWhitelistedStorage: boolean; - supply: BigNumber; - decimals: number; - royalties: BigNumber; - ticker: string; - assets: string[]; -} - - -export interface IDefinitionOfFungibleTokenOnNetwork { - identifier: string; - name: string; - ticker: string; - owner: IAddress; - decimals: number; - supply: BigNumber; - isPaused: boolean; - canUpgrade: boolean; - canMint: boolean; - canBurn: boolean; - canChangeOwner: boolean; - canPause: boolean; - canFreeze: boolean; - canWipe: boolean; - canAddSpecialRoles: boolean; -} - -export interface IDefinitionOfTokenCollectionOnNetwork { - collection: string; - type: string; - name: string; - ticker: string; - owner: IAddress; - decimals: number; - canPause: boolean; - canFreeze: boolean; - canWipe: boolean; - canTransferRole: boolean; - // TODO: add "assets", "roles" -} - export interface IContractQuery { toHttpRequest(): any; } diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index 822e8be0..a24dde7d 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -1,6 +1,6 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; -import { IAddress, IContractQuery, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork, IFungibleTokenOfAccountOnNetwork, IHash, INetworkProvider, INonce, INonFungibleTokenOfAccountOnNetwork, ITransaction, Pagination } from "./interface"; +import { IAddress, IContractQuery, IHash, INetworkProvider, INonce, ITransaction, Pagination } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; import { Stats } from "./stats"; @@ -12,6 +12,7 @@ import { ErrNetworkProvider } from "./errors"; import { defaultAxiosConfig } from "./config"; import { NetworkStatus } from "./networkStatus"; import { ContractQueryResponse } from "./contractQueryResponse"; +import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ProxyNetworkProvider implements INetworkProvider { @@ -53,7 +54,7 @@ export class ProxyNetworkProvider implements INetworkProvider { return account; } - async getFungibleTokensOfAccount(address: IAddress, _pagination?: Pagination): Promise { + async getFungibleTokensOfAccount(address: IAddress, _pagination?: Pagination): Promise { let url = `address/${address.bech32()}/esdt`; let response = await this.doGetGeneric(url); let responseItems: any[] = Object.values(response.esdts); @@ -66,7 +67,7 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokens; } - async getNonFungibleTokensOfAccount(address: IAddress, _pagination?: Pagination): Promise { + async getNonFungibleTokensOfAccount(address: IAddress, _pagination?: Pagination): Promise { let url = `address/${address.bech32()}/esdt`; let response = await this.doGetGeneric(url); let responseItems: any[] = Object.values(response.esdts); @@ -79,13 +80,13 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokens; } - async getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise { + async getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise { let response = await this.doGetGeneric(`address/${address.bech32()}/esdt/${tokenIdentifier}`); let tokenData = FungibleTokenOfAccountOnNetwork.fromHttpResponse(response.tokenData); return tokenData; } - async getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: INonce): Promise { + async getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: INonce): Promise { let response = await this.doGetGeneric(`address/${address.bech32()}/nft/${collection}/nonce/${nonce.valueOf()}`); let tokenData = NonFungibleTokenOfAccountOnNetwork.fromProxyHttpResponseByNonce(response.tokenData); return tokenData; @@ -122,20 +123,20 @@ export class ProxyNetworkProvider implements INetworkProvider { return queryResponse; } - async getDefinitionOfFungibleToken(_tokenIdentifier: string): Promise { + async getDefinitionOfFungibleToken(_tokenIdentifier: string): Promise { // TODO: Implement wrt.: // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/esdt/esdt.service.ts#L221 throw new Error("Method not implemented."); } - async getDefinitionOfTokenCollection(_collection: string): Promise { + async getDefinitionOfTokenCollection(_collection: string): Promise { // TODO: Implement wrt.: // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/collections/collection.service.ts // https://docs.elrond.com/developers/esdt-tokens/#get-esdt-token-properties throw new Error("Method not implemented."); } - async getNonFungibleToken(_collection: string, _nonce: INonce): Promise { + async getNonFungibleToken(_collection: string, _nonce: INonce): Promise { throw new Error("Method not implemented."); } diff --git a/src-network-providers/networkProvider/tokenDefinitions.ts b/src-network-providers/networkProvider/tokenDefinitions.ts index c1064485..0a7f156d 100644 --- a/src-network-providers/networkProvider/tokenDefinitions.ts +++ b/src-network-providers/networkProvider/tokenDefinitions.ts @@ -1,8 +1,8 @@ import { BigNumber } from "bignumber.js"; import { Address } from "./primitives"; -import { IAddress, IDefinitionOfFungibleTokenOnNetwork, IDefinitionOfTokenCollectionOnNetwork } from "./interface"; +import { IAddress } from "./interface"; -export class DefinitionOfFungibleTokenOnNetwork implements IDefinitionOfFungibleTokenOnNetwork { +export class DefinitionOfFungibleTokenOnNetwork { identifier: string = ""; name: string = ""; ticker: string = ""; @@ -42,7 +42,7 @@ export class DefinitionOfFungibleTokenOnNetwork implements IDefinitionOfFungible } } -export class DefinitionOfTokenCollectionOnNetwork implements IDefinitionOfTokenCollectionOnNetwork { +export class DefinitionOfTokenCollectionOnNetwork { collection: string = ""; type: string = ""; name: string = ""; diff --git a/src-network-providers/networkProvider/tokens.ts b/src-network-providers/networkProvider/tokens.ts index d089c9ed..6e167028 100644 --- a/src-network-providers/networkProvider/tokens.ts +++ b/src-network-providers/networkProvider/tokens.ts @@ -1,8 +1,8 @@ import { BigNumber } from "bignumber.js"; import { Address, Nonce } from "./primitives"; -import { IAddress, IFungibleTokenOfAccountOnNetwork, INonce, INonFungibleTokenOfAccountOnNetwork } from "./interface"; +import { IAddress, INonce } from "./interface"; -export class FungibleTokenOfAccountOnNetwork implements IFungibleTokenOfAccountOnNetwork { +export class FungibleTokenOfAccountOnNetwork { identifier: string = ""; balance: BigNumber = new BigNumber(0); @@ -16,7 +16,7 @@ export class FungibleTokenOfAccountOnNetwork implements IFungibleTokenOfAccountO } } -export class NonFungibleTokenOfAccountOnNetwork implements INonFungibleTokenOfAccountOnNetwork { +export class NonFungibleTokenOfAccountOnNetwork { identifier: string = ""; collection: string = ""; timestamp: number = 0; From bb34980c2effe0e3239cd234edd2a4d0a85842b8 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 7 Apr 2022 11:51:45 +0300 Subject: [PATCH 042/133] More specific error for vm queries (as before). --- .../networkProvider/apiNetworkProvider.ts | 12 +++++++----- .../networkProvider/errors.ts | 18 ++++-------------- .../networkProvider/proxyNetworkProvider.ts | 12 +++++++----- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/networkProvider/apiNetworkProvider.ts index f8e407b7..5438c4d2 100644 --- a/src-network-providers/networkProvider/apiNetworkProvider.ts +++ b/src-network-providers/networkProvider/apiNetworkProvider.ts @@ -10,7 +10,7 @@ import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } f import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { Hash } from "./primitives"; -import { ErrNetworkProvider } from "./errors"; +import { ErrContractQuery, ErrNetworkProvider } from "./errors"; import { defaultAxiosConfig } from "./config"; import { NetworkStatus } from "./networkStatus"; import { ContractQueryResponse } from "./contractQueryResponse"; @@ -112,10 +112,12 @@ export class ApiNetworkProvider implements INetworkProvider { } async queryContract(query: IContractQuery): Promise { - let data = query.toHttpRequest(); - let response = await this.doPostGeneric("query", data); - let queryResponse = ContractQueryResponse.fromHttpResponse(response); - return queryResponse; + try { + let response = await this.doPostGeneric("query", query.toHttpRequest()); + return ContractQueryResponse.fromHttpResponse(response); + } catch (error: any) { + throw new ErrContractQuery(error); + } } async getDefinitionOfFungibleToken(tokenIdentifier: string): Promise { diff --git a/src-network-providers/networkProvider/errors.ts b/src-network-providers/networkProvider/errors.ts index bed8984f..73882ecd 100644 --- a/src-network-providers/networkProvider/errors.ts +++ b/src-network-providers/networkProvider/errors.ts @@ -29,22 +29,12 @@ export class ErrNetworkProvider extends Err { } } -/** - * Signals an error that happened during a HTTP GET request. - */ -export class ErrApiProviderGet extends Err { - public constructor(url: string, error: string, inner?: Error) { - let message = `Cannot GET ${url}: [${error}]`; - super(message, inner); - } -} /** - * Signals an error that happened during a HTTP POST request. + * Signals a generic error in the context of querying Smart Contracts. */ -export class ErrApiProviderPost extends Err { - public constructor(url: string, error: string, inner?: Error) { - let message = `Cannot POST ${url}: [${error}]`; - super(message, inner); +export class ErrContractQuery extends Err { + public constructor(originalError: Error) { + super(originalError.message.replace("executeQuery:", "")); } } diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/networkProvider/proxyNetworkProvider.ts index a24dde7d..9313d045 100644 --- a/src-network-providers/networkProvider/proxyNetworkProvider.ts +++ b/src-network-providers/networkProvider/proxyNetworkProvider.ts @@ -8,7 +8,7 @@ import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } f import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { Hash } from "./primitives"; -import { ErrNetworkProvider } from "./errors"; +import { ErrContractQuery, ErrNetworkProvider } from "./errors"; import { defaultAxiosConfig } from "./config"; import { NetworkStatus } from "./networkStatus"; import { ContractQueryResponse } from "./contractQueryResponse"; @@ -117,10 +117,12 @@ export class ProxyNetworkProvider implements INetworkProvider { } async queryContract(query: IContractQuery): Promise { - let data = query.toHttpRequest(); - let response = await this.doPostGeneric("vm-values/query", data); - let queryResponse = ContractQueryResponse.fromHttpResponse(response.data); - return queryResponse; + try { + let response = await this.doPostGeneric("vm-values/query", query.toHttpRequest()); + return ContractQueryResponse.fromHttpResponse(response.data); + } catch (error: any) { + throw new ErrContractQuery(error); + } } async getDefinitionOfFungibleToken(_tokenIdentifier: string): Promise { From 3944eaaf773e4ae953326d6e14d914ba1042e9ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 7 Apr 2022 15:37:47 +0300 Subject: [PATCH 043/133] Move files one-level up. --- src-network-providers/{networkProvider => }/accounts.ts | 0 src-network-providers/{networkProvider => }/apiNetworkProvider.ts | 0 src-network-providers/{networkProvider => }/config.ts | 0 src-network-providers/{networkProvider => }/constants.ts | 0 .../{networkProvider => }/contractQueryResponse.ts | 0 src-network-providers/{networkProvider => }/contractResults.ts | 0 src-network-providers/{networkProvider => }/errors.ts | 0 src-network-providers/{networkProvider => }/index.ts | 0 src-network-providers/{networkProvider => }/interface.ts | 0 src-network-providers/{networkProvider => }/networkConfig.ts | 0 src-network-providers/{networkProvider => }/networkStake.ts | 0 src-network-providers/{networkProvider => }/networkStatus.ts | 0 src-network-providers/{networkProvider => }/primitives.ts | 0 .../{networkProvider => }/providers.dev.net.spec.ts | 0 .../{networkProvider => }/proxyNetworkProvider.ts | 0 src-network-providers/{networkProvider => }/stats.ts | 0 src-network-providers/{networkProvider => }/tokenDefinitions.ts | 0 src-network-providers/{networkProvider => }/tokens.ts | 0 .../{networkProvider => }/transactionCompletionStrategy.ts | 0 src-network-providers/{networkProvider => }/transactionEvents.ts | 0 src-network-providers/{networkProvider => }/transactionLogs.ts | 0 src-network-providers/{networkProvider => }/transactionReceipt.ts | 0 src-network-providers/{networkProvider => }/transactionStatus.ts | 0 src-network-providers/{networkProvider => }/transactions.ts | 0 24 files changed, 0 insertions(+), 0 deletions(-) rename src-network-providers/{networkProvider => }/accounts.ts (100%) rename src-network-providers/{networkProvider => }/apiNetworkProvider.ts (100%) rename src-network-providers/{networkProvider => }/config.ts (100%) rename src-network-providers/{networkProvider => }/constants.ts (100%) rename src-network-providers/{networkProvider => }/contractQueryResponse.ts (100%) rename src-network-providers/{networkProvider => }/contractResults.ts (100%) rename src-network-providers/{networkProvider => }/errors.ts (100%) rename src-network-providers/{networkProvider => }/index.ts (100%) rename src-network-providers/{networkProvider => }/interface.ts (100%) rename src-network-providers/{networkProvider => }/networkConfig.ts (100%) rename src-network-providers/{networkProvider => }/networkStake.ts (100%) rename src-network-providers/{networkProvider => }/networkStatus.ts (100%) rename src-network-providers/{networkProvider => }/primitives.ts (100%) rename src-network-providers/{networkProvider => }/providers.dev.net.spec.ts (100%) rename src-network-providers/{networkProvider => }/proxyNetworkProvider.ts (100%) rename src-network-providers/{networkProvider => }/stats.ts (100%) rename src-network-providers/{networkProvider => }/tokenDefinitions.ts (100%) rename src-network-providers/{networkProvider => }/tokens.ts (100%) rename src-network-providers/{networkProvider => }/transactionCompletionStrategy.ts (100%) rename src-network-providers/{networkProvider => }/transactionEvents.ts (100%) rename src-network-providers/{networkProvider => }/transactionLogs.ts (100%) rename src-network-providers/{networkProvider => }/transactionReceipt.ts (100%) rename src-network-providers/{networkProvider => }/transactionStatus.ts (100%) rename src-network-providers/{networkProvider => }/transactions.ts (100%) diff --git a/src-network-providers/networkProvider/accounts.ts b/src-network-providers/accounts.ts similarity index 100% rename from src-network-providers/networkProvider/accounts.ts rename to src-network-providers/accounts.ts diff --git a/src-network-providers/networkProvider/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts similarity index 100% rename from src-network-providers/networkProvider/apiNetworkProvider.ts rename to src-network-providers/apiNetworkProvider.ts diff --git a/src-network-providers/networkProvider/config.ts b/src-network-providers/config.ts similarity index 100% rename from src-network-providers/networkProvider/config.ts rename to src-network-providers/config.ts diff --git a/src-network-providers/networkProvider/constants.ts b/src-network-providers/constants.ts similarity index 100% rename from src-network-providers/networkProvider/constants.ts rename to src-network-providers/constants.ts diff --git a/src-network-providers/networkProvider/contractQueryResponse.ts b/src-network-providers/contractQueryResponse.ts similarity index 100% rename from src-network-providers/networkProvider/contractQueryResponse.ts rename to src-network-providers/contractQueryResponse.ts diff --git a/src-network-providers/networkProvider/contractResults.ts b/src-network-providers/contractResults.ts similarity index 100% rename from src-network-providers/networkProvider/contractResults.ts rename to src-network-providers/contractResults.ts diff --git a/src-network-providers/networkProvider/errors.ts b/src-network-providers/errors.ts similarity index 100% rename from src-network-providers/networkProvider/errors.ts rename to src-network-providers/errors.ts diff --git a/src-network-providers/networkProvider/index.ts b/src-network-providers/index.ts similarity index 100% rename from src-network-providers/networkProvider/index.ts rename to src-network-providers/index.ts diff --git a/src-network-providers/networkProvider/interface.ts b/src-network-providers/interface.ts similarity index 100% rename from src-network-providers/networkProvider/interface.ts rename to src-network-providers/interface.ts diff --git a/src-network-providers/networkProvider/networkConfig.ts b/src-network-providers/networkConfig.ts similarity index 100% rename from src-network-providers/networkProvider/networkConfig.ts rename to src-network-providers/networkConfig.ts diff --git a/src-network-providers/networkProvider/networkStake.ts b/src-network-providers/networkStake.ts similarity index 100% rename from src-network-providers/networkProvider/networkStake.ts rename to src-network-providers/networkStake.ts diff --git a/src-network-providers/networkProvider/networkStatus.ts b/src-network-providers/networkStatus.ts similarity index 100% rename from src-network-providers/networkProvider/networkStatus.ts rename to src-network-providers/networkStatus.ts diff --git a/src-network-providers/networkProvider/primitives.ts b/src-network-providers/primitives.ts similarity index 100% rename from src-network-providers/networkProvider/primitives.ts rename to src-network-providers/primitives.ts diff --git a/src-network-providers/networkProvider/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts similarity index 100% rename from src-network-providers/networkProvider/providers.dev.net.spec.ts rename to src-network-providers/providers.dev.net.spec.ts diff --git a/src-network-providers/networkProvider/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts similarity index 100% rename from src-network-providers/networkProvider/proxyNetworkProvider.ts rename to src-network-providers/proxyNetworkProvider.ts diff --git a/src-network-providers/networkProvider/stats.ts b/src-network-providers/stats.ts similarity index 100% rename from src-network-providers/networkProvider/stats.ts rename to src-network-providers/stats.ts diff --git a/src-network-providers/networkProvider/tokenDefinitions.ts b/src-network-providers/tokenDefinitions.ts similarity index 100% rename from src-network-providers/networkProvider/tokenDefinitions.ts rename to src-network-providers/tokenDefinitions.ts diff --git a/src-network-providers/networkProvider/tokens.ts b/src-network-providers/tokens.ts similarity index 100% rename from src-network-providers/networkProvider/tokens.ts rename to src-network-providers/tokens.ts diff --git a/src-network-providers/networkProvider/transactionCompletionStrategy.ts b/src-network-providers/transactionCompletionStrategy.ts similarity index 100% rename from src-network-providers/networkProvider/transactionCompletionStrategy.ts rename to src-network-providers/transactionCompletionStrategy.ts diff --git a/src-network-providers/networkProvider/transactionEvents.ts b/src-network-providers/transactionEvents.ts similarity index 100% rename from src-network-providers/networkProvider/transactionEvents.ts rename to src-network-providers/transactionEvents.ts diff --git a/src-network-providers/networkProvider/transactionLogs.ts b/src-network-providers/transactionLogs.ts similarity index 100% rename from src-network-providers/networkProvider/transactionLogs.ts rename to src-network-providers/transactionLogs.ts diff --git a/src-network-providers/networkProvider/transactionReceipt.ts b/src-network-providers/transactionReceipt.ts similarity index 100% rename from src-network-providers/networkProvider/transactionReceipt.ts rename to src-network-providers/transactionReceipt.ts diff --git a/src-network-providers/networkProvider/transactionStatus.ts b/src-network-providers/transactionStatus.ts similarity index 100% rename from src-network-providers/networkProvider/transactionStatus.ts rename to src-network-providers/transactionStatus.ts diff --git a/src-network-providers/networkProvider/transactions.ts b/src-network-providers/transactions.ts similarity index 100% rename from src-network-providers/networkProvider/transactions.ts rename to src-network-providers/transactions.ts From 0344d432c857b0c7c60bbaf3ef4951aa378afb44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 7 Apr 2022 17:45:42 +0300 Subject: [PATCH 044/133] Fix / improve tests. --- src-network-providers/apiNetworkProvider.ts | 12 +- src-network-providers/interface.ts | 1 + .../providers.dev.net.spec.ts | 130 ++++++++++-------- src-network-providers/proxyNetworkProvider.ts | 12 +- .../testscommon/dummyQuery.ts | 23 ++++ src-network-providers/tokens.ts | 4 - 6 files changed, 110 insertions(+), 72 deletions(-) create mode 100644 src-network-providers/testscommon/dummyQuery.ts diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 5438c4d2..27e85b73 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -90,13 +90,13 @@ export class ApiNetworkProvider implements INetworkProvider { } async getTransaction(txHash: IHash): Promise { - let response = await this.doGetGeneric(`transactions/${txHash.toString()}`); + let response = await this.doGetGeneric(`transactions/${txHash.hex()}`); let transaction = TransactionOnNetwork.fromApiHttpResponse(txHash, response); return transaction; } async getTransactionStatus(txHash: IHash): Promise { - let response = await this.doGetGeneric(`transactions/${txHash.toString()}?fields=status`); + let response = await this.doGetGeneric(`transactions/${txHash.hex()}?fields=status`); let status = new TransactionStatus(response.status); return status; } @@ -153,8 +153,10 @@ export class ApiNetworkProvider implements INetworkProvider { } private async doGet(resourceUrl: string): Promise { + let url = `${this.url}/${resourceUrl}`; + console.debug(`ApiNetworkProvider.doGet(): ${url}`); + try { - let url = `${this.url}/${resourceUrl}`; let response = await axios.get(url, this.config); return response.data; } catch (error) { @@ -163,8 +165,10 @@ export class ApiNetworkProvider implements INetworkProvider { } private async doPost(resourceUrl: string, payload: any): Promise { + let url = `${this.url}/${resourceUrl}`; + console.debug(`ApiNetworkProvider.doPost(): ${url}`); + try { - let url = `${this.url}/${resourceUrl}`; let response = await axios.post(url, payload, { ...this.config, headers: { diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index 762c9504..b34a0b7b 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -112,6 +112,7 @@ export interface INetworkProvider { doPostGeneric(resourceUrl: string, payload: any): Promise; } +// TODO: network-providers package should be responsible with formatting the http request. export interface IContractQuery { toHttpRequest(): any; } diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 0b21855a..1987b951 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -1,29 +1,22 @@ import { assert } from "chai"; import { INetworkProvider } from "./interface"; -import { loadTestWallets, TestWallet } from "../testutils"; -import { TransactionHash } from "../transaction"; -import { ContractFunction, Query } from "../smartcontracts"; -import { BigUIntValue, U32Value, BytesValue, VariadicValue, VariadicType, CompositeType, BytesType, BooleanType } from "../smartcontracts/typesystem"; -import { BigNumber } from "bignumber.js"; +import { Hash } from "./primitives"; import { ApiNetworkProvider } from "./apiNetworkProvider"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; -import { Address, Nonce, TransactionValue } from "./primitives"; +import { Address, Nonce } from "./primitives"; +import { DummyQuery } from "./testscommon/dummyQuery"; describe("test network providers on devnet: Proxy and API", function () { + let alice = new Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); + let bob = new Address("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"); + let carol = new Address("erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8"); + let dan = new Address("erd1kyaqzaprcdnv4luvanah0gfxzzsnpaygsy6pytrexll2urtd05ts9vegu7"); + let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 10000 }); let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.elrond.com", { timeout: 10000 }); - let alice: TestWallet; - let bob: TestWallet; - let carol: TestWallet; - let dan: TestWallet; - - before(async function () { - ({ alice, bob, carol, dan } = await loadTestWallets()); - }); - it("should have same response for getNetworkConfig()", async function () { let apiResponse = await apiProvider.getNetworkConfig(); let proxyResponse = await proxyProvider.getNetworkConfig(); @@ -56,8 +49,8 @@ describe("test network providers on devnet: Proxy and API", function () { it("should have same response for getAccount()", async function () { for (const user of [bob, carol, dan]) { - let apiResponse = await apiProvider.getAccount(user.address); - let proxyResponse = await proxyProvider.getAccount(user.address); + let apiResponse = await apiProvider.getAccount(user); + let proxyResponse = await proxyProvider.getAccount(user); assert.deepEqual(apiResponse, proxyResponse); } @@ -67,16 +60,16 @@ describe("test network providers on devnet: Proxy and API", function () { this.timeout(30000); for (const user of [carol, dan]) { - let apiResponse = await apiProvider.getFungibleTokensOfAccount(user.address); - let proxyResponse = await proxyProvider.getFungibleTokensOfAccount(user.address); + let apiResponse = await apiProvider.getFungibleTokensOfAccount(user); + let proxyResponse = await proxyProvider.getFungibleTokensOfAccount(user); assert.deepEqual(apiResponse.slice(0, 100), proxyResponse.slice(0, 100)); for (const item of apiResponse.slice(0, 5)) { - let apiResponse = await apiProvider.getFungibleTokenOfAccount(user.address, item.identifier); - let proxyResponse = await proxyProvider.getFungibleTokenOfAccount(user.address, item.identifier); + let apiResponse = await apiProvider.getFungibleTokenOfAccount(user, item.identifier); + let proxyResponse = await proxyProvider.getFungibleTokenOfAccount(user, item.identifier); - assert.deepEqual(apiResponse, proxyResponse, `user: ${user.address.bech32()}, token: ${item.identifier}`); + assert.deepEqual(apiResponse, proxyResponse, `user: ${user.bech32()}, token: ${item.identifier}`); } } }); @@ -85,16 +78,24 @@ describe("test network providers on devnet: Proxy and API", function () { this.timeout(30000); for (const user of [alice, bob, carol, dan]) { - let apiResponse = await apiProvider.getNonFungibleTokensOfAccount(user.address); - let proxyResponse = await proxyProvider.getNonFungibleTokensOfAccount(user.address); + let apiResponse = await apiProvider.getNonFungibleTokensOfAccount(user); + let proxyResponse = await proxyProvider.getNonFungibleTokensOfAccount(user); + + for (const item of apiResponse) { + // Gateway does not provide "type". + item.type = ""; + } assert.deepEqual(apiResponse.slice(0, 100), proxyResponse.slice(0, 100)); for (const item of apiResponse.slice(0, 5)) { - let apiResponse = await apiProvider.getNonFungibleTokenOfAccount(user.address, item.collection, item.nonce); - let proxyResponse = await proxyProvider.getNonFungibleTokenOfAccount(user.address, item.collection, item.nonce); + let apiResponse = await apiProvider.getNonFungibleTokenOfAccount(user, item.collection, item.nonce); + let proxyResponse = await proxyProvider.getNonFungibleTokenOfAccount(user, item.collection, item.nonce); + + // Gateway does not provide "type". + apiResponse.type = ""; - assert.deepEqual(apiResponse, proxyResponse, `user: ${user.address.bech32()}, token: ${item.identifier}`); + assert.deepEqual(apiResponse, proxyResponse, `user: ${user.bech32()}, token: ${item.identifier}`); } } }); @@ -103,10 +104,10 @@ describe("test network providers on devnet: Proxy and API", function () { this.timeout(20000); let hashes = [ - new TransactionHash("a069c663831002651fd542479869cc61103465f3284dace772e7480f81429fa8"), - new TransactionHash("de3bc87f3e057e28ea6a625acd6d6d332e24f35ea73e820462b71256c8ecffb7"), - new TransactionHash("dbefa0299fe6b2336eb0bc3123fa623845c276e5c6e2a175adf1a562d5e77718"), - new TransactionHash("2a8ccbd91b7d9460a86174b5a8d4e6aa073b38674d1ee8107e728980a66f0676"), + new Hash("a069c663831002651fd542479869cc61103465f3284dace772e7480f81429fa8"), + new Hash("de3bc87f3e057e28ea6a625acd6d6d332e24f35ea73e820462b71256c8ecffb7"), + new Hash("dbefa0299fe6b2336eb0bc3123fa623845c276e5c6e2a175adf1a562d5e77718"), + new Hash("2a8ccbd91b7d9460a86174b5a8d4e6aa073b38674d1ee8107e728980a66f0676"), // TODO: uncomment after fix (SCR missing on API) // new TransactionHash("be7914b1eb4c6bd352ba1d86991959b443e446e0ad49fb796be3495c287b2472") ]; @@ -138,11 +139,11 @@ describe("test network providers on devnet: Proxy and API", function () { this.timeout(20000); let hashes = [ - new TransactionHash("a069c663831002651fd542479869cc61103465f3284dace772e7480f81429fa8"), - new TransactionHash("de3bc87f3e057e28ea6a625acd6d6d332e24f35ea73e820462b71256c8ecffb7"), - new TransactionHash("dbefa0299fe6b2336eb0bc3123fa623845c276e5c6e2a175adf1a562d5e77718"), - new TransactionHash("2a8ccbd91b7d9460a86174b5a8d4e6aa073b38674d1ee8107e728980a66f0676"), - new TransactionHash("be7914b1eb4c6bd352ba1d86991959b443e446e0ad49fb796be3495c287b2472") + new Hash("a069c663831002651fd542479869cc61103465f3284dace772e7480f81429fa8"), + new Hash("de3bc87f3e057e28ea6a625acd6d6d332e24f35ea73e820462b71256c8ecffb7"), + new Hash("dbefa0299fe6b2336eb0bc3123fa623845c276e5c6e2a175adf1a562d5e77718"), + new Hash("2a8ccbd91b7d9460a86174b5a8d4e6aa073b38674d1ee8107e728980a66f0676"), + new Hash("be7914b1eb4c6bd352ba1d86991959b443e446e0ad49fb796be3495c287b2472") ]; for (const hash of hashes) { @@ -201,55 +202,64 @@ describe("test network providers on devnet: Proxy and API", function () { } }); - // TODO: enable when API fixes the imprecision around "gasRemaining". - // TODO: enable when API supports queries with "value". - it.skip("should have same response for queryContract()", async function () { + it("should have same response for queryContract()", async function () { this.timeout(10000); - // Query: get ultimate answer - let query = new Query({ - address: new Address("erd1qqqqqqqqqqqqqpgqggww7tjryk9saqzfpq09tw3vm06kl8h3396qqz277y"), - func: new ContractFunction("getUltimateAnswer"), - args: [] + // Query: get sum (of adder contract) + let query = new DummyQuery({ + contract: "erd1qqqqqqqqqqqqqpgquykqja5c4v33zdmnwglj3jphqwrelzdn396qlc9g33", + function: "getSum" }); let apiResponse = await apiProvider.queryContract(query); let proxyResponse = await proxyProvider.queryContract(query); + // Ignore "gasUsed" due to numerical imprecision (API). + apiResponse.gasUsed = 0; + proxyResponse.gasUsed = 0; + assert.deepEqual(apiResponse, proxyResponse); assert.deepEqual(apiResponse.getReturnDataParts(), proxyResponse.getReturnDataParts()); // Query: increment counter - query = new Query({ - address: new Address("erd1qqqqqqqqqqqqqpgqz045rw74nthgzw2te9lytgah775n3l08396q3wt4qq"), - func: new ContractFunction("increment"), - args: [] + query = new DummyQuery({ + contract: "erd1qqqqqqqqqqqqqpgqzeq07xvhs5g7cg4ama85upaqarrcgu49396q0gz4yf", + function: "increment", + arguments: [] }); apiResponse = await apiProvider.queryContract(query); proxyResponse = await proxyProvider.queryContract(query); + // Ignore "gasUsed" due to numerical imprecision (API). + apiResponse.gasUsed = 0; + proxyResponse.gasUsed = 0; + assert.deepEqual(apiResponse, proxyResponse); assert.deepEqual(apiResponse.getReturnDataParts(), proxyResponse.getReturnDataParts()); + }); + + it.skip("should have same response for queryContract() (2)", async function () { + this.timeout(10000); // Query: issue ESDT - query = new Query({ - address: new Address("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"), - func: new ContractFunction("issue"), - value: new TransactionValue("42"), - args: [ - BytesValue.fromUTF8("FOO"), - BytesValue.fromUTF8("FOO"), - new BigUIntValue(new BigNumber("10000")), - new U32Value(18), - new VariadicValue(new VariadicType(new CompositeType(new BytesType(), new BooleanType())), []) + let query = new DummyQuery({ + contract: "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", + function: "issue", + value: "50000000000000000", + arguments: [ + Buffer.from("HELLO").toString("hex"), + Buffer.from("WORLD").toString("hex"), + "0A", // Supply + "03" // Decimals ] }); - apiResponse = await apiProvider.queryContract(query); - proxyResponse = await proxyProvider.queryContract(query); + let apiResponse = await apiProvider.queryContract(query); + let proxyResponse = await proxyProvider.queryContract(query); assert.deepEqual(apiResponse, proxyResponse); assert.deepEqual(apiResponse.getReturnDataParts(), proxyResponse.getReturnDataParts()); }); }); + diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 9313d045..e560d7b3 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -93,14 +93,14 @@ export class ProxyNetworkProvider implements INetworkProvider { } async getTransaction(txHash: IHash): Promise { - let url = this.buildUrlWithQueryParameters(`transaction/${txHash.toString()}`, { withResults: "true" }); + let url = this.buildUrlWithQueryParameters(`transaction/${txHash.hex()}`, { withResults: "true" }); let response = await this.doGetGeneric(url); let transaction = TransactionOnNetwork.fromProxyHttpResponse(txHash, response.transaction); return transaction; } async getTransactionStatus(txHash: IHash): Promise { - let response = await this.doGetGeneric(`transaction/${txHash.toString()}/status`); + let response = await this.doGetGeneric(`transaction/${txHash.hex()}/status`); let status = new TransactionStatus(response.status); return status; } @@ -153,8 +153,10 @@ export class ProxyNetworkProvider implements INetworkProvider { } private async doGet(resourceUrl: string): Promise { + let url = `${this.url}/${resourceUrl}`; + console.debug(`ProxyNetworkProvider.doGet(): ${url}`); + try { - let url = `${this.url}/${resourceUrl}`; let response = await axios.get(url, this.config); let payload = response.data.data; return payload; @@ -164,8 +166,10 @@ export class ProxyNetworkProvider implements INetworkProvider { } private async doPost(resourceUrl: string, payload: any): Promise { + let url = `${this.url}/${resourceUrl}`; + console.debug(`ProxyNetworkProvider.doPost(): ${url}`); + try { - let url = `${this.url}/${resourceUrl}`; let response = await axios.post(url, payload, { ...this.config, headers: { diff --git a/src-network-providers/testscommon/dummyQuery.ts b/src-network-providers/testscommon/dummyQuery.ts new file mode 100644 index 00000000..7b3ac3ec --- /dev/null +++ b/src-network-providers/testscommon/dummyQuery.ts @@ -0,0 +1,23 @@ +import { IContractQuery } from "../interface"; + +export class DummyQuery implements IContractQuery { + contract: string = ""; + function: string = ""; + arguments: string[] = []; + value: string = ""; + caller: string = ""; + + constructor(init?: Partial) { + Object.assign(this, init); + } + + toHttpRequest() { + return { + "scAddress": this.contract, + "funcName": this.function, + "args": this.arguments, + "value": this.value, + "caller": this.caller + } + } +} diff --git a/src-network-providers/tokens.ts b/src-network-providers/tokens.ts index 6e167028..39e14033 100644 --- a/src-network-providers/tokens.ts +++ b/src-network-providers/tokens.ts @@ -25,11 +25,9 @@ export class NonFungibleTokenOfAccountOnNetwork { type: string = ""; name: string = ""; creator: IAddress = new Address(""); - isWhitelistedStorage: boolean = false; supply: BigNumber = new BigNumber(0); decimals: number = 0; royalties: BigNumber = new BigNumber(0); - ticker: string = ""; assets: string[] = []; constructor(init?: Partial) { @@ -75,11 +73,9 @@ export class NonFungibleTokenOfAccountOnNetwork { result.type = payload.type || ""; result.name = payload.name || ""; result.creator = new Address(payload.creator || ""); - result.isWhitelistedStorage = payload.isWhitelistedStorage || false; result.decimals = Number(payload.decimals || 0); result.supply = new BigNumber(payload.balance || 1); result.royalties = new BigNumber(payload.royalties || 0); - result.ticker = payload.ticker || ""; result.assets = payload.assets || []; return result; From 7c8bc1888449bc96459e0db2109eef7c373b5a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 7 Apr 2022 17:47:35 +0300 Subject: [PATCH 045/133] Linting. --- src-network-providers/apiNetworkProvider.ts | 4 ++-- src-network-providers/contractResults.ts | 2 +- src-network-providers/interface.ts | 2 +- src-network-providers/testscommon/dummyQuery.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 27e85b73..33b8c1e5 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -37,13 +37,13 @@ export class ApiNetworkProvider implements INetworkProvider { async getNetworkStakeStatistics(): Promise { let response = await this.doGetGeneric("stake"); - let networkStake = NetworkStake.fromHttpResponse(response) + let networkStake = NetworkStake.fromHttpResponse(response); return networkStake; } async getNetworkGeneralStatistics(): Promise { let response = await this.doGetGeneric("stats"); - let stats = Stats.fromHttpResponse(response) + let stats = Stats.fromHttpResponse(response); return stats; } diff --git a/src-network-providers/contractResults.ts b/src-network-providers/contractResults.ts index 8ecfeacf..194189fb 100644 --- a/src-network-providers/contractResults.ts +++ b/src-network-providers/contractResults.ts @@ -29,7 +29,7 @@ export class ContractResults { } export class ContractResultItem { - hash: IHash = new Hash("") + hash: IHash = new Hash(""); nonce: INonce = new Nonce(0); value: TransactionValue = new TransactionValue(""); receiver: IAddress = new Address(""); diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index b34a0b7b..cf16f9a3 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -138,7 +138,7 @@ export interface ITransaction { toSendable(): any; } -export interface IHexable { hex(): string } +export interface IHexable { hex(): string; } export interface IHash extends IHexable { } export interface IAddress { bech32(): string; } export interface INonce extends IHexable { valueOf(): number; } diff --git a/src-network-providers/testscommon/dummyQuery.ts b/src-network-providers/testscommon/dummyQuery.ts index 7b3ac3ec..a19a4ade 100644 --- a/src-network-providers/testscommon/dummyQuery.ts +++ b/src-network-providers/testscommon/dummyQuery.ts @@ -18,6 +18,6 @@ export class DummyQuery implements IContractQuery { "args": this.arguments, "value": this.value, "caller": this.caller - } + }; } } From 528c8632caf79be16ed2e9f79d77389b1da1bd5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 7 Apr 2022 18:13:36 +0300 Subject: [PATCH 046/133] Add factory of network providers. --- src-network-providers/factory.ts | 12 ++++++++++++ src-network-providers/index.ts | 6 ++---- src-network-providers/interface.ts | 10 +++++----- src-network-providers/providers.dev.net.spec.ts | 7 +++---- 4 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 src-network-providers/factory.ts diff --git a/src-network-providers/factory.ts b/src-network-providers/factory.ts new file mode 100644 index 00000000..192b133d --- /dev/null +++ b/src-network-providers/factory.ts @@ -0,0 +1,12 @@ +import { AxiosRequestConfig } from "axios"; +import { ApiNetworkProvider } from "./apiNetworkProvider"; +import { INetworkProvider } from "./interface"; +import { ProxyNetworkProvider } from "./proxyNetworkProvider"; + +export function createProxyNetworkProvider(url: string, config?: AxiosRequestConfig): INetworkProvider { + return new ProxyNetworkProvider(url, config); +} + +export function createApiNetworkProvider(url: string, config?: AxiosRequestConfig): INetworkProvider { + return new ApiNetworkProvider(url, config); +} diff --git a/src-network-providers/index.ts b/src-network-providers/index.ts index 0c4e6aa0..9bbac2ef 100644 --- a/src-network-providers/index.ts +++ b/src-network-providers/index.ts @@ -1,5 +1,3 @@ -export * from "./apiNetworkProvider"; -export * from "./proxyNetworkProvider"; +export * from "./factory"; -// we do not export "./tokens" -// we do not export "./transactions" +// Important: we do not export any other components. diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index cf16f9a3..3328b9fc 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -34,7 +34,7 @@ export interface INetworkProvider { getNetworkGeneralStatistics(): Promise; /** - * Fetches the state of an {@link Account}. + * Fetches the state of an account. */ getAccount(address: IAddress): Promise; @@ -59,22 +59,22 @@ export interface INetworkProvider { getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: INonce): Promise; /** - * Fetches the state of a {@link Transaction}. + * Fetches the state of a transaction. */ getTransaction(txHash: IHash): Promise; /** - * Queries the status of a {@link Transaction}. + * Queries the status of a transaction. */ getTransactionStatus(txHash: IHash): Promise; /** - * Broadcasts an already-signed {@link Transaction}. + * Broadcasts an already-signed transaction. */ sendTransaction(tx: ITransaction): Promise; /** - * Simulates the processing of an already-signed {@link Transaction}. + * Simulates the processing of an already-signed transaction. * */ simulateTransaction(tx: ITransaction): Promise; diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 1987b951..b230496d 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -1,12 +1,11 @@ import { assert } from "chai"; import { INetworkProvider } from "./interface"; import { Hash } from "./primitives"; -import { ApiNetworkProvider } from "./apiNetworkProvider"; -import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { Address, Nonce } from "./primitives"; import { DummyQuery } from "./testscommon/dummyQuery"; +import { createApiNetworkProvider, createProxyNetworkProvider } from "./factory"; describe("test network providers on devnet: Proxy and API", function () { let alice = new Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); @@ -14,8 +13,8 @@ describe("test network providers on devnet: Proxy and API", function () { let carol = new Address("erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8"); let dan = new Address("erd1kyaqzaprcdnv4luvanah0gfxzzsnpaygsy6pytrexll2urtd05ts9vegu7"); - let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 10000 }); - let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.elrond.com", { timeout: 10000 }); + let apiProvider: INetworkProvider = createApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 10000 }); + let proxyProvider: INetworkProvider = createProxyNetworkProvider("https://devnet-gateway.elrond.com", { timeout: 10000 }); it("should have same response for getNetworkConfig()", async function () { let apiResponse = await apiProvider.getNetworkConfig(); From dbca42e290bac42cd5060bccaaeeea2066f38cd3 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 7 Apr 2022 22:19:47 +0300 Subject: [PATCH 047/133] Add IPagination interface, instead of Pagination. --- src-network-providers/apiNetworkProvider.ts | 14 +++++++------- src-network-providers/config.ts | 7 +++++++ src-network-providers/interface.ts | 14 +++++--------- src-network-providers/proxyNetworkProvider.ts | 6 +++--- 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 33b8c1e5..045dad19 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -1,6 +1,6 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; -import { IAddress, IContractQuery, IHash, INetworkProvider, INonce, ITransaction, Pagination } from "./interface"; +import { IAddress, IContractQuery, IHash, INetworkProvider, INonce, ITransaction, IPagination } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; import { Stats } from "./stats"; @@ -11,7 +11,7 @@ import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { Hash } from "./primitives"; import { ErrContractQuery, ErrNetworkProvider } from "./errors"; -import { defaultAxiosConfig } from "./config"; +import { defaultAxiosConfig, defaultPagination } from "./config"; import { NetworkStatus } from "./networkStatus"; import { ContractQueryResponse } from "./contractQueryResponse"; @@ -53,8 +53,8 @@ export class ApiNetworkProvider implements INetworkProvider { return account; } - async getFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise { - pagination = pagination || Pagination.default(); + async getFungibleTokensOfAccount(address: IAddress, pagination?: IPagination): Promise { + pagination = pagination || defaultPagination; let url = `accounts/${address.bech32()}/tokens?${this.buildPaginationParams(pagination)}`; let response: any[] = await this.doGetGeneric(url); @@ -65,8 +65,8 @@ export class ApiNetworkProvider implements INetworkProvider { return tokens; } - async getNonFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise { - pagination = pagination || Pagination.default(); + async getNonFungibleTokensOfAccount(address: IAddress, pagination?: IPagination): Promise { + pagination = pagination || defaultPagination; let url = `accounts/${address.bech32()}/nfts?${this.buildPaginationParams(pagination)}`; let response: any[] = await this.doGetGeneric(url); @@ -148,7 +148,7 @@ export class ApiNetworkProvider implements INetworkProvider { return response; } - private buildPaginationParams(pagination: Pagination) { + private buildPaginationParams(pagination: IPagination) { return `from=${pagination.from}&size=${pagination.size}`; } diff --git a/src-network-providers/config.ts b/src-network-providers/config.ts index 9d352c9d..a5b2215b 100644 --- a/src-network-providers/config.ts +++ b/src-network-providers/config.ts @@ -1,3 +1,5 @@ +import { IPagination } from "./interface"; + const JSONbig = require("json-bigint"); export const defaultAxiosConfig = { @@ -9,3 +11,8 @@ export const defaultAxiosConfig = { } ] }; + +export const defaultPagination: IPagination = { + from: 0, + size: 100 +}; diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index 3328b9fc..be81fa01 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -41,12 +41,12 @@ export interface INetworkProvider { /** * Fetches data about the fungible tokens held by an account. */ - getFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise; + getFungibleTokensOfAccount(address: IAddress, pagination?: IPagination): Promise; /** * Fetches data about the non-fungible tokens held by account. */ - getNonFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise; + getNonFungibleTokensOfAccount(address: IAddress, pagination?: IPagination): Promise; /** * Fetches data about a specific fungible token held by an account. @@ -125,13 +125,9 @@ export interface IContractReturnCode { export interface IContractSimulation { } -export class Pagination { - from: number = 0; - size: number = 100; - - static default(): Pagination { - return { from: 0, size: 100 }; - } +export interface IPagination { + from: number; + size: number; } export interface ITransaction { diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index e560d7b3..475ac5ea 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -1,6 +1,6 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; -import { IAddress, IContractQuery, IHash, INetworkProvider, INonce, ITransaction, Pagination } from "./interface"; +import { IAddress, IContractQuery, IHash, INetworkProvider, INonce, IPagination, ITransaction } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; import { Stats } from "./stats"; @@ -54,7 +54,7 @@ export class ProxyNetworkProvider implements INetworkProvider { return account; } - async getFungibleTokensOfAccount(address: IAddress, _pagination?: Pagination): Promise { + async getFungibleTokensOfAccount(address: IAddress, _pagination?: IPagination): Promise { let url = `address/${address.bech32()}/esdt`; let response = await this.doGetGeneric(url); let responseItems: any[] = Object.values(response.esdts); @@ -67,7 +67,7 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokens; } - async getNonFungibleTokensOfAccount(address: IAddress, _pagination?: Pagination): Promise { + async getNonFungibleTokensOfAccount(address: IAddress, _pagination?: IPagination): Promise { let url = `address/${address.bech32()}/esdt`; let response = await this.doGetGeneric(url); let responseItems: any[] = Object.values(response.esdts); From c172f07bbaf72ef57e89f72faf65f6ca45ba94bf Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 7 Apr 2022 23:11:28 +0300 Subject: [PATCH 048/133] Removed transactionOnNetwork.getAllEvents(). --- src-network-providers/transactions.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index 4cd351cb..4b5ef247 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -88,15 +88,5 @@ import { TransactionReceipt } from "./transactionReceipt"; // TODO: use different transaction completion strategies - API / Proxy. return new TransactionCompletionStrategy().isCompleted(this); } - - getAllEvents(): TransactionEvent[] { - let result = [...this.logs.events]; - - for (const resultItem of this.contractResults.items) { - result.push(...resultItem.logs.events); - } - - return result; - } } From b34ebfb24d7c4eb8ea18544e38e563d6d40e4639 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 7 Apr 2022 23:11:46 +0300 Subject: [PATCH 049/133] Fix interfaces. --- src-network-providers/interface.ts | 5 ++--- src-network-providers/networkConfig.ts | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index be81fa01..26836a76 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -77,7 +77,7 @@ export interface INetworkProvider { * Simulates the processing of an already-signed transaction. * */ - simulateTransaction(tx: ITransaction): Promise; + simulateTransaction(tx: ITransaction): Promise; /** * Queries a Smart Contract - runs a pure function defined by the contract and returns its results. @@ -122,7 +122,7 @@ export interface IContractReturnCode { isSuccess(): boolean; } -export interface IContractSimulation { +export interface ISimulationResults { } export interface IPagination { @@ -142,6 +142,5 @@ export interface ITransactionPayload { encoded(): string; } export interface IGasLimit { valueOf(): number; } export interface IGasPrice { valueOf(): number; } export interface IChainID { valueOf(): string; } -export interface IGasPriceModifier { valueOf(): number; } export interface ITransactionVersion { valueOf(): number; } export interface IAccountBalance { toString(): string; } diff --git a/src-network-providers/networkConfig.ts b/src-network-providers/networkConfig.ts index 690609c4..5f0718ad 100644 --- a/src-network-providers/networkConfig.ts +++ b/src-network-providers/networkConfig.ts @@ -1,5 +1,5 @@ import BigNumber from "bignumber.js"; -import { IChainID, IGasLimit, IGasPrice, IGasPriceModifier, ITransactionVersion } from "./interface"; +import { IChainID, IGasLimit, IGasPrice, ITransactionVersion } from "./interface"; /** * An object holding Network configuration parameters. @@ -36,7 +36,7 @@ export class NetworkConfig { /** * */ - public GasPriceModifier: IGasPriceModifier; + public GasPriceModifier: number; /** * The minimum gas limit required to be set when broadcasting a {@link Transaction}. From 2718f8fd19ef14ab6fe6c052ba81deef71695d9c Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 7 Apr 2022 23:11:54 +0300 Subject: [PATCH 050/133] Fix exports. --- src-network-providers/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-network-providers/index.ts b/src-network-providers/index.ts index 9bbac2ef..2b3276a7 100644 --- a/src-network-providers/index.ts +++ b/src-network-providers/index.ts @@ -1,3 +1,3 @@ -export * from "./factory"; +export { createProxyNetworkProvider, createApiNetworkProvider } from "./factory"; // Important: we do not export any other components. From d653546a68207a1720c657f15894ee612f540dc9 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Fri, 8 Apr 2022 10:26:59 +0300 Subject: [PATCH 051/133] Fix after extraction: TransactionEvent. --- src-network-providers/transactionEvents.ts | 28 ++++++++++------------ src-network-providers/transactions.ts | 1 - 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src-network-providers/transactionEvents.ts b/src-network-providers/transactionEvents.ts index 3ff2a5c4..780a1034 100644 --- a/src-network-providers/transactionEvents.ts +++ b/src-network-providers/transactionEvents.ts @@ -2,16 +2,13 @@ import { IAddress } from "./interface"; import { Address } from "./primitives"; export class TransactionEvent { - readonly address: IAddress; - readonly identifier: string; - readonly topics: TransactionEventTopic[]; - readonly data: string; + address: IAddress = new Address(""); + identifier: string = ""; + topics: TransactionEventTopic[] = []; + data: string = ""; - constructor(address: IAddress, identifier: string, topics: TransactionEventTopic[], data: string) { - this.address = address; - this.identifier = identifier; - this.topics = topics; - this.data = data; + constructor(init?: Partial) { + Object.assign(this, init); } static fromHttpResponse(responsePart: { @@ -20,12 +17,13 @@ export class TransactionEvent { topics: string[], data: string }): TransactionEvent { - let topics = (responsePart.topics || []).map(topic => new TransactionEventTopic(topic)); - let address = new Address(responsePart.address); - let identifier = responsePart.identifier || ""; - let data = Buffer.from(responsePart.data || "", "base64").toString(); - let event = new TransactionEvent(address, identifier, topics, data); - return event; + let result = new TransactionEvent(); + result.address = new Address(responsePart.address); + result.identifier = responsePart.identifier || ""; + result.topics = (responsePart.topics || []).map(topic => new TransactionEventTopic(topic)); + result.data = Buffer.from(responsePart.data || "", "base64").toString(); + + return result; } findFirstOrNoneTopic(predicate: (topic: TransactionEventTopic) => boolean): TransactionEventTopic | undefined { diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index 4b5ef247..7467e28a 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -3,7 +3,6 @@ import { ContractResults } from "./contractResults"; import { Address, Hash, Nonce, TransactionValue, TransactionPayload } from "./primitives"; import { IAddress, IGasLimit, IGasPrice, IHash, INonce, ITransactionPayload } from "./interface"; import { TransactionCompletionStrategy } from "./transactionCompletionStrategy"; -import { TransactionEvent } from "./transactionEvents"; import { TransactionLogs } from "./transactionLogs"; import { TransactionReceipt } from "./transactionReceipt"; From e0ea5f686c281cc6d3d6f7fed72e3e6eb592a81a Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Fri, 8 Apr 2022 10:43:36 +0300 Subject: [PATCH 052/133] Fix exports. --- src-network-providers/apiNetworkProvider.ts | 6 +++--- src-network-providers/index.ts | 20 ++++++++++++++++++- src-network-providers/interface.ts | 4 ++-- .../{stats.ts => networkGeneralStatistics.ts} | 8 +++----- .../providers.dev.net.spec.ts | 8 ++++---- src-network-providers/proxyNetworkProvider.ts | 4 ++-- .../testscommon/dummyQuery.ts | 4 ++-- src-network-providers/transactions.ts | 2 +- 8 files changed, 36 insertions(+), 20 deletions(-) rename src-network-providers/{stats.ts => networkGeneralStatistics.ts} (90%) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 045dad19..aaf59b20 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -3,7 +3,7 @@ import { AccountOnNetwork } from "./accounts"; import { IAddress, IContractQuery, IHash, INetworkProvider, INonce, ITransaction, IPagination } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; -import { Stats } from "./stats"; +import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; @@ -41,9 +41,9 @@ export class ApiNetworkProvider implements INetworkProvider { return networkStake; } - async getNetworkGeneralStatistics(): Promise { + async getNetworkGeneralStatistics(): Promise { let response = await this.doGetGeneric("stats"); - let stats = Stats.fromHttpResponse(response); + let stats = NetworkGeneralStatistics.fromHttpResponse(response); return stats; } diff --git a/src-network-providers/index.ts b/src-network-providers/index.ts index 2b3276a7..c3938987 100644 --- a/src-network-providers/index.ts +++ b/src-network-providers/index.ts @@ -1,3 +1,21 @@ export { createProxyNetworkProvider, createApiNetworkProvider } from "./factory"; +export { INetworkProvider } from "./interface"; -// Important: we do not export any other components. +export { AccountOnNetwork } from "./accounts"; + +export { ContractQueryResponse } from "./contractQueryResponse"; +export { ContractResults, ContractResultItem } from "./contractResults"; + +export { TransactionOnNetwork } from "./transactions"; +export { TransactionEvent, TransactionEventTopic } from "./transactionEvents"; +export { TransactionLogs } from "./transactionLogs"; +export { TransactionReceipt } from "./transactionReceipt"; +export { TransactionStatus } from "./transactionStatus"; + +export { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; +export { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; + +export { NetworkConfig } from "./networkConfig"; +export { NetworkGeneralStatistics } from "./networkGeneralStatistics"; +export { NetworkStake } from "./networkStake"; +export { NetworkStatus } from "./networkStatus"; diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index 26836a76..3fdf6817 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -1,7 +1,7 @@ import { AccountOnNetwork } from "./accounts"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; -import { Stats } from "./stats"; +import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { NetworkStatus } from "./networkStatus"; @@ -31,7 +31,7 @@ export interface INetworkProvider { /** * Fetches general statistics. */ - getNetworkGeneralStatistics(): Promise; + getNetworkGeneralStatistics(): Promise; /** * Fetches the state of an account. diff --git a/src-network-providers/stats.ts b/src-network-providers/networkGeneralStatistics.ts similarity index 90% rename from src-network-providers/stats.ts rename to src-network-providers/networkGeneralStatistics.ts index e2c63f96..7cad59e5 100644 --- a/src-network-providers/stats.ts +++ b/src-network-providers/networkGeneralStatistics.ts @@ -1,9 +1,7 @@ /** * An object holding Network stats parameters. */ -export class Stats { - private static default: Stats; - +export class NetworkGeneralStatistics { /** * The number of Shards. */ @@ -52,8 +50,8 @@ export class Stats { /** * Constructs a stats object from a HTTP response (as returned by the provider). */ - static fromHttpResponse(payload: any): Stats { - let stats = new Stats(); + static fromHttpResponse(payload: any): NetworkGeneralStatistics { + let stats = new NetworkGeneralStatistics(); stats.Shards = Number(payload["shards"]); stats.Blocks = Number(payload["blocks"]); diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index b230496d..e039fea8 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -4,7 +4,7 @@ import { Hash } from "./primitives"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { Address, Nonce } from "./primitives"; -import { DummyQuery } from "./testscommon/dummyQuery"; +import { MockQuery } from "./testscommon/dummyQuery"; import { createApiNetworkProvider, createProxyNetworkProvider } from "./factory"; describe("test network providers on devnet: Proxy and API", function () { @@ -205,7 +205,7 @@ describe("test network providers on devnet: Proxy and API", function () { this.timeout(10000); // Query: get sum (of adder contract) - let query = new DummyQuery({ + let query = new MockQuery({ contract: "erd1qqqqqqqqqqqqqpgquykqja5c4v33zdmnwglj3jphqwrelzdn396qlc9g33", function: "getSum" }); @@ -221,7 +221,7 @@ describe("test network providers on devnet: Proxy and API", function () { assert.deepEqual(apiResponse.getReturnDataParts(), proxyResponse.getReturnDataParts()); // Query: increment counter - query = new DummyQuery({ + query = new MockQuery({ contract: "erd1qqqqqqqqqqqqqpgqzeq07xvhs5g7cg4ama85upaqarrcgu49396q0gz4yf", function: "increment", arguments: [] @@ -242,7 +242,7 @@ describe("test network providers on devnet: Proxy and API", function () { this.timeout(10000); // Query: issue ESDT - let query = new DummyQuery({ + let query = new MockQuery({ contract: "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", function: "issue", value: "50000000000000000", diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 475ac5ea..81741b44 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -3,7 +3,7 @@ import { AccountOnNetwork } from "./accounts"; import { IAddress, IContractQuery, IHash, INetworkProvider, INonce, IPagination, ITransaction } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; -import { Stats } from "./stats"; +import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; @@ -42,7 +42,7 @@ export class ProxyNetworkProvider implements INetworkProvider { throw new Error("Method not implemented."); } - async getNetworkGeneralStatistics(): Promise { + async getNetworkGeneralStatistics(): Promise { // TODO: Implement wrt. (full implementation may not be possible): // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/network/network.service.ts throw new Error("Method not implemented."); diff --git a/src-network-providers/testscommon/dummyQuery.ts b/src-network-providers/testscommon/dummyQuery.ts index a19a4ade..33befef3 100644 --- a/src-network-providers/testscommon/dummyQuery.ts +++ b/src-network-providers/testscommon/dummyQuery.ts @@ -1,13 +1,13 @@ import { IContractQuery } from "../interface"; -export class DummyQuery implements IContractQuery { +export class MockQuery implements IContractQuery { contract: string = ""; function: string = ""; arguments: string[] = []; value: string = ""; caller: string = ""; - constructor(init?: Partial) { + constructor(init?: Partial) { Object.assign(this, init); } diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index 7467e28a..5e90c207 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -6,7 +6,7 @@ import { TransactionCompletionStrategy } from "./transactionCompletionStrategy"; import { TransactionLogs } from "./transactionLogs"; import { TransactionReceipt } from "./transactionReceipt"; - export class TransactionOnNetwork { +export class TransactionOnNetwork { hash: IHash = new Hash(""); type: string = ""; nonce: INonce = new Nonce(0); From 4c2212e089d32afc0feb5c0942e13e62f8a3122d Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Fri, 8 Apr 2022 11:11:06 +0300 Subject: [PATCH 053/133] Fix DTOs. --- src-network-providers/contractResults.ts | 6 +----- src-network-providers/transactionLogs.ts | 21 +++++++++------------ src-network-providers/transactions.ts | 4 ++-- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src-network-providers/contractResults.ts b/src-network-providers/contractResults.ts index 194189fb..8cabd048 100644 --- a/src-network-providers/contractResults.ts +++ b/src-network-providers/contractResults.ts @@ -13,10 +13,6 @@ export class ContractResults { }); } - static empty(): ContractResults { - return new ContractResults([]); - } - static fromProxyHttpResponse(results: any[]): ContractResults { let items = results.map(item => ContractResultItem.fromProxyHttpResponse(item)); return new ContractResults(items); @@ -41,7 +37,7 @@ export class ContractResultItem { gasPrice: IGasPrice = 0; callType: number = 0; returnMessage: string = ""; - logs: TransactionLogs = TransactionLogs.empty(); + logs: TransactionLogs = new TransactionLogs(); constructor(init?: Partial) { Object.assign(this, init); diff --git a/src-network-providers/transactionLogs.ts b/src-network-providers/transactionLogs.ts index 91586ef0..9e7a6ef1 100644 --- a/src-network-providers/transactionLogs.ts +++ b/src-network-providers/transactionLogs.ts @@ -4,22 +4,19 @@ import { Address } from "./primitives"; import { TransactionEvent } from "./transactionEvents"; export class TransactionLogs { - readonly address: IAddress; - readonly events: TransactionEvent[]; + address: IAddress = new Address(""); + events: TransactionEvent[] = []; - constructor(address: IAddress, events: TransactionEvent[]) { - this.address = address; - this.events = events; - } - - static empty(): TransactionLogs { - return new TransactionLogs(new Address(""), []); + constructor(init?: Partial) { + Object.assign(this, init); } static fromHttpResponse(logs: any): TransactionLogs { - let address = new Address(logs.address); - let events = (logs.events || []).map((event: any) => TransactionEvent.fromHttpResponse(event)); - return new TransactionLogs(address, events); + let result = new TransactionLogs(); + result.address = new Address(logs.address); + result.events = (logs.events || []).map((event: any) => TransactionEvent.fromHttpResponse(event)); + + return result; } findSingleOrNoneEvent(identifier: string, predicate?: (event: TransactionEvent) => boolean): TransactionEvent | undefined { diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index 5e90c207..c9cc6321 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -28,8 +28,8 @@ export class TransactionOnNetwork { pendingResults: boolean = false; receipt: TransactionReceipt = new TransactionReceipt(); - contractResults: ContractResults = ContractResults.empty(); - logs: TransactionLogs = TransactionLogs.empty(); + contractResults: ContractResults = new ContractResults([]); + logs: TransactionLogs = new TransactionLogs(); constructor(init?: Partial) { Object.assign(this, init); From d8fac6f8bd4ab8c4fd446ff72f7c82ab1bb39c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Fri, 8 Apr 2022 15:41:08 +0300 Subject: [PATCH 054/133] Handle completion: API vs. Proxy. --- src-network-providers/providers.dev.net.spec.ts | 4 ++++ .../transactionCompletionStrategy.ts | 17 +++++++++++++---- src-network-providers/transactions.ts | 17 ++++++++++------- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index e039fea8..ba8d9a7f 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -117,6 +117,10 @@ describe("test network providers on devnet: Proxy and API", function () { ignoreKnownTransactionDifferencesBetweenProviders(apiResponse, proxyResponse); assert.deepEqual(apiResponse, proxyResponse, `transaction: ${hash}`); + + // Also assert completion + assert.isTrue(apiResponse.isCompleted()); + assert.isTrue(proxyResponse.isCompleted()); } }); diff --git a/src-network-providers/transactionCompletionStrategy.ts b/src-network-providers/transactionCompletionStrategy.ts index 60de758e..5fccc5a6 100644 --- a/src-network-providers/transactionCompletionStrategy.ts +++ b/src-network-providers/transactionCompletionStrategy.ts @@ -3,9 +3,6 @@ import { ITransactionPayload } from "./interface"; import { TransactionLogs } from "./transactionLogs"; import { isPaddedHex } from "./primitives"; -/** - * Internal interface: a transaction, as seen from the perspective of a {@link TransactionCompletionStrategy}. - */ interface ITransactionOnNetwork { logs: TransactionLogs; status: TransactionStatus; @@ -19,7 +16,7 @@ const WellKnownCompletionEvents = ["completedTxEvent", "SCDeploy", "signalError" * Algorithm for detecting transaction completion. * Based on some heuristics (a bit imprecise therefore, at this moment). */ -export class TransactionCompletionStrategy { +export class TransactionCompletionStrategyOnProxy { isCompleted(transaction: ITransactionOnNetwork): boolean { if (transaction.status.isPending()) { // Certainly not completed. @@ -65,3 +62,15 @@ export class TransactionCompletionStrategy { return isPaddedHex(arg); } } + +export class TransactionCompletionStrategyOnAPI { + isCompleted(transaction: ITransactionOnNetwork): boolean { + return !transaction.status.isPending(); + } +} + +export class NullTransactionCompletionStrategy { + isCompleted(_transaction: ITransactionOnNetwork): boolean { + return false; + } +} diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index 5e90c207..003c5bfb 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -2,11 +2,17 @@ import { TransactionStatus } from "./transactionStatus"; import { ContractResults } from "./contractResults"; import { Address, Hash, Nonce, TransactionValue, TransactionPayload } from "./primitives"; import { IAddress, IGasLimit, IGasPrice, IHash, INonce, ITransactionPayload } from "./interface"; -import { TransactionCompletionStrategy } from "./transactionCompletionStrategy"; +import { NullTransactionCompletionStrategy, TransactionCompletionStrategyOnAPI, TransactionCompletionStrategyOnProxy } from "./transactionCompletionStrategy"; import { TransactionLogs } from "./transactionLogs"; import { TransactionReceipt } from "./transactionReceipt"; +interface ICompletionStrategy { + isCompleted(transaction: TransactionOnNetwork): boolean; +} + export class TransactionOnNetwork { + completionStrategy: ICompletionStrategy = new NullTransactionCompletionStrategy(); + hash: IHash = new Hash(""); type: string = ""; nonce: INonce = new Nonce(0); @@ -25,7 +31,6 @@ export class TransactionOnNetwork { blockNonce: number = 0; hyperblockNonce: number = 0; hyperblockHash: string = ""; - pendingResults: boolean = false; receipt: TransactionReceipt = new TransactionReceipt(); contractResults: ContractResults = ContractResults.empty(); @@ -38,16 +43,16 @@ export class TransactionOnNetwork { static fromProxyHttpResponse(txHash: IHash, response: any): TransactionOnNetwork { let result = TransactionOnNetwork.fromHttpResponse(txHash, response); result.contractResults = ContractResults.fromProxyHttpResponse(response.smartContractResults || []); + result.completionStrategy = new TransactionCompletionStrategyOnProxy(); // TODO: uniformize transaction status. - // TODO: Use specific completion detection strategy. return result; } static fromApiHttpResponse(txHash: IHash, response: any): TransactionOnNetwork { let result = TransactionOnNetwork.fromHttpResponse(txHash, response); result.contractResults = ContractResults.fromApiHttpResponse(response.results || []); + result.completionStrategy = new TransactionCompletionStrategyOnAPI(); // TODO: uniformize transaction status. - // TODO: Use specific completion detection strategy. return result; } @@ -71,7 +76,6 @@ export class TransactionOnNetwork { result.blockNonce = response.blockNonce || 0; result.hyperblockNonce = response.hyperblockNonce || 0; result.hyperblockHash = response.hyperblockHash || ""; - result.pendingResults = response.pendingResults || false; result.receipt = TransactionReceipt.fromHttpResponse(response.receipt || {}); result.logs = TransactionLogs.fromHttpResponse(response.logs || {}); @@ -84,8 +88,7 @@ export class TransactionOnNetwork { } isCompleted(): boolean { - // TODO: use different transaction completion strategies - API / Proxy. - return new TransactionCompletionStrategy().isCompleted(this); + return this.completionStrategy.isCompleted(this); } } From bcd8fbc08b79ac8d73620939329dfe1bb24b4a8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Fri, 8 Apr 2022 15:46:51 +0300 Subject: [PATCH 055/133] Simplify. --- src-network-providers/providers.dev.net.spec.ts | 4 ++-- src-network-providers/transactions.ts | 17 ++++------------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index ba8d9a7f..15ecf3c5 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -119,8 +119,8 @@ describe("test network providers on devnet: Proxy and API", function () { assert.deepEqual(apiResponse, proxyResponse, `transaction: ${hash}`); // Also assert completion - assert.isTrue(apiResponse.isCompleted()); - assert.isTrue(proxyResponse.isCompleted()); + assert.isTrue(apiResponse.isCompleted); + assert.isTrue(proxyResponse.isCompleted); } }); diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index 003c5bfb..eaa43511 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -2,17 +2,12 @@ import { TransactionStatus } from "./transactionStatus"; import { ContractResults } from "./contractResults"; import { Address, Hash, Nonce, TransactionValue, TransactionPayload } from "./primitives"; import { IAddress, IGasLimit, IGasPrice, IHash, INonce, ITransactionPayload } from "./interface"; -import { NullTransactionCompletionStrategy, TransactionCompletionStrategyOnAPI, TransactionCompletionStrategyOnProxy } from "./transactionCompletionStrategy"; +import { TransactionCompletionStrategyOnAPI, TransactionCompletionStrategyOnProxy } from "./transactionCompletionStrategy"; import { TransactionLogs } from "./transactionLogs"; import { TransactionReceipt } from "./transactionReceipt"; -interface ICompletionStrategy { - isCompleted(transaction: TransactionOnNetwork): boolean; -} - export class TransactionOnNetwork { - completionStrategy: ICompletionStrategy = new NullTransactionCompletionStrategy(); - + isCompleted: boolean = false; hash: IHash = new Hash(""); type: string = ""; nonce: INonce = new Nonce(0); @@ -43,7 +38,7 @@ export class TransactionOnNetwork { static fromProxyHttpResponse(txHash: IHash, response: any): TransactionOnNetwork { let result = TransactionOnNetwork.fromHttpResponse(txHash, response); result.contractResults = ContractResults.fromProxyHttpResponse(response.smartContractResults || []); - result.completionStrategy = new TransactionCompletionStrategyOnProxy(); + result.isCompleted = new TransactionCompletionStrategyOnProxy().isCompleted(result); // TODO: uniformize transaction status. return result; } @@ -51,7 +46,7 @@ export class TransactionOnNetwork { static fromApiHttpResponse(txHash: IHash, response: any): TransactionOnNetwork { let result = TransactionOnNetwork.fromHttpResponse(txHash, response); result.contractResults = ContractResults.fromApiHttpResponse(response.results || []); - result.completionStrategy = new TransactionCompletionStrategyOnAPI(); + result.isCompleted = new TransactionCompletionStrategyOnAPI().isCompleted(result); // TODO: uniformize transaction status. return result; } @@ -86,9 +81,5 @@ export class TransactionOnNetwork { getDateTime(): Date { return new Date(this.timestamp * 1000); } - - isCompleted(): boolean { - return this.completionStrategy.isCompleted(this); - } } From 5cef3fe6deeaa648378e1a481dba8b09b97417de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Fri, 8 Apr 2022 15:50:23 +0300 Subject: [PATCH 056/133] Cleanup. --- src-network-providers/transactionCompletionStrategy.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src-network-providers/transactionCompletionStrategy.ts b/src-network-providers/transactionCompletionStrategy.ts index 5fccc5a6..e0fe457a 100644 --- a/src-network-providers/transactionCompletionStrategy.ts +++ b/src-network-providers/transactionCompletionStrategy.ts @@ -68,9 +68,3 @@ export class TransactionCompletionStrategyOnAPI { return !transaction.status.isPending(); } } - -export class NullTransactionCompletionStrategy { - isCompleted(_transaction: ITransactionOnNetwork): boolean { - return false; - } -} From 1fb0dcfe0b0ee5d91b15e5c473a5f11d0c762189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Sat, 9 Apr 2022 23:20:47 +0300 Subject: [PATCH 057/133] Formatting etc. --- src-network-providers/interface.ts | 7 +- .../networkGeneralStatistics.ts | 8 ++- src-network-providers/networkStake.ts | 68 +++++++++---------- 3 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index 3fdf6817..1bf3045d 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -77,7 +77,7 @@ export interface INetworkProvider { * Simulates the processing of an already-signed transaction. * */ - simulateTransaction(tx: ITransaction): Promise; + simulateTransaction(tx: ITransaction): Promise; /** * Queries a Smart Contract - runs a pure function defined by the contract and returns its results. @@ -86,13 +86,11 @@ export interface INetworkProvider { /** * Fetches the definition of a fungible token. - * */ getDefinitionOfFungibleToken(tokenIdentifier: string): Promise; /** * Fetches the definition of a SFT (including Meta ESDT) or NFT. - * */ getDefinitionOfTokenCollection(collection: string): Promise; @@ -122,9 +120,6 @@ export interface IContractReturnCode { isSuccess(): boolean; } -export interface ISimulationResults { -} - export interface IPagination { from: number; size: number; diff --git a/src-network-providers/networkGeneralStatistics.ts b/src-network-providers/networkGeneralStatistics.ts index 7cad59e5..2935b1cb 100644 --- a/src-network-providers/networkGeneralStatistics.ts +++ b/src-network-providers/networkGeneralStatistics.ts @@ -1,5 +1,5 @@ /** - * An object holding Network stats parameters. + * An object holding general Network statistics and parameters. */ export class NetworkGeneralStatistics { /** @@ -11,26 +11,32 @@ export class NetworkGeneralStatistics { * The Number of Blocks. */ public Blocks: number; + /** * The Number of Accounts. */ public Accounts: number; + /** * The Number of transactions. */ public Transactions: number; + /** * The Refresh rate. */ public RefreshRate: number; + /** * The Number of the current Epoch. */ public Epoch: number; + /** * The Number of rounds passed. */ public RoundsPassed: number; + /** * The Number of Rounds per epoch. */ diff --git a/src-network-providers/networkStake.ts b/src-network-providers/networkStake.ts index cab48b60..5806f9eb 100644 --- a/src-network-providers/networkStake.ts +++ b/src-network-providers/networkStake.ts @@ -4,44 +4,44 @@ import BigNumber from "bignumber.js"; * An object holding Network stake parameters. */ export class NetworkStake { - private static default: NetworkStake; + private static default: NetworkStake; - /** - * The Total Validators Number. - */ - public TotalValidators: number; + /** + * The Total Validators Number. + */ + public TotalValidators: number; - /** - * The Active Validators Number. - */ - public ActiveValidators: number; - /** - * The Queue Size. - */ - public QueueSize: number; - /** - * The Total Validators Number. - */ - public TotalStaked: BigNumber; + /** + * The Active Validators Number. + */ + public ActiveValidators: number; + /** + * The Queue Size. + */ + public QueueSize: number; + /** + * The Total Validators Number. + */ + public TotalStaked: BigNumber; - constructor() { - this.TotalValidators = 0; - this.ActiveValidators = 0; - this.QueueSize = 0; - this.TotalStaked = new BigNumber(0); - } + constructor() { + this.TotalValidators = 0; + this.ActiveValidators = 0; + this.QueueSize = 0; + this.TotalStaked = new BigNumber(0); + } - /** - * Constructs a configuration object from a HTTP response (as returned by the provider). - */ - static fromHttpResponse(payload: any): NetworkStake { - let networkStake = new NetworkStake(); + /** + * Constructs a configuration object from a HTTP response (as returned by the provider). + */ + static fromHttpResponse(payload: any): NetworkStake { + let networkStake = new NetworkStake(); - networkStake.TotalValidators = Number(payload["totalValidators"]); - networkStake.ActiveValidators = Number(payload["activeValidators"]); - networkStake.QueueSize = Number(payload["queueSize"]); - networkStake.TotalStaked = new BigNumber(payload["totalStaked"]); + networkStake.TotalValidators = Number(payload["totalValidators"]); + networkStake.ActiveValidators = Number(payload["activeValidators"]); + networkStake.QueueSize = Number(payload["queueSize"]); + networkStake.TotalStaked = new BigNumber(payload["totalStaked"]); - return networkStake; - } + return networkStake; + } } From f13e771b104c67ec24d94b72c47eb1db202e877d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Sat, 9 Apr 2022 23:24:34 +0300 Subject: [PATCH 058/133] Fix exports. --- src-network-providers/factory.ts | 12 ------------ src-network-providers/index.ts | 10 ++++------ src-network-providers/providers.dev.net.spec.ts | 7 ++++--- 3 files changed, 8 insertions(+), 21 deletions(-) delete mode 100644 src-network-providers/factory.ts diff --git a/src-network-providers/factory.ts b/src-network-providers/factory.ts deleted file mode 100644 index 192b133d..00000000 --- a/src-network-providers/factory.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { AxiosRequestConfig } from "axios"; -import { ApiNetworkProvider } from "./apiNetworkProvider"; -import { INetworkProvider } from "./interface"; -import { ProxyNetworkProvider } from "./proxyNetworkProvider"; - -export function createProxyNetworkProvider(url: string, config?: AxiosRequestConfig): INetworkProvider { - return new ProxyNetworkProvider(url, config); -} - -export function createApiNetworkProvider(url: string, config?: AxiosRequestConfig): INetworkProvider { - return new ApiNetworkProvider(url, config); -} diff --git a/src-network-providers/index.ts b/src-network-providers/index.ts index c3938987..5f578c85 100644 --- a/src-network-providers/index.ts +++ b/src-network-providers/index.ts @@ -1,16 +1,14 @@ -export { createProxyNetworkProvider, createApiNetworkProvider } from "./factory"; -export { INetworkProvider } from "./interface"; +export { ProxyNetworkProvider } from "./proxyNetworkProvider"; +export { ApiNetworkProvider } from "./apiNetworkProvider"; export { AccountOnNetwork } from "./accounts"; - -export { ContractQueryResponse } from "./contractQueryResponse"; -export { ContractResults, ContractResultItem } from "./contractResults"; - export { TransactionOnNetwork } from "./transactions"; export { TransactionEvent, TransactionEventTopic } from "./transactionEvents"; export { TransactionLogs } from "./transactionLogs"; export { TransactionReceipt } from "./transactionReceipt"; export { TransactionStatus } from "./transactionStatus"; +export { ContractQueryResponse } from "./contractQueryResponse"; +export { ContractResults, ContractResultItem } from "./contractResults"; export { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; export { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 15ecf3c5..cdbfe610 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -5,7 +5,8 @@ import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { Address, Nonce } from "./primitives"; import { MockQuery } from "./testscommon/dummyQuery"; -import { createApiNetworkProvider, createProxyNetworkProvider } from "./factory"; +import { ApiNetworkProvider } from "./apiNetworkProvider"; +import { ProxyNetworkProvider } from "./proxyNetworkProvider"; describe("test network providers on devnet: Proxy and API", function () { let alice = new Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); @@ -13,8 +14,8 @@ describe("test network providers on devnet: Proxy and API", function () { let carol = new Address("erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8"); let dan = new Address("erd1kyaqzaprcdnv4luvanah0gfxzzsnpaygsy6pytrexll2urtd05ts9vegu7"); - let apiProvider: INetworkProvider = createApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 10000 }); - let proxyProvider: INetworkProvider = createProxyNetworkProvider("https://devnet-gateway.elrond.com", { timeout: 10000 }); + let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 10000 }); + let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.elrond.com", { timeout: 10000 }); it("should have same response for getNetworkConfig()", async function () { let apiResponse = await apiProvider.getNetworkConfig(); From 8004195e60002596de02ef6741f1162577af8ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Sat, 9 Apr 2022 23:50:03 +0300 Subject: [PATCH 059/133] Simplify interfaces etc. --- src-network-providers/accounts.ts | 14 +++++------ src-network-providers/apiNetworkProvider.ts | 22 +++++++++-------- .../contractQueryResponse.ts | 6 ++--- src-network-providers/contractResults.ts | 20 ++++++++-------- src-network-providers/interface.ts | 24 +++++++------------ src-network-providers/networkConfig.ts | 18 ++++++-------- src-network-providers/primitives.ts | 8 +++---- .../providers.dev.net.spec.ts | 12 +++++----- src-network-providers/proxyNetworkProvider.ts | 14 +++++------ src-network-providers/tokenDefinitions.ts | 12 +++++----- src-network-providers/tokens.ts | 15 ++++++------ .../transactionCompletionStrategy.ts | 5 ++-- src-network-providers/transactionEvents.ts | 8 +++---- src-network-providers/transactionLogs.ts | 12 +++++----- src-network-providers/transactionReceipt.ts | 8 +++---- src-network-providers/transactions.ts | 23 +++++++++--------- 16 files changed, 105 insertions(+), 116 deletions(-) diff --git a/src-network-providers/accounts.ts b/src-network-providers/accounts.ts index 6c713358..c5602eb5 100644 --- a/src-network-providers/accounts.ts +++ b/src-network-providers/accounts.ts @@ -1,13 +1,13 @@ -import { IAccountBalance, IAddress, INonce } from "./interface"; -import { AccountBalance, Address, Nonce } from "./primitives"; +import { IBech32Address } from "./interface"; +import { AccountBalance, Bech32Address } from "./primitives"; /** * A plain view of an account, as queried from the Network. */ export class AccountOnNetwork { - address: IAddress = new Address(""); - nonce: INonce = new Nonce(0); - balance: IAccountBalance = new AccountBalance(""); + address: IBech32Address = new Bech32Address(""); + nonce: number = 0; + balance: AccountBalance = new AccountBalance(""); code: string = ""; userName: string = ""; @@ -18,8 +18,8 @@ import { AccountBalance, Address, Nonce } from "./primitives"; static fromHttpResponse(payload: any): AccountOnNetwork { let result = new AccountOnNetwork(); - result.address = new Address(payload["address"] || 0); - result.nonce = new Nonce(payload["nonce"] || 0); + result.address = new Bech32Address(payload["address"] || 0); + result.nonce = Number(payload["nonce"] || 0); result.balance = new AccountBalance(payload["balance"] || "0"); result.code = payload["code"] || ""; result.userName = payload["username"] || ""; diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index aaf59b20..8d54a4c8 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -1,6 +1,6 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; -import { IAddress, IContractQuery, IHash, INetworkProvider, INonce, ITransaction, IPagination } from "./interface"; +import { IBech32Address, IContractQuery, IHash, INetworkProvider, ITransaction, IPagination } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; @@ -9,7 +9,7 @@ import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwor import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; -import { Hash } from "./primitives"; +import { Hash, Nonce } from "./primitives"; import { ErrContractQuery, ErrNetworkProvider } from "./errors"; import { defaultAxiosConfig, defaultPagination } from "./config"; import { NetworkStatus } from "./networkStatus"; @@ -47,13 +47,13 @@ export class ApiNetworkProvider implements INetworkProvider { return stats; } - async getAccount(address: IAddress): Promise { + async getAccount(address: IBech32Address): Promise { let response = await this.doGetGeneric(`accounts/${address.bech32()}`); let account = AccountOnNetwork.fromHttpResponse(response); return account; } - async getFungibleTokensOfAccount(address: IAddress, pagination?: IPagination): Promise { + async getFungibleTokensOfAccount(address: IBech32Address, pagination?: IPagination): Promise { pagination = pagination || defaultPagination; let url = `accounts/${address.bech32()}/tokens?${this.buildPaginationParams(pagination)}`; @@ -65,7 +65,7 @@ export class ApiNetworkProvider implements INetworkProvider { return tokens; } - async getNonFungibleTokensOfAccount(address: IAddress, pagination?: IPagination): Promise { + async getNonFungibleTokensOfAccount(address: IBech32Address, pagination?: IPagination): Promise { pagination = pagination || defaultPagination; let url = `accounts/${address.bech32()}/nfts?${this.buildPaginationParams(pagination)}`; @@ -77,14 +77,15 @@ export class ApiNetworkProvider implements INetworkProvider { return tokens; } - async getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise { + async getFungibleTokenOfAccount(address: IBech32Address, tokenIdentifier: string): Promise { let response = await this.doGetGeneric(`accounts/${address.bech32()}/tokens/${tokenIdentifier}`); let tokenData = FungibleTokenOfAccountOnNetwork.fromHttpResponse(response); return tokenData; } - async getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: INonce): Promise { - let response = await this.doGetGeneric(`accounts/${address.bech32()}/nfts/${collection}-${nonce.hex()}`); + async getNonFungibleTokenOfAccount(address: IBech32Address, collection: string, nonce: number): Promise { + let nonceAsHex = new Nonce(nonce).hex(); + let response = await this.doGetGeneric(`accounts/${address.bech32()}/nfts/${collection}-${nonceAsHex}`); let tokenData = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response); return tokenData; } @@ -132,8 +133,9 @@ export class ApiNetworkProvider implements INetworkProvider { return definition; } - async getNonFungibleToken(collection: string, nonce: INonce): Promise { - let response = await this.doGetGeneric(`nfts/${collection}-${nonce.hex()}`); + async getNonFungibleToken(collection: string, nonce: number): Promise { + let nonceAsHex = new Nonce(nonce).hex(); + let response = await this.doGetGeneric(`nfts/${collection}-${nonceAsHex}`); let token = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response); return token; } diff --git a/src-network-providers/contractQueryResponse.ts b/src-network-providers/contractQueryResponse.ts index 404d9600..79cc1452 100644 --- a/src-network-providers/contractQueryResponse.ts +++ b/src-network-providers/contractQueryResponse.ts @@ -1,13 +1,13 @@ import BigNumber from "bignumber.js"; import { MaxUint64AsBigNumber } from "./constants"; -import { IContractReturnCode, IGasLimit } from "./interface"; +import { IContractReturnCode } from "./interface"; import { ContractReturnCode } from "./primitives"; export class ContractQueryResponse { returnData: string[]; returnCode: IContractReturnCode; returnMessage: string; - gasUsed: IGasLimit; + gasUsed: number; constructor(init?: Partial) { this.returnData = init?.returnData || []; @@ -24,7 +24,7 @@ export class ContractQueryResponse { let returnCode = payload["returnCode"] || payload["ReturnCode"]; let returnMessage = payload["returnMessage"] || payload["ReturnMessage"]; let gasRemaining = new BigNumber(payload["gasRemaining"] || payload["GasRemaining"] || 0); - let gasUsed = new Number(MaxUint64AsBigNumber.minus(gasRemaining).toNumber()); + let gasUsed = MaxUint64AsBigNumber.minus(gasRemaining).toNumber(); return new ContractQueryResponse({ returnData: returnData, diff --git a/src-network-providers/contractResults.ts b/src-network-providers/contractResults.ts index 194189fb..1eca3afc 100644 --- a/src-network-providers/contractResults.ts +++ b/src-network-providers/contractResults.ts @@ -1,6 +1,6 @@ -import { IAddress, IGasLimit, IGasPrice, IHash, INonce } from "./interface"; +import { IBech32Address, IHash } from "./interface"; import { TransactionLogs } from "./transactionLogs"; -import { Address, Hash, Nonce, TransactionValue } from "./primitives"; +import { Bech32Address, Hash, Nonce, TransactionValue } from "./primitives"; export class ContractResults { readonly items: ContractResultItem[]; @@ -30,15 +30,15 @@ export class ContractResults { export class ContractResultItem { hash: IHash = new Hash(""); - nonce: INonce = new Nonce(0); + nonce: number = 0; value: TransactionValue = new TransactionValue(""); - receiver: IAddress = new Address(""); - sender: IAddress = new Address(""); + receiver: IBech32Address = new Bech32Address(""); + sender: IBech32Address = new Bech32Address(""); data: string = ""; previousHash: Hash = new Hash(""); originalHash: Hash = new Hash(""); - gasLimit: IGasLimit = 0; - gasPrice: IGasPrice = 0; + gasLimit: number = 0; + gasPrice: number = 0; callType: number = 0; returnMessage: string = ""; logs: TransactionLogs = TransactionLogs.empty(); @@ -65,10 +65,10 @@ export class ContractResultItem { let item = new ContractResultItem(); item.hash = new Hash(response.hash); - item.nonce = new Nonce(response.nonce || 0); + item.nonce = Number(response.nonce || 0); item.value = new TransactionValue((response.value || 0).toString()); - item.receiver = new Address(response.receiver); - item.sender = new Address(response.sender); + item.receiver = new Bech32Address(response.receiver); + item.sender = new Bech32Address(response.sender); item.previousHash = new Hash(response.prevTxHash); item.originalHash = new Hash(response.originalTxHash); item.gasLimit = Number(response.gasLimit || 0); diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index 1bf3045d..0040002b 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -36,27 +36,27 @@ export interface INetworkProvider { /** * Fetches the state of an account. */ - getAccount(address: IAddress): Promise; + getAccount(address: IBech32Address): Promise; /** * Fetches data about the fungible tokens held by an account. */ - getFungibleTokensOfAccount(address: IAddress, pagination?: IPagination): Promise; + getFungibleTokensOfAccount(address: IBech32Address, pagination?: IPagination): Promise; /** * Fetches data about the non-fungible tokens held by account. */ - getNonFungibleTokensOfAccount(address: IAddress, pagination?: IPagination): Promise; + getNonFungibleTokensOfAccount(address: IBech32Address, pagination?: IPagination): Promise; /** * Fetches data about a specific fungible token held by an account. */ - getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise; + getFungibleTokenOfAccount(address: IBech32Address, tokenIdentifier: string): Promise; /** * Fetches data about a specific non-fungible token (instance) held by an account. */ - getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: INonce): Promise; + getNonFungibleTokenOfAccount(address: IBech32Address, collection: string, nonce: number): Promise; /** * Fetches the state of a transaction. @@ -97,7 +97,7 @@ export interface INetworkProvider { /** * Fetches data about a specific non-fungible token (instance). */ - getNonFungibleToken(collection: string, nonce: INonce): Promise; + getNonFungibleToken(collection: string, nonce: number): Promise; /** * Performs a generic GET action against the provider (useful for new HTTP endpoints, not yet supported by erdjs). @@ -129,13 +129,5 @@ export interface ITransaction { toSendable(): any; } -export interface IHexable { hex(): string; } -export interface IHash extends IHexable { } -export interface IAddress { bech32(): string; } -export interface INonce extends IHexable { valueOf(): number; } -export interface ITransactionPayload { encoded(): string; } -export interface IGasLimit { valueOf(): number; } -export interface IGasPrice { valueOf(): number; } -export interface IChainID { valueOf(): string; } -export interface ITransactionVersion { valueOf(): number; } -export interface IAccountBalance { toString(): string; } +export interface IHash { hex(): string; } +export interface IBech32Address { bech32(): string; } diff --git a/src-network-providers/networkConfig.ts b/src-network-providers/networkConfig.ts index 5f0718ad..be931e3c 100644 --- a/src-network-providers/networkConfig.ts +++ b/src-network-providers/networkConfig.ts @@ -1,5 +1,4 @@ import BigNumber from "bignumber.js"; -import { IChainID, IGasLimit, IGasPrice, ITransactionVersion } from "./interface"; /** * An object holding Network configuration parameters. @@ -8,10 +7,10 @@ export class NetworkConfig { /** * The chain ID. E.g. "1" for the Mainnet. */ - public ChainID: IChainID; + public ChainID: string; /** - * The gas required by the Network to process a byte of the {@link TransactionPayload}. + * The gas required by the Network to process a byte of the transaction data. */ public GasPerDataByte: number; /** @@ -33,25 +32,22 @@ export class NetworkConfig { */ public TopUpRewardsGradientPoint: BigNumber; - /** - * - */ public GasPriceModifier: number; /** - * The minimum gas limit required to be set when broadcasting a {@link Transaction}. + * The minimum gas limit required to be set when broadcasting a transaction. */ - public MinGasLimit: IGasLimit; + public MinGasLimit: number; /** - * The minimum gas price required to be set when broadcasting a {@link Transaction}. + * The minimum gas price required to be set when broadcasting a transaction. */ - public MinGasPrice: IGasPrice; + public MinGasPrice: number; /** * The oldest transaction version accepted by the Network. */ - public MinTransactionVersion: ITransactionVersion; + public MinTransactionVersion: number; constructor() { this.ChainID = "T"; diff --git a/src-network-providers/primitives.ts b/src-network-providers/primitives.ts index 1a32caa3..f123fd0a 100644 --- a/src-network-providers/primitives.ts +++ b/src-network-providers/primitives.ts @@ -1,4 +1,4 @@ -import { IAddress, IHash, INonce, ITransactionPayload } from "./interface"; +import { IBech32Address, IHash } from "./interface"; export class Hash implements IHash { private readonly value: string; @@ -12,7 +12,7 @@ export class Hash implements IHash { } } -export class Address implements IAddress { +export class Bech32Address implements IBech32Address { private readonly value: string; constructor(value: string) { @@ -24,7 +24,7 @@ export class Address implements IAddress { } } -export class Nonce implements INonce { +export class Nonce { private readonly value: number; constructor(value: number) { @@ -52,7 +52,7 @@ export class TransactionValue { } } -export class TransactionPayload implements ITransactionPayload { +export class TransactionPayload { private readonly decoded: Buffer; constructor(encoded: string) { diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index cdbfe610..25276442 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -3,16 +3,16 @@ import { INetworkProvider } from "./interface"; import { Hash } from "./primitives"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; -import { Address, Nonce } from "./primitives"; +import { Bech32Address, Nonce } from "./primitives"; import { MockQuery } from "./testscommon/dummyQuery"; import { ApiNetworkProvider } from "./apiNetworkProvider"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; describe("test network providers on devnet: Proxy and API", function () { - let alice = new Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); - let bob = new Address("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"); - let carol = new Address("erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8"); - let dan = new Address("erd1kyaqzaprcdnv4luvanah0gfxzzsnpaygsy6pytrexll2urtd05ts9vegu7"); + let alice = new Bech32Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); + let bob = new Bech32Address("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"); + let carol = new Bech32Address("erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8"); + let dan = new Bech32Address("erd1kyaqzaprcdnv4luvanah0gfxzzsnpaygsy6pytrexll2urtd05ts9vegu7"); let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 10000 }); let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.elrond.com", { timeout: 10000 }); @@ -193,7 +193,7 @@ describe("test network providers on devnet: Proxy and API", function () { it("should have same response for getNonFungibleToken()", async function () { this.timeout(10000); - let tokens = [{ id: "ERDJS-38f249", nonce: new Nonce(1) }]; + let tokens = [{ id: "ERDJS-38f249", nonce: 1 }]; for (const token of tokens) { let apiResponse = await apiProvider.getNonFungibleToken(token.id, token.nonce); diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 81741b44..e79f32f2 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -1,6 +1,6 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; -import { IAddress, IContractQuery, IHash, INetworkProvider, INonce, IPagination, ITransaction } from "./interface"; +import { IBech32Address, IContractQuery, IHash, INetworkProvider, IPagination, ITransaction } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; @@ -48,13 +48,13 @@ export class ProxyNetworkProvider implements INetworkProvider { throw new Error("Method not implemented."); } - async getAccount(address: IAddress): Promise { + async getAccount(address: IBech32Address): Promise { let response = await this.doGetGeneric(`address/${address.bech32()}`); let account = AccountOnNetwork.fromHttpResponse(response.account); return account; } - async getFungibleTokensOfAccount(address: IAddress, _pagination?: IPagination): Promise { + async getFungibleTokensOfAccount(address: IBech32Address, _pagination?: IPagination): Promise { let url = `address/${address.bech32()}/esdt`; let response = await this.doGetGeneric(url); let responseItems: any[] = Object.values(response.esdts); @@ -67,7 +67,7 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokens; } - async getNonFungibleTokensOfAccount(address: IAddress, _pagination?: IPagination): Promise { + async getNonFungibleTokensOfAccount(address: IBech32Address, _pagination?: IPagination): Promise { let url = `address/${address.bech32()}/esdt`; let response = await this.doGetGeneric(url); let responseItems: any[] = Object.values(response.esdts); @@ -80,13 +80,13 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokens; } - async getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise { + async getFungibleTokenOfAccount(address: IBech32Address, tokenIdentifier: string): Promise { let response = await this.doGetGeneric(`address/${address.bech32()}/esdt/${tokenIdentifier}`); let tokenData = FungibleTokenOfAccountOnNetwork.fromHttpResponse(response.tokenData); return tokenData; } - async getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: INonce): Promise { + async getNonFungibleTokenOfAccount(address: IBech32Address, collection: string, nonce: number): Promise { let response = await this.doGetGeneric(`address/${address.bech32()}/nft/${collection}/nonce/${nonce.valueOf()}`); let tokenData = NonFungibleTokenOfAccountOnNetwork.fromProxyHttpResponseByNonce(response.tokenData); return tokenData; @@ -138,7 +138,7 @@ export class ProxyNetworkProvider implements INetworkProvider { throw new Error("Method not implemented."); } - async getNonFungibleToken(_collection: string, _nonce: INonce): Promise { + async getNonFungibleToken(_collection: string, _nonce: number): Promise { throw new Error("Method not implemented."); } diff --git a/src-network-providers/tokenDefinitions.ts b/src-network-providers/tokenDefinitions.ts index 0a7f156d..9f6261d9 100644 --- a/src-network-providers/tokenDefinitions.ts +++ b/src-network-providers/tokenDefinitions.ts @@ -1,12 +1,12 @@ import { BigNumber } from "bignumber.js"; -import { Address } from "./primitives"; -import { IAddress } from "./interface"; +import { Bech32Address } from "./primitives"; +import { IBech32Address } from "./interface"; export class DefinitionOfFungibleTokenOnNetwork { identifier: string = ""; name: string = ""; ticker: string = ""; - owner: IAddress = new Address(""); + owner: IBech32Address = new Bech32Address(""); decimals: number = 0; supply: BigNumber = new BigNumber(0); isPaused: boolean = false; @@ -25,7 +25,7 @@ export class DefinitionOfFungibleTokenOnNetwork { result.identifier = payload.identifier || ""; result.name = payload.name || ""; result.ticker = payload.ticker || ""; - result.owner = new Address(payload.owner || ""); + result.owner = new Bech32Address(payload.owner || ""); result.decimals = payload.decimals || 0; result.supply = new BigNumber(payload.supply || "0"); result.isPaused = payload.isPaused || false; @@ -47,7 +47,7 @@ export class DefinitionOfTokenCollectionOnNetwork { type: string = ""; name: string = ""; ticker: string = ""; - owner: IAddress = new Address(""); + owner: IBech32Address = new Bech32Address(""); decimals: number = 0; canPause: boolean = false; canFreeze: boolean = false; @@ -61,7 +61,7 @@ export class DefinitionOfTokenCollectionOnNetwork { result.type = payload.type || ""; result.name = payload.name || ""; result.ticker = payload.ticker || ""; - result.owner = new Address(payload.owner || ""); + result.owner = new Bech32Address(payload.owner || ""); result.decimals = payload.decimals || 0; result.canPause = payload.canPause || false; result.canFreeze = payload.canFreeze || false; diff --git a/src-network-providers/tokens.ts b/src-network-providers/tokens.ts index 39e14033..d23394f2 100644 --- a/src-network-providers/tokens.ts +++ b/src-network-providers/tokens.ts @@ -1,6 +1,6 @@ import { BigNumber } from "bignumber.js"; -import { Address, Nonce } from "./primitives"; -import { IAddress, INonce } from "./interface"; +import { Bech32Address, Nonce } from "./primitives"; +import { IBech32Address } from "./interface"; export class FungibleTokenOfAccountOnNetwork { identifier: string = ""; @@ -21,10 +21,10 @@ export class NonFungibleTokenOfAccountOnNetwork { collection: string = ""; timestamp: number = 0; attributes: Buffer = Buffer.from([]); - nonce: INonce = new Nonce(0); + nonce: number = 0; type: string = ""; name: string = ""; - creator: IAddress = new Address(""); + creator: IBech32Address = new Bech32Address(""); supply: BigNumber = new BigNumber(0); decimals: number = 0; royalties: BigNumber = new BigNumber(0); @@ -46,8 +46,9 @@ export class NonFungibleTokenOfAccountOnNetwork { static fromProxyHttpResponseByNonce(payload: any): NonFungibleTokenOfAccountOnNetwork { let result = NonFungibleTokenOfAccountOnNetwork.fromHttpResponse(payload); + let nonceAsHex = new Nonce(result.nonce).hex(); - result.identifier = `${payload.tokenIdentifier}-${result.nonce.hex()}`; + result.identifier = `${payload.tokenIdentifier}-${nonceAsHex}`; result.collection = payload.tokenIdentifier || ""; result.royalties = new BigNumber(payload.royalties || 0).div(100); @@ -69,10 +70,10 @@ export class NonFungibleTokenOfAccountOnNetwork { result.timestamp = Number(payload.timestamp || 0); result.attributes = Buffer.from(payload.attributes || "", "base64"); - result.nonce = new Nonce(payload.nonce || 0); + result.nonce = payload.nonce || 0; result.type = payload.type || ""; result.name = payload.name || ""; - result.creator = new Address(payload.creator || ""); + result.creator = new Bech32Address(payload.creator || ""); result.decimals = Number(payload.decimals || 0); result.supply = new BigNumber(payload.balance || 1); result.royalties = new BigNumber(payload.royalties || 0); diff --git a/src-network-providers/transactionCompletionStrategy.ts b/src-network-providers/transactionCompletionStrategy.ts index e0fe457a..50cfea36 100644 --- a/src-network-providers/transactionCompletionStrategy.ts +++ b/src-network-providers/transactionCompletionStrategy.ts @@ -1,13 +1,12 @@ import { TransactionStatus } from "./transactionStatus"; -import { ITransactionPayload } from "./interface"; import { TransactionLogs } from "./transactionLogs"; -import { isPaddedHex } from "./primitives"; +import { isPaddedHex, TransactionPayload } from "./primitives"; interface ITransactionOnNetwork { logs: TransactionLogs; status: TransactionStatus; hyperblockNonce: number; - data: ITransactionPayload; + data: TransactionPayload; } const WellKnownCompletionEvents = ["completedTxEvent", "SCDeploy", "signalError"]; diff --git a/src-network-providers/transactionEvents.ts b/src-network-providers/transactionEvents.ts index 780a1034..d0505ce8 100644 --- a/src-network-providers/transactionEvents.ts +++ b/src-network-providers/transactionEvents.ts @@ -1,8 +1,8 @@ -import { IAddress } from "./interface"; -import { Address } from "./primitives"; +import { IBech32Address } from "./interface"; +import { Bech32Address } from "./primitives"; export class TransactionEvent { - address: IAddress = new Address(""); + address: IBech32Address = new Bech32Address(""); identifier: string = ""; topics: TransactionEventTopic[] = []; data: string = ""; @@ -18,7 +18,7 @@ export class TransactionEvent { data: string }): TransactionEvent { let result = new TransactionEvent(); - result.address = new Address(responsePart.address); + result.address = new Bech32Address(responsePart.address); result.identifier = responsePart.identifier || ""; result.topics = (responsePart.topics || []).map(topic => new TransactionEventTopic(topic)); result.data = Buffer.from(responsePart.data || "", "base64").toString(); diff --git a/src-network-providers/transactionLogs.ts b/src-network-providers/transactionLogs.ts index 91586ef0..608d712f 100644 --- a/src-network-providers/transactionLogs.ts +++ b/src-network-providers/transactionLogs.ts @@ -1,23 +1,23 @@ import { ErrUnexpectedCondition } from "./errors"; -import { IAddress } from "./interface"; -import { Address } from "./primitives"; +import { IBech32Address } from "./interface"; +import { Bech32Address } from "./primitives"; import { TransactionEvent } from "./transactionEvents"; export class TransactionLogs { - readonly address: IAddress; + readonly address: IBech32Address; readonly events: TransactionEvent[]; - constructor(address: IAddress, events: TransactionEvent[]) { + constructor(address: IBech32Address, events: TransactionEvent[]) { this.address = address; this.events = events; } static empty(): TransactionLogs { - return new TransactionLogs(new Address(""), []); + return new TransactionLogs(new Bech32Address(""), []); } static fromHttpResponse(logs: any): TransactionLogs { - let address = new Address(logs.address); + let address = new Bech32Address(logs.address); let events = (logs.events || []).map((event: any) => TransactionEvent.fromHttpResponse(event)); return new TransactionLogs(address, events); } diff --git a/src-network-providers/transactionReceipt.ts b/src-network-providers/transactionReceipt.ts index 35866169..b24aec64 100644 --- a/src-network-providers/transactionReceipt.ts +++ b/src-network-providers/transactionReceipt.ts @@ -1,9 +1,9 @@ -import { IAddress, IHash } from "./interface"; -import { Address, Hash, TransactionValue } from "./primitives"; +import { IBech32Address, IHash } from "./interface"; +import { Bech32Address, Hash, TransactionValue } from "./primitives"; export class TransactionReceipt { value: TransactionValue = new TransactionValue(""); - sender: IAddress = new Address(""); + sender: IBech32Address = new Bech32Address(""); data: string = ""; hash: IHash = new Hash(""); @@ -16,7 +16,7 @@ export class TransactionReceipt { let receipt = new TransactionReceipt(); receipt.value = new TransactionValue(response.value); - receipt.sender = new Address(response.sender); + receipt.sender = new Bech32Address(response.sender); receipt.data = response.data; receipt.hash = new Hash(response.txHash); diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index eaa43511..a479d06b 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -1,7 +1,7 @@ import { TransactionStatus } from "./transactionStatus"; import { ContractResults } from "./contractResults"; -import { Address, Hash, Nonce, TransactionValue, TransactionPayload } from "./primitives"; -import { IAddress, IGasLimit, IGasPrice, IHash, INonce, ITransactionPayload } from "./interface"; +import { Bech32Address, Hash, TransactionValue, TransactionPayload } from "./primitives"; +import { IBech32Address, IHash } from "./interface"; import { TransactionCompletionStrategyOnAPI, TransactionCompletionStrategyOnProxy } from "./transactionCompletionStrategy"; import { TransactionLogs } from "./transactionLogs"; import { TransactionReceipt } from "./transactionReceipt"; @@ -10,15 +10,15 @@ export class TransactionOnNetwork { isCompleted: boolean = false; hash: IHash = new Hash(""); type: string = ""; - nonce: INonce = new Nonce(0); + nonce: number = 0; round: number = 0; epoch: number = 0; value: TransactionValue = new TransactionValue(""); - receiver: IAddress = new Address(""); - sender: IAddress = new Address(""); - gasLimit: IGasLimit = 0; - gasPrice: IGasPrice = 0; - data: ITransactionPayload = new TransactionPayload(""); + receiver: IBech32Address = new Bech32Address(""); + sender: IBech32Address = new Bech32Address(""); + gasLimit: number = 0; + gasPrice: number = 0; + data: TransactionPayload = new TransactionPayload(""); signature: string = ""; status: TransactionStatus = TransactionStatus.createUnknown(); timestamp: number = 0; @@ -56,12 +56,12 @@ export class TransactionOnNetwork { result.hash = txHash; result.type = response.type || ""; - result.nonce = new Nonce(response.nonce || 0); + result.nonce = response.nonce || 0; result.round = response.round; result.epoch = response.epoch || 0; result.value = new TransactionValue((response.value || 0).toString()); - result.sender = new Address(response.sender); - result.receiver = new Address(response.receiver); + result.sender = new Bech32Address(response.sender); + result.receiver = new Bech32Address(response.receiver); result.gasPrice = response.gasPrice || 0; result.gasLimit = response.gasLimit || 0; result.data = new TransactionPayload(response.data); @@ -82,4 +82,3 @@ export class TransactionOnNetwork { return new Date(this.timestamp * 1000); } } - From a311e1ceb0c37f0c061e1dce49229f5aab31224e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Sun, 10 Apr 2022 00:30:46 +0300 Subject: [PATCH 060/133] Adjust config. --- src-network-providers/.npmignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 src-network-providers/.npmignore diff --git a/src-network-providers/.npmignore b/src-network-providers/.npmignore new file mode 100644 index 00000000..4c56e2af --- /dev/null +++ b/src-network-providers/.npmignore @@ -0,0 +1 @@ +src/testscommon/** From e2dc6312b29bd15ab3fd95488395a76dd2d6a4cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Sun, 10 Apr 2022 00:31:06 +0300 Subject: [PATCH 061/133] Simplification (string instead of AccountBalance). --- src-network-providers/accounts.ts | 6 +++--- src-network-providers/contractResults.ts | 6 +++--- src-network-providers/primitives.ts | 24 --------------------- src-network-providers/transactionReceipt.ts | 6 +++--- src-network-providers/transactions.ts | 6 +++--- 5 files changed, 12 insertions(+), 36 deletions(-) diff --git a/src-network-providers/accounts.ts b/src-network-providers/accounts.ts index c5602eb5..94a2dcab 100644 --- a/src-network-providers/accounts.ts +++ b/src-network-providers/accounts.ts @@ -1,5 +1,5 @@ import { IBech32Address } from "./interface"; -import { AccountBalance, Bech32Address } from "./primitives"; +import { Bech32Address } from "./primitives"; /** * A plain view of an account, as queried from the Network. @@ -7,7 +7,7 @@ import { AccountBalance, Bech32Address } from "./primitives"; export class AccountOnNetwork { address: IBech32Address = new Bech32Address(""); nonce: number = 0; - balance: AccountBalance = new AccountBalance(""); + balance: string = ""; code: string = ""; userName: string = ""; @@ -20,7 +20,7 @@ import { AccountBalance, Bech32Address } from "./primitives"; result.address = new Bech32Address(payload["address"] || 0); result.nonce = Number(payload["nonce"] || 0); - result.balance = new AccountBalance(payload["balance"] || "0"); + result.balance = (payload["balance"] || 0).toString(); result.code = payload["code"] || ""; result.userName = payload["username"] || ""; diff --git a/src-network-providers/contractResults.ts b/src-network-providers/contractResults.ts index 1eca3afc..a89c5678 100644 --- a/src-network-providers/contractResults.ts +++ b/src-network-providers/contractResults.ts @@ -1,6 +1,6 @@ import { IBech32Address, IHash } from "./interface"; import { TransactionLogs } from "./transactionLogs"; -import { Bech32Address, Hash, Nonce, TransactionValue } from "./primitives"; +import { Bech32Address, Hash } from "./primitives"; export class ContractResults { readonly items: ContractResultItem[]; @@ -31,7 +31,7 @@ export class ContractResults { export class ContractResultItem { hash: IHash = new Hash(""); nonce: number = 0; - value: TransactionValue = new TransactionValue(""); + value: string = ""; receiver: IBech32Address = new Bech32Address(""); sender: IBech32Address = new Bech32Address(""); data: string = ""; @@ -66,7 +66,7 @@ export class ContractResultItem { item.hash = new Hash(response.hash); item.nonce = Number(response.nonce || 0); - item.value = new TransactionValue((response.value || 0).toString()); + item.value = (response.value || 0).toString(); item.receiver = new Bech32Address(response.receiver); item.sender = new Bech32Address(response.sender); item.previousHash = new Hash(response.prevTxHash); diff --git a/src-network-providers/primitives.ts b/src-network-providers/primitives.ts index f123fd0a..2a28fd12 100644 --- a/src-network-providers/primitives.ts +++ b/src-network-providers/primitives.ts @@ -40,18 +40,6 @@ export class Nonce { } } -export class TransactionValue { - private readonly value: string; - - constructor(value: string) { - this.value = value; - } - - toString(): string { - return this.value; - } -} - export class TransactionPayload { private readonly decoded: Buffer; @@ -86,18 +74,6 @@ export class ContractReturnCode { } } -export class AccountBalance { - private readonly value: string; - - constructor(value: string) { - this.value = value; - } - - toString(): string { - return this.value; - } -} - export function numberToPaddedHex(value: number) { let hex = value.toString(16); return zeroPadStringIfOddLength(hex); diff --git a/src-network-providers/transactionReceipt.ts b/src-network-providers/transactionReceipt.ts index b24aec64..337bf384 100644 --- a/src-network-providers/transactionReceipt.ts +++ b/src-network-providers/transactionReceipt.ts @@ -1,8 +1,8 @@ import { IBech32Address, IHash } from "./interface"; -import { Bech32Address, Hash, TransactionValue } from "./primitives"; +import { Bech32Address, Hash } from "./primitives"; export class TransactionReceipt { - value: TransactionValue = new TransactionValue(""); + value: string = ""; sender: IBech32Address = new Bech32Address(""); data: string = ""; hash: IHash = new Hash(""); @@ -15,7 +15,7 @@ export class TransactionReceipt { }): TransactionReceipt { let receipt = new TransactionReceipt(); - receipt.value = new TransactionValue(response.value); + receipt.value = (response.value || 0).toString(); receipt.sender = new Bech32Address(response.sender); receipt.data = response.data; receipt.hash = new Hash(response.txHash); diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index a479d06b..8ddd330f 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -1,6 +1,6 @@ import { TransactionStatus } from "./transactionStatus"; import { ContractResults } from "./contractResults"; -import { Bech32Address, Hash, TransactionValue, TransactionPayload } from "./primitives"; +import { Bech32Address, Hash, TransactionPayload } from "./primitives"; import { IBech32Address, IHash } from "./interface"; import { TransactionCompletionStrategyOnAPI, TransactionCompletionStrategyOnProxy } from "./transactionCompletionStrategy"; import { TransactionLogs } from "./transactionLogs"; @@ -13,7 +13,7 @@ export class TransactionOnNetwork { nonce: number = 0; round: number = 0; epoch: number = 0; - value: TransactionValue = new TransactionValue(""); + value: string = ""; receiver: IBech32Address = new Bech32Address(""); sender: IBech32Address = new Bech32Address(""); gasLimit: number = 0; @@ -59,7 +59,7 @@ export class TransactionOnNetwork { result.nonce = response.nonce || 0; result.round = response.round; result.epoch = response.epoch || 0; - result.value = new TransactionValue((response.value || 0).toString()); + result.value = (response.value || 0).toString(); result.sender = new Bech32Address(response.sender); result.receiver = new Bech32Address(response.receiver); result.gasPrice = response.gasPrice || 0; From 9a41acfb69722a98c7b98f6017f70293f9590de8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Sun, 10 Apr 2022 12:56:38 +0300 Subject: [PATCH 062/133] Further simplification (transaction payload). --- src-network-providers/primitives.ts | 16 ---------------- .../transactionCompletionStrategy.ts | 10 +++++----- src-network-providers/transactions.ts | 6 +++--- 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/src-network-providers/primitives.ts b/src-network-providers/primitives.ts index 2a28fd12..6be2af43 100644 --- a/src-network-providers/primitives.ts +++ b/src-network-providers/primitives.ts @@ -40,22 +40,6 @@ export class Nonce { } } -export class TransactionPayload { - private readonly decoded: Buffer; - - constructor(encoded: string) { - this.decoded = Buffer.from(encoded || "", "base64"); - } - - encoded(): string { - return this.decoded.toString("base64"); - } - - toString() { - return this.decoded.toString(); - } -} - export class ContractReturnCode { private static OK: string = "ok"; diff --git a/src-network-providers/transactionCompletionStrategy.ts b/src-network-providers/transactionCompletionStrategy.ts index 50cfea36..cd072c20 100644 --- a/src-network-providers/transactionCompletionStrategy.ts +++ b/src-network-providers/transactionCompletionStrategy.ts @@ -1,12 +1,12 @@ import { TransactionStatus } from "./transactionStatus"; import { TransactionLogs } from "./transactionLogs"; -import { isPaddedHex, TransactionPayload } from "./primitives"; +import { isPaddedHex } from "./primitives"; interface ITransactionOnNetwork { logs: TransactionLogs; status: TransactionStatus; hyperblockNonce: number; - data: TransactionPayload; + data: Buffer; } const WellKnownCompletionEvents = ["completedTxEvent", "SCDeploy", "signalError"]; @@ -31,7 +31,7 @@ export class TransactionCompletionStrategyOnProxy { } } - if (this.isCertainlyMoveBalance(transaction.data.toString())) { + if (this.isCertainlyMoveBalance(transaction.data)) { return transaction.status.isExecuted(); } @@ -47,8 +47,8 @@ export class TransactionCompletionStrategyOnProxy { return false; } - private isCertainlyMoveBalance(transactionData: string): boolean { - let parts = transactionData.split("@"); + private isCertainlyMoveBalance(transactionData: Buffer): boolean { + let parts = transactionData.toString().split("@"); let prefix = parts[0]; let otherParts = parts.slice(1); let emptyPrefix = !prefix; diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index 8ddd330f..72801109 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -1,6 +1,6 @@ import { TransactionStatus } from "./transactionStatus"; import { ContractResults } from "./contractResults"; -import { Bech32Address, Hash, TransactionPayload } from "./primitives"; +import { Bech32Address, Hash } from "./primitives"; import { IBech32Address, IHash } from "./interface"; import { TransactionCompletionStrategyOnAPI, TransactionCompletionStrategyOnProxy } from "./transactionCompletionStrategy"; import { TransactionLogs } from "./transactionLogs"; @@ -18,7 +18,7 @@ export class TransactionOnNetwork { sender: IBech32Address = new Bech32Address(""); gasLimit: number = 0; gasPrice: number = 0; - data: TransactionPayload = new TransactionPayload(""); + data: Buffer = Buffer.from([]); signature: string = ""; status: TransactionStatus = TransactionStatus.createUnknown(); timestamp: number = 0; @@ -64,7 +64,7 @@ export class TransactionOnNetwork { result.receiver = new Bech32Address(response.receiver); result.gasPrice = response.gasPrice || 0; result.gasLimit = response.gasLimit || 0; - result.data = new TransactionPayload(response.data); + result.data = Buffer.from(response.data || "", "base64"); result.status = new TransactionStatus(response.status); result.timestamp = response.timestamp || 0; From 4b69eed66ee93ee7269b5ce57a2bee283561c304 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Sun, 10 Apr 2022 13:07:50 +0300 Subject: [PATCH 063/133] Simplification (contract return code is now a string). --- src-network-providers/contractQueryResponse.ts | 13 +++---------- src-network-providers/interface.ts | 5 ----- src-network-providers/primitives.ts | 18 ------------------ 3 files changed, 3 insertions(+), 33 deletions(-) diff --git a/src-network-providers/contractQueryResponse.ts b/src-network-providers/contractQueryResponse.ts index 79cc1452..40da0912 100644 --- a/src-network-providers/contractQueryResponse.ts +++ b/src-network-providers/contractQueryResponse.ts @@ -1,17 +1,15 @@ import BigNumber from "bignumber.js"; import { MaxUint64AsBigNumber } from "./constants"; -import { IContractReturnCode } from "./interface"; -import { ContractReturnCode } from "./primitives"; export class ContractQueryResponse { returnData: string[]; - returnCode: IContractReturnCode; + returnCode: string; returnMessage: string; gasUsed: number; constructor(init?: Partial) { this.returnData = init?.returnData || []; - this.returnCode = init?.returnCode || new ContractReturnCode(""); + this.returnCode = init?.returnCode || ""; this.returnMessage = init?.returnMessage || ""; this.gasUsed = init?.gasUsed || 0; } @@ -28,7 +26,7 @@ export class ContractQueryResponse { return new ContractQueryResponse({ returnData: returnData, - returnCode: new ContractReturnCode(returnCode), + returnCode: returnCode, returnMessage: returnMessage, gasUsed: gasUsed, }); @@ -38,16 +36,11 @@ export class ContractQueryResponse { return this.returnData.map((item) => Buffer.from(item || "", "base64")); } - isSuccess(): boolean { - return this.returnCode.isSuccess(); - } - /** * Converts the object to a pretty, plain JavaScript object. */ toJSON(): object { return { - success: this.isSuccess(), returnData: this.returnData, returnCode: this.returnCode, returnMessage: this.returnMessage, diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index 0040002b..014ad666 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -115,11 +115,6 @@ export interface IContractQuery { toHttpRequest(): any; } -export interface IContractReturnCode { - toString(): string; - isSuccess(): boolean; -} - export interface IPagination { from: number; size: number; diff --git a/src-network-providers/primitives.ts b/src-network-providers/primitives.ts index 6be2af43..a0b45e7f 100644 --- a/src-network-providers/primitives.ts +++ b/src-network-providers/primitives.ts @@ -40,24 +40,6 @@ export class Nonce { } } -export class ContractReturnCode { - private static OK: string = "ok"; - - private readonly value: string; - - constructor(value: string) { - this.value = value; - } - - toString() { - return this.value; - } - - isSuccess(): boolean { - return this.value == ContractReturnCode.OK; - } -} - export function numberToPaddedHex(value: number) { let hex = value.toString(16); return zeroPadStringIfOddLength(hex); From 9e1f86cda12a12a45176618ca0b42a44d546386d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Sun, 10 Apr 2022 15:10:00 +0300 Subject: [PATCH 064/133] Bring query.toHttpRequest() logic in network-providers. --- src-network-providers/apiNetworkProvider.ts | 4 +++- src-network-providers/contractQueryRequest.ts | 21 +++++++++++++++++++ src-network-providers/interface.ts | 7 +++++-- .../providers.dev.net.spec.ts | 16 +++++++------- src-network-providers/proxyNetworkProvider.ts | 4 +++- .../testscommon/dummyQuery.ts | 21 +++++++------------ 6 files changed, 48 insertions(+), 25 deletions(-) create mode 100644 src-network-providers/contractQueryRequest.ts diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 8d54a4c8..20a3c500 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -14,6 +14,7 @@ import { ErrContractQuery, ErrNetworkProvider } from "./errors"; import { defaultAxiosConfig, defaultPagination } from "./config"; import { NetworkStatus } from "./networkStatus"; import { ContractQueryResponse } from "./contractQueryResponse"; +import { ContractQueryRequest } from "./contractQueryRequest"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ApiNetworkProvider implements INetworkProvider { @@ -114,7 +115,8 @@ export class ApiNetworkProvider implements INetworkProvider { async queryContract(query: IContractQuery): Promise { try { - let response = await this.doPostGeneric("query", query.toHttpRequest()); + let request = new ContractQueryRequest(query).toHttpRequest(); + let response = await this.doPostGeneric("query", request); return ContractQueryResponse.fromHttpResponse(response); } catch (error: any) { throw new ErrContractQuery(error); diff --git a/src-network-providers/contractQueryRequest.ts b/src-network-providers/contractQueryRequest.ts new file mode 100644 index 00000000..69b9cebb --- /dev/null +++ b/src-network-providers/contractQueryRequest.ts @@ -0,0 +1,21 @@ +import { IContractQuery } from "./interface"; + +export class ContractQueryRequest { + private readonly query: IContractQuery; + + constructor(query: IContractQuery) { + this.query = query; + } + + toHttpRequest() { + let request: any = {}; + let query = this.query; + request.scAddress = query.address.bech32(); + request.caller = query.caller.bech32() ? query.caller.bech32() : undefined; + request.funcName = query.func.toString(); + request.value = query.value.toString(); + request.args = query.getEncodedArguments(); + + return request; + } +} diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index 014ad666..366b48b3 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -110,9 +110,12 @@ export interface INetworkProvider { doPostGeneric(resourceUrl: string, payload: any): Promise; } -// TODO: network-providers package should be responsible with formatting the http request. export interface IContractQuery { - toHttpRequest(): any; + address: IBech32Address; + caller: IBech32Address; + func: { toString(): string; }; + value: { toString(): string; }; + getEncodedArguments(): string[]; } export interface IPagination { diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 25276442..bcc39c2f 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -211,8 +211,8 @@ describe("test network providers on devnet: Proxy and API", function () { // Query: get sum (of adder contract) let query = new MockQuery({ - contract: "erd1qqqqqqqqqqqqqpgquykqja5c4v33zdmnwglj3jphqwrelzdn396qlc9g33", - function: "getSum" + address: new Bech32Address("erd1qqqqqqqqqqqqqpgquykqja5c4v33zdmnwglj3jphqwrelzdn396qlc9g33"), + func: "getSum" }); let apiResponse = await apiProvider.queryContract(query); @@ -227,9 +227,9 @@ describe("test network providers on devnet: Proxy and API", function () { // Query: increment counter query = new MockQuery({ - contract: "erd1qqqqqqqqqqqqqpgqzeq07xvhs5g7cg4ama85upaqarrcgu49396q0gz4yf", - function: "increment", - arguments: [] + address: new Bech32Address("erd1qqqqqqqqqqqqqpgqzeq07xvhs5g7cg4ama85upaqarrcgu49396q0gz4yf"), + func: "increment", + args: [] }); apiResponse = await apiProvider.queryContract(query); @@ -248,10 +248,10 @@ describe("test network providers on devnet: Proxy and API", function () { // Query: issue ESDT let query = new MockQuery({ - contract: "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u", - function: "issue", + address: new Bech32Address("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"), + func: "issue", value: "50000000000000000", - arguments: [ + args: [ Buffer.from("HELLO").toString("hex"), Buffer.from("WORLD").toString("hex"), "0A", // Supply diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index e79f32f2..8b0dac69 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -13,6 +13,7 @@ import { defaultAxiosConfig } from "./config"; import { NetworkStatus } from "./networkStatus"; import { ContractQueryResponse } from "./contractQueryResponse"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; +import { ContractQueryRequest } from "./contractQueryRequest"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ProxyNetworkProvider implements INetworkProvider { @@ -118,7 +119,8 @@ export class ProxyNetworkProvider implements INetworkProvider { async queryContract(query: IContractQuery): Promise { try { - let response = await this.doPostGeneric("vm-values/query", query.toHttpRequest()); + let request = new ContractQueryRequest(query).toHttpRequest(); + let response = await this.doPostGeneric("vm-values/query", request); return ContractQueryResponse.fromHttpResponse(response.data); } catch (error: any) { throw new ErrContractQuery(error); diff --git a/src-network-providers/testscommon/dummyQuery.ts b/src-network-providers/testscommon/dummyQuery.ts index 33befef3..437ac4b2 100644 --- a/src-network-providers/testscommon/dummyQuery.ts +++ b/src-network-providers/testscommon/dummyQuery.ts @@ -1,23 +1,18 @@ -import { IContractQuery } from "../interface"; +import { IBech32Address, IContractQuery } from "../interface"; +import { Bech32Address } from "../primitives"; export class MockQuery implements IContractQuery { - contract: string = ""; - function: string = ""; - arguments: string[] = []; + caller: IBech32Address = new Bech32Address(""); + address: IBech32Address = new Bech32Address(""); + func: string = ""; + args: string[] = []; value: string = ""; - caller: string = ""; constructor(init?: Partial) { Object.assign(this, init); } - toHttpRequest() { - return { - "scAddress": this.contract, - "funcName": this.function, - "args": this.arguments, - "value": this.value, - "caller": this.caller - }; + getEncodedArguments(): string[] { + return this.args; } } From 7768419bbd732496384ee6f31e299c6b19f7a8e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Sun, 10 Apr 2022 19:05:38 +0300 Subject: [PATCH 065/133] Simplification: string instead of IHash. --- src-network-providers/apiNetworkProvider.ts | 17 +++++++-------- src-network-providers/contractResults.ts | 16 +++++++------- src-network-providers/interface.ts | 7 +++---- src-network-providers/primitives.ts | 14 +------------ .../providers.dev.net.spec.ts | 21 +++++++++---------- src-network-providers/proxyNetworkProvider.ts | 16 +++++++------- src-network-providers/transactionReceipt.ts | 8 +++---- src-network-providers/transactions.ts | 12 +++++------ 8 files changed, 47 insertions(+), 64 deletions(-) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 20a3c500..5e7f4eb1 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -1,6 +1,6 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; -import { IBech32Address, IContractQuery, IHash, INetworkProvider, ITransaction, IPagination } from "./interface"; +import { IBech32Address, IContractQuery, INetworkProvider, ITransaction, IPagination } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; @@ -9,7 +9,7 @@ import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwor import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; -import { Hash, Nonce } from "./primitives"; +import { Nonce } from "./primitives"; import { ErrContractQuery, ErrNetworkProvider } from "./errors"; import { defaultAxiosConfig, defaultPagination } from "./config"; import { NetworkStatus } from "./networkStatus"; @@ -91,22 +91,21 @@ export class ApiNetworkProvider implements INetworkProvider { return tokenData; } - async getTransaction(txHash: IHash): Promise { - let response = await this.doGetGeneric(`transactions/${txHash.hex()}`); + async getTransaction(txHash: string): Promise { + let response = await this.doGetGeneric(`transactions/${txHash}`); let transaction = TransactionOnNetwork.fromApiHttpResponse(txHash, response); return transaction; } - async getTransactionStatus(txHash: IHash): Promise { - let response = await this.doGetGeneric(`transactions/${txHash.hex()}?fields=status`); + async getTransactionStatus(txHash: string): Promise { + let response = await this.doGetGeneric(`transactions/${txHash}?fields=status`); let status = new TransactionStatus(response.status); return status; } - async sendTransaction(tx: ITransaction): Promise { + async sendTransaction(tx: ITransaction): Promise { let response = await this.doPostGeneric("transactions", tx.toSendable()); - let hash = new Hash(response.txHash); - return hash; + return response.txHash; } async simulateTransaction(tx: ITransaction): Promise { diff --git a/src-network-providers/contractResults.ts b/src-network-providers/contractResults.ts index a89c5678..6d431fe7 100644 --- a/src-network-providers/contractResults.ts +++ b/src-network-providers/contractResults.ts @@ -1,6 +1,6 @@ -import { IBech32Address, IHash } from "./interface"; +import { IBech32Address } from "./interface"; import { TransactionLogs } from "./transactionLogs"; -import { Bech32Address, Hash } from "./primitives"; +import { Bech32Address } from "./primitives"; export class ContractResults { readonly items: ContractResultItem[]; @@ -29,14 +29,14 @@ export class ContractResults { } export class ContractResultItem { - hash: IHash = new Hash(""); + hash: string = ""; nonce: number = 0; value: string = ""; receiver: IBech32Address = new Bech32Address(""); sender: IBech32Address = new Bech32Address(""); data: string = ""; - previousHash: Hash = new Hash(""); - originalHash: Hash = new Hash(""); + previousHash: string = ""; + originalHash: string = ""; gasLimit: number = 0; gasPrice: number = 0; callType: number = 0; @@ -64,13 +64,13 @@ export class ContractResultItem { private static fromHttpResponse(response: any): ContractResultItem { let item = new ContractResultItem(); - item.hash = new Hash(response.hash); + item.hash = response.hash; item.nonce = Number(response.nonce || 0); item.value = (response.value || 0).toString(); item.receiver = new Bech32Address(response.receiver); item.sender = new Bech32Address(response.sender); - item.previousHash = new Hash(response.prevTxHash); - item.originalHash = new Hash(response.originalTxHash); + item.previousHash = response.prevTxHash; + item.originalHash = response.originalTxHash; item.gasLimit = Number(response.gasLimit || 0); item.gasPrice = Number(response.gasPrice || 0); item.data = response.data || ""; diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index 366b48b3..21d70170 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -61,17 +61,17 @@ export interface INetworkProvider { /** * Fetches the state of a transaction. */ - getTransaction(txHash: IHash): Promise; + getTransaction(txHash: string): Promise; /** * Queries the status of a transaction. */ - getTransactionStatus(txHash: IHash): Promise; + getTransactionStatus(txHash: string): Promise; /** * Broadcasts an already-signed transaction. */ - sendTransaction(tx: ITransaction): Promise; + sendTransaction(tx: ITransaction): Promise; /** * Simulates the processing of an already-signed transaction. @@ -127,5 +127,4 @@ export interface ITransaction { toSendable(): any; } -export interface IHash { hex(): string; } export interface IBech32Address { bech32(): string; } diff --git a/src-network-providers/primitives.ts b/src-network-providers/primitives.ts index a0b45e7f..a39edfee 100644 --- a/src-network-providers/primitives.ts +++ b/src-network-providers/primitives.ts @@ -1,16 +1,4 @@ -import { IBech32Address, IHash } from "./interface"; - -export class Hash implements IHash { - private readonly value: string; - - constructor(value: string) { - this.value = value; - } - - hex(): string { - return this.value; - } -} +import { IBech32Address } from "./interface"; export class Bech32Address implements IBech32Address { private readonly value: string; diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index bcc39c2f..6f55c7f8 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -1,6 +1,5 @@ import { assert } from "chai"; import { INetworkProvider } from "./interface"; -import { Hash } from "./primitives"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { Bech32Address, Nonce } from "./primitives"; @@ -104,12 +103,12 @@ describe("test network providers on devnet: Proxy and API", function () { this.timeout(20000); let hashes = [ - new Hash("a069c663831002651fd542479869cc61103465f3284dace772e7480f81429fa8"), - new Hash("de3bc87f3e057e28ea6a625acd6d6d332e24f35ea73e820462b71256c8ecffb7"), - new Hash("dbefa0299fe6b2336eb0bc3123fa623845c276e5c6e2a175adf1a562d5e77718"), - new Hash("2a8ccbd91b7d9460a86174b5a8d4e6aa073b38674d1ee8107e728980a66f0676"), + "a069c663831002651fd542479869cc61103465f3284dace772e7480f81429fa8", + "de3bc87f3e057e28ea6a625acd6d6d332e24f35ea73e820462b71256c8ecffb7", + "dbefa0299fe6b2336eb0bc3123fa623845c276e5c6e2a175adf1a562d5e77718", + "2a8ccbd91b7d9460a86174b5a8d4e6aa073b38674d1ee8107e728980a66f0676", // TODO: uncomment after fix (SCR missing on API) - // new TransactionHash("be7914b1eb4c6bd352ba1d86991959b443e446e0ad49fb796be3495c287b2472") + // "be7914b1eb4c6bd352ba1d86991959b443e446e0ad49fb796be3495c287b2472" ]; for (const hash of hashes) { @@ -143,11 +142,11 @@ describe("test network providers on devnet: Proxy and API", function () { this.timeout(20000); let hashes = [ - new Hash("a069c663831002651fd542479869cc61103465f3284dace772e7480f81429fa8"), - new Hash("de3bc87f3e057e28ea6a625acd6d6d332e24f35ea73e820462b71256c8ecffb7"), - new Hash("dbefa0299fe6b2336eb0bc3123fa623845c276e5c6e2a175adf1a562d5e77718"), - new Hash("2a8ccbd91b7d9460a86174b5a8d4e6aa073b38674d1ee8107e728980a66f0676"), - new Hash("be7914b1eb4c6bd352ba1d86991959b443e446e0ad49fb796be3495c287b2472") + "a069c663831002651fd542479869cc61103465f3284dace772e7480f81429fa8", + "de3bc87f3e057e28ea6a625acd6d6d332e24f35ea73e820462b71256c8ecffb7", + "dbefa0299fe6b2336eb0bc3123fa623845c276e5c6e2a175adf1a562d5e77718", + "2a8ccbd91b7d9460a86174b5a8d4e6aa073b38674d1ee8107e728980a66f0676", + "be7914b1eb4c6bd352ba1d86991959b443e446e0ad49fb796be3495c287b2472" ]; for (const hash of hashes) { diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 8b0dac69..ba7c6233 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -1,13 +1,12 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; -import { IBech32Address, IContractQuery, IHash, INetworkProvider, IPagination, ITransaction } from "./interface"; +import { IBech32Address, IContractQuery, INetworkProvider, IPagination, ITransaction } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; -import { Hash } from "./primitives"; import { ErrContractQuery, ErrNetworkProvider } from "./errors"; import { defaultAxiosConfig } from "./config"; import { NetworkStatus } from "./networkStatus"; @@ -93,23 +92,22 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokenData; } - async getTransaction(txHash: IHash): Promise { - let url = this.buildUrlWithQueryParameters(`transaction/${txHash.hex()}`, { withResults: "true" }); + async getTransaction(txHash: string): Promise { + let url = this.buildUrlWithQueryParameters(`transaction/${txHash}`, { withResults: "true" }); let response = await this.doGetGeneric(url); let transaction = TransactionOnNetwork.fromProxyHttpResponse(txHash, response.transaction); return transaction; } - async getTransactionStatus(txHash: IHash): Promise { - let response = await this.doGetGeneric(`transaction/${txHash.hex()}/status`); + async getTransactionStatus(txHash: string): Promise { + let response = await this.doGetGeneric(`transaction/${txHash}/status`); let status = new TransactionStatus(response.status); return status; } - async sendTransaction(tx: ITransaction): Promise { + async sendTransaction(tx: ITransaction): Promise { let response = await this.doPostGeneric("transaction/send", tx.toSendable()); - let hash = new Hash(response.txHash); - return hash; + return response.txHash; } async simulateTransaction(tx: ITransaction): Promise { diff --git a/src-network-providers/transactionReceipt.ts b/src-network-providers/transactionReceipt.ts index 337bf384..0cad1476 100644 --- a/src-network-providers/transactionReceipt.ts +++ b/src-network-providers/transactionReceipt.ts @@ -1,11 +1,11 @@ -import { IBech32Address, IHash } from "./interface"; -import { Bech32Address, Hash } from "./primitives"; +import { IBech32Address } from "./interface"; +import { Bech32Address } from "./primitives"; export class TransactionReceipt { value: string = ""; sender: IBech32Address = new Bech32Address(""); data: string = ""; - hash: IHash = new Hash(""); + hash: string = ""; static fromHttpResponse(response: { value: string, @@ -18,7 +18,7 @@ export class TransactionReceipt { receipt.value = (response.value || 0).toString(); receipt.sender = new Bech32Address(response.sender); receipt.data = response.data; - receipt.hash = new Hash(response.txHash); + receipt.hash = response.txHash; return receipt; } diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index 72801109..542f708d 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -1,14 +1,14 @@ import { TransactionStatus } from "./transactionStatus"; import { ContractResults } from "./contractResults"; -import { Bech32Address, Hash } from "./primitives"; -import { IBech32Address, IHash } from "./interface"; +import { Bech32Address } from "./primitives"; +import { IBech32Address } from "./interface"; import { TransactionCompletionStrategyOnAPI, TransactionCompletionStrategyOnProxy } from "./transactionCompletionStrategy"; import { TransactionLogs } from "./transactionLogs"; import { TransactionReceipt } from "./transactionReceipt"; export class TransactionOnNetwork { isCompleted: boolean = false; - hash: IHash = new Hash(""); + hash: string = ""; type: string = ""; nonce: number = 0; round: number = 0; @@ -35,7 +35,7 @@ export class TransactionOnNetwork { Object.assign(this, init); } - static fromProxyHttpResponse(txHash: IHash, response: any): TransactionOnNetwork { + static fromProxyHttpResponse(txHash: string, response: any): TransactionOnNetwork { let result = TransactionOnNetwork.fromHttpResponse(txHash, response); result.contractResults = ContractResults.fromProxyHttpResponse(response.smartContractResults || []); result.isCompleted = new TransactionCompletionStrategyOnProxy().isCompleted(result); @@ -43,7 +43,7 @@ export class TransactionOnNetwork { return result; } - static fromApiHttpResponse(txHash: IHash, response: any): TransactionOnNetwork { + static fromApiHttpResponse(txHash: string, response: any): TransactionOnNetwork { let result = TransactionOnNetwork.fromHttpResponse(txHash, response); result.contractResults = ContractResults.fromApiHttpResponse(response.results || []); result.isCompleted = new TransactionCompletionStrategyOnAPI().isCompleted(result); @@ -51,7 +51,7 @@ export class TransactionOnNetwork { return result; } - private static fromHttpResponse(txHash: IHash, response: any): TransactionOnNetwork { + private static fromHttpResponse(txHash: string, response: any): TransactionOnNetwork { let result = new TransactionOnNetwork(); result.hash = txHash; From a6d1310ee75de759d92b568dbb768517b0150487 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 12 Apr 2022 16:15:07 +0300 Subject: [PATCH 066/133] Account.balance as bigNumber. --- src-network-providers/accounts.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src-network-providers/accounts.ts b/src-network-providers/accounts.ts index 94a2dcab..9249bcb8 100644 --- a/src-network-providers/accounts.ts +++ b/src-network-providers/accounts.ts @@ -1,3 +1,4 @@ +import BigNumber from "bignumber.js"; import { IBech32Address } from "./interface"; import { Bech32Address } from "./primitives"; @@ -7,7 +8,7 @@ import { Bech32Address } from "./primitives"; export class AccountOnNetwork { address: IBech32Address = new Bech32Address(""); nonce: number = 0; - balance: string = ""; + balance: BigNumber = new BigNumber(0); code: string = ""; userName: string = ""; @@ -20,7 +21,7 @@ import { Bech32Address } from "./primitives"; result.address = new Bech32Address(payload["address"] || 0); result.nonce = Number(payload["nonce"] || 0); - result.balance = (payload["balance"] || 0).toString(); + result.balance = new BigNumber(payload["balance"] || 0); result.code = payload["code"] || ""; result.userName = payload["username"] || ""; From 2cc0af34548e3460e580200ca40a7bf80e161f2e Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 12 Apr 2022 21:52:56 +0300 Subject: [PATCH 067/133] Rename class (Bech32Address to Address). --- src-network-providers/accounts.ts | 8 ++++---- src-network-providers/apiNetworkProvider.ts | 12 ++++++------ src-network-providers/constants.ts | 1 + src-network-providers/contractResults.ts | 12 ++++++------ src-network-providers/interface.ts | 18 +++++++++--------- src-network-providers/primitives.ts | 16 ++++++++++++++-- .../providers.dev.net.spec.ts | 16 ++++++++-------- src-network-providers/proxyNetworkProvider.ts | 12 ++++++------ .../testscommon/dummyQuery.ts | 8 ++++---- src-network-providers/tokenDefinitions.ts | 12 ++++++------ src-network-providers/tokens.ts | 8 ++++---- src-network-providers/transactionEvents.ts | 8 ++++---- src-network-providers/transactionLogs.ts | 8 ++++---- src-network-providers/transactionReceipt.ts | 8 ++++---- src-network-providers/transactions.ts | 12 ++++++------ 15 files changed, 86 insertions(+), 73 deletions(-) diff --git a/src-network-providers/accounts.ts b/src-network-providers/accounts.ts index 9249bcb8..637248ac 100644 --- a/src-network-providers/accounts.ts +++ b/src-network-providers/accounts.ts @@ -1,12 +1,12 @@ import BigNumber from "bignumber.js"; -import { IBech32Address } from "./interface"; -import { Bech32Address } from "./primitives"; +import { IAddress } from "./interface"; +import { Address } from "./primitives"; /** * A plain view of an account, as queried from the Network. */ export class AccountOnNetwork { - address: IBech32Address = new Bech32Address(""); + address: IAddress = new Address(""); nonce: number = 0; balance: BigNumber = new BigNumber(0); code: string = ""; @@ -19,7 +19,7 @@ import { Bech32Address } from "./primitives"; static fromHttpResponse(payload: any): AccountOnNetwork { let result = new AccountOnNetwork(); - result.address = new Bech32Address(payload["address"] || 0); + result.address = new Address(payload["address"] || 0); result.nonce = Number(payload["nonce"] || 0); result.balance = new BigNumber(payload["balance"] || 0); result.code = payload["code"] || ""; diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 5e7f4eb1..dea1f7c3 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -1,6 +1,6 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; -import { IBech32Address, IContractQuery, INetworkProvider, ITransaction, IPagination } from "./interface"; +import { IAddress, IContractQuery, INetworkProvider, ITransaction, IPagination } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; @@ -48,13 +48,13 @@ export class ApiNetworkProvider implements INetworkProvider { return stats; } - async getAccount(address: IBech32Address): Promise { + async getAccount(address: IAddress): Promise { let response = await this.doGetGeneric(`accounts/${address.bech32()}`); let account = AccountOnNetwork.fromHttpResponse(response); return account; } - async getFungibleTokensOfAccount(address: IBech32Address, pagination?: IPagination): Promise { + async getFungibleTokensOfAccount(address: IAddress, pagination?: IPagination): Promise { pagination = pagination || defaultPagination; let url = `accounts/${address.bech32()}/tokens?${this.buildPaginationParams(pagination)}`; @@ -66,7 +66,7 @@ export class ApiNetworkProvider implements INetworkProvider { return tokens; } - async getNonFungibleTokensOfAccount(address: IBech32Address, pagination?: IPagination): Promise { + async getNonFungibleTokensOfAccount(address: IAddress, pagination?: IPagination): Promise { pagination = pagination || defaultPagination; let url = `accounts/${address.bech32()}/nfts?${this.buildPaginationParams(pagination)}`; @@ -78,13 +78,13 @@ export class ApiNetworkProvider implements INetworkProvider { return tokens; } - async getFungibleTokenOfAccount(address: IBech32Address, tokenIdentifier: string): Promise { + async getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise { let response = await this.doGetGeneric(`accounts/${address.bech32()}/tokens/${tokenIdentifier}`); let tokenData = FungibleTokenOfAccountOnNetwork.fromHttpResponse(response); return tokenData; } - async getNonFungibleTokenOfAccount(address: IBech32Address, collection: string, nonce: number): Promise { + async getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: number): Promise { let nonceAsHex = new Nonce(nonce).hex(); let response = await this.doGetGeneric(`accounts/${address.bech32()}/nfts/${collection}-${nonceAsHex}`); let tokenData = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response); diff --git a/src-network-providers/constants.ts b/src-network-providers/constants.ts index f4ab70a0..c79f74a6 100644 --- a/src-network-providers/constants.ts +++ b/src-network-providers/constants.ts @@ -1,3 +1,4 @@ import BigNumber from "bignumber.js"; +import { Address } from "./primitives"; export const MaxUint64AsBigNumber = new BigNumber("18446744073709551615"); diff --git a/src-network-providers/contractResults.ts b/src-network-providers/contractResults.ts index 5d2debf2..37046fb0 100644 --- a/src-network-providers/contractResults.ts +++ b/src-network-providers/contractResults.ts @@ -1,6 +1,6 @@ -import { IBech32Address } from "./interface"; +import { IAddress } from "./interface"; import { TransactionLogs } from "./transactionLogs"; -import { Bech32Address } from "./primitives"; +import { Address } from "./primitives"; export class ContractResults { readonly items: ContractResultItem[]; @@ -28,8 +28,8 @@ export class ContractResultItem { hash: string = ""; nonce: number = 0; value: string = ""; - receiver: IBech32Address = new Bech32Address(""); - sender: IBech32Address = new Bech32Address(""); + receiver: IAddress = new Address(""); + sender: IAddress = new Address(""); data: string = ""; previousHash: string = ""; originalHash: string = ""; @@ -63,8 +63,8 @@ export class ContractResultItem { item.hash = response.hash; item.nonce = Number(response.nonce || 0); item.value = (response.value || 0).toString(); - item.receiver = new Bech32Address(response.receiver); - item.sender = new Bech32Address(response.sender); + item.receiver = new Address(response.receiver); + item.sender = new Address(response.sender); item.previousHash = response.prevTxHash; item.originalHash = response.originalTxHash; item.gasLimit = Number(response.gasLimit || 0); diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index 21d70170..4d44c32e 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -36,27 +36,27 @@ export interface INetworkProvider { /** * Fetches the state of an account. */ - getAccount(address: IBech32Address): Promise; + getAccount(address: IAddress): Promise; /** * Fetches data about the fungible tokens held by an account. */ - getFungibleTokensOfAccount(address: IBech32Address, pagination?: IPagination): Promise; + getFungibleTokensOfAccount(address: IAddress, pagination?: IPagination): Promise; /** * Fetches data about the non-fungible tokens held by account. */ - getNonFungibleTokensOfAccount(address: IBech32Address, pagination?: IPagination): Promise; + getNonFungibleTokensOfAccount(address: IAddress, pagination?: IPagination): Promise; /** * Fetches data about a specific fungible token held by an account. */ - getFungibleTokenOfAccount(address: IBech32Address, tokenIdentifier: string): Promise; + getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise; /** * Fetches data about a specific non-fungible token (instance) held by an account. */ - getNonFungibleTokenOfAccount(address: IBech32Address, collection: string, nonce: number): Promise; + getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: number): Promise; /** * Fetches the state of a transaction. @@ -111,10 +111,10 @@ export interface INetworkProvider { } export interface IContractQuery { - address: IBech32Address; - caller: IBech32Address; + address: IAddress; + caller?: IAddress; func: { toString(): string; }; - value: { toString(): string; }; + value?: { toString(): string; }; getEncodedArguments(): string[]; } @@ -127,4 +127,4 @@ export interface ITransaction { toSendable(): any; } -export interface IBech32Address { bech32(): string; } +export interface IAddress { bech32(): string; } diff --git a/src-network-providers/primitives.ts b/src-network-providers/primitives.ts index a39edfee..fecbbace 100644 --- a/src-network-providers/primitives.ts +++ b/src-network-providers/primitives.ts @@ -1,12 +1,24 @@ -import { IBech32Address } from "./interface"; +import * as bech32 from "bech32"; +import { IAddress } from "./interface"; -export class Bech32Address implements IBech32Address { +/** + * The human-readable-part of the bech32 addresses. + */ +const HRP = "erd"; + +export class Address implements IAddress { private readonly value: string; constructor(value: string) { this.value = value; } + static fromPubkey(pubkey: Buffer): IAddress { + let words = bech32.toWords(pubkey); + let address = bech32.encode(HRP, words); + return new Address(address); + } + bech32(): string { return this.value; } diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 6f55c7f8..c9a9f48d 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -2,16 +2,16 @@ import { assert } from "chai"; import { INetworkProvider } from "./interface"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; -import { Bech32Address, Nonce } from "./primitives"; +import { Address } from "./primitives"; import { MockQuery } from "./testscommon/dummyQuery"; import { ApiNetworkProvider } from "./apiNetworkProvider"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; describe("test network providers on devnet: Proxy and API", function () { - let alice = new Bech32Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); - let bob = new Bech32Address("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"); - let carol = new Bech32Address("erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8"); - let dan = new Bech32Address("erd1kyaqzaprcdnv4luvanah0gfxzzsnpaygsy6pytrexll2urtd05ts9vegu7"); + let alice = new Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); + let bob = new Address("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"); + let carol = new Address("erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8"); + let dan = new Address("erd1kyaqzaprcdnv4luvanah0gfxzzsnpaygsy6pytrexll2urtd05ts9vegu7"); let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 10000 }); let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.elrond.com", { timeout: 10000 }); @@ -210,7 +210,7 @@ describe("test network providers on devnet: Proxy and API", function () { // Query: get sum (of adder contract) let query = new MockQuery({ - address: new Bech32Address("erd1qqqqqqqqqqqqqpgquykqja5c4v33zdmnwglj3jphqwrelzdn396qlc9g33"), + address: new Address("erd1qqqqqqqqqqqqqpgquykqja5c4v33zdmnwglj3jphqwrelzdn396qlc9g33"), func: "getSum" }); @@ -226,7 +226,7 @@ describe("test network providers on devnet: Proxy and API", function () { // Query: increment counter query = new MockQuery({ - address: new Bech32Address("erd1qqqqqqqqqqqqqpgqzeq07xvhs5g7cg4ama85upaqarrcgu49396q0gz4yf"), + address: new Address("erd1qqqqqqqqqqqqqpgqzeq07xvhs5g7cg4ama85upaqarrcgu49396q0gz4yf"), func: "increment", args: [] }); @@ -247,7 +247,7 @@ describe("test network providers on devnet: Proxy and API", function () { // Query: issue ESDT let query = new MockQuery({ - address: new Bech32Address("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"), + address: new Address("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"), func: "issue", value: "50000000000000000", args: [ diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index ba7c6233..f7b3d579 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -1,6 +1,6 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; -import { IBech32Address, IContractQuery, INetworkProvider, IPagination, ITransaction } from "./interface"; +import { IAddress, IContractQuery, INetworkProvider, IPagination, ITransaction } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkStake } from "./networkStake"; import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; @@ -48,13 +48,13 @@ export class ProxyNetworkProvider implements INetworkProvider { throw new Error("Method not implemented."); } - async getAccount(address: IBech32Address): Promise { + async getAccount(address: IAddress): Promise { let response = await this.doGetGeneric(`address/${address.bech32()}`); let account = AccountOnNetwork.fromHttpResponse(response.account); return account; } - async getFungibleTokensOfAccount(address: IBech32Address, _pagination?: IPagination): Promise { + async getFungibleTokensOfAccount(address: IAddress, _pagination?: IPagination): Promise { let url = `address/${address.bech32()}/esdt`; let response = await this.doGetGeneric(url); let responseItems: any[] = Object.values(response.esdts); @@ -67,7 +67,7 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokens; } - async getNonFungibleTokensOfAccount(address: IBech32Address, _pagination?: IPagination): Promise { + async getNonFungibleTokensOfAccount(address: IAddress, _pagination?: IPagination): Promise { let url = `address/${address.bech32()}/esdt`; let response = await this.doGetGeneric(url); let responseItems: any[] = Object.values(response.esdts); @@ -80,13 +80,13 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokens; } - async getFungibleTokenOfAccount(address: IBech32Address, tokenIdentifier: string): Promise { + async getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise { let response = await this.doGetGeneric(`address/${address.bech32()}/esdt/${tokenIdentifier}`); let tokenData = FungibleTokenOfAccountOnNetwork.fromHttpResponse(response.tokenData); return tokenData; } - async getNonFungibleTokenOfAccount(address: IBech32Address, collection: string, nonce: number): Promise { + async getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: number): Promise { let response = await this.doGetGeneric(`address/${address.bech32()}/nft/${collection}/nonce/${nonce.valueOf()}`); let tokenData = NonFungibleTokenOfAccountOnNetwork.fromProxyHttpResponseByNonce(response.tokenData); return tokenData; diff --git a/src-network-providers/testscommon/dummyQuery.ts b/src-network-providers/testscommon/dummyQuery.ts index 437ac4b2..a0cdac9c 100644 --- a/src-network-providers/testscommon/dummyQuery.ts +++ b/src-network-providers/testscommon/dummyQuery.ts @@ -1,9 +1,9 @@ -import { IBech32Address, IContractQuery } from "../interface"; -import { Bech32Address } from "../primitives"; +import { IAddress, IContractQuery } from "../interface"; +import { Address } from "../primitives"; export class MockQuery implements IContractQuery { - caller: IBech32Address = new Bech32Address(""); - address: IBech32Address = new Bech32Address(""); + caller: IAddress = new Address(""); + address: IAddress = new Address(""); func: string = ""; args: string[] = []; value: string = ""; diff --git a/src-network-providers/tokenDefinitions.ts b/src-network-providers/tokenDefinitions.ts index 9f6261d9..0a7f156d 100644 --- a/src-network-providers/tokenDefinitions.ts +++ b/src-network-providers/tokenDefinitions.ts @@ -1,12 +1,12 @@ import { BigNumber } from "bignumber.js"; -import { Bech32Address } from "./primitives"; -import { IBech32Address } from "./interface"; +import { Address } from "./primitives"; +import { IAddress } from "./interface"; export class DefinitionOfFungibleTokenOnNetwork { identifier: string = ""; name: string = ""; ticker: string = ""; - owner: IBech32Address = new Bech32Address(""); + owner: IAddress = new Address(""); decimals: number = 0; supply: BigNumber = new BigNumber(0); isPaused: boolean = false; @@ -25,7 +25,7 @@ export class DefinitionOfFungibleTokenOnNetwork { result.identifier = payload.identifier || ""; result.name = payload.name || ""; result.ticker = payload.ticker || ""; - result.owner = new Bech32Address(payload.owner || ""); + result.owner = new Address(payload.owner || ""); result.decimals = payload.decimals || 0; result.supply = new BigNumber(payload.supply || "0"); result.isPaused = payload.isPaused || false; @@ -47,7 +47,7 @@ export class DefinitionOfTokenCollectionOnNetwork { type: string = ""; name: string = ""; ticker: string = ""; - owner: IBech32Address = new Bech32Address(""); + owner: IAddress = new Address(""); decimals: number = 0; canPause: boolean = false; canFreeze: boolean = false; @@ -61,7 +61,7 @@ export class DefinitionOfTokenCollectionOnNetwork { result.type = payload.type || ""; result.name = payload.name || ""; result.ticker = payload.ticker || ""; - result.owner = new Bech32Address(payload.owner || ""); + result.owner = new Address(payload.owner || ""); result.decimals = payload.decimals || 0; result.canPause = payload.canPause || false; result.canFreeze = payload.canFreeze || false; diff --git a/src-network-providers/tokens.ts b/src-network-providers/tokens.ts index d23394f2..5a574507 100644 --- a/src-network-providers/tokens.ts +++ b/src-network-providers/tokens.ts @@ -1,6 +1,6 @@ import { BigNumber } from "bignumber.js"; -import { Bech32Address, Nonce } from "./primitives"; -import { IBech32Address } from "./interface"; +import { Address, Nonce } from "./primitives"; +import { IAddress } from "./interface"; export class FungibleTokenOfAccountOnNetwork { identifier: string = ""; @@ -24,7 +24,7 @@ export class NonFungibleTokenOfAccountOnNetwork { nonce: number = 0; type: string = ""; name: string = ""; - creator: IBech32Address = new Bech32Address(""); + creator: IAddress = new Address(""); supply: BigNumber = new BigNumber(0); decimals: number = 0; royalties: BigNumber = new BigNumber(0); @@ -73,7 +73,7 @@ export class NonFungibleTokenOfAccountOnNetwork { result.nonce = payload.nonce || 0; result.type = payload.type || ""; result.name = payload.name || ""; - result.creator = new Bech32Address(payload.creator || ""); + result.creator = new Address(payload.creator || ""); result.decimals = Number(payload.decimals || 0); result.supply = new BigNumber(payload.balance || 1); result.royalties = new BigNumber(payload.royalties || 0); diff --git a/src-network-providers/transactionEvents.ts b/src-network-providers/transactionEvents.ts index d0505ce8..780a1034 100644 --- a/src-network-providers/transactionEvents.ts +++ b/src-network-providers/transactionEvents.ts @@ -1,8 +1,8 @@ -import { IBech32Address } from "./interface"; -import { Bech32Address } from "./primitives"; +import { IAddress } from "./interface"; +import { Address } from "./primitives"; export class TransactionEvent { - address: IBech32Address = new Bech32Address(""); + address: IAddress = new Address(""); identifier: string = ""; topics: TransactionEventTopic[] = []; data: string = ""; @@ -18,7 +18,7 @@ export class TransactionEvent { data: string }): TransactionEvent { let result = new TransactionEvent(); - result.address = new Bech32Address(responsePart.address); + result.address = new Address(responsePart.address); result.identifier = responsePart.identifier || ""; result.topics = (responsePart.topics || []).map(topic => new TransactionEventTopic(topic)); result.data = Buffer.from(responsePart.data || "", "base64").toString(); diff --git a/src-network-providers/transactionLogs.ts b/src-network-providers/transactionLogs.ts index a7733efb..9e7a6ef1 100644 --- a/src-network-providers/transactionLogs.ts +++ b/src-network-providers/transactionLogs.ts @@ -1,10 +1,10 @@ import { ErrUnexpectedCondition } from "./errors"; -import { IBech32Address } from "./interface"; -import { Bech32Address } from "./primitives"; +import { IAddress } from "./interface"; +import { Address } from "./primitives"; import { TransactionEvent } from "./transactionEvents"; export class TransactionLogs { - address: IBech32Address = new Bech32Address(""); + address: IAddress = new Address(""); events: TransactionEvent[] = []; constructor(init?: Partial) { @@ -13,7 +13,7 @@ export class TransactionLogs { static fromHttpResponse(logs: any): TransactionLogs { let result = new TransactionLogs(); - result.address = new Bech32Address(logs.address); + result.address = new Address(logs.address); result.events = (logs.events || []).map((event: any) => TransactionEvent.fromHttpResponse(event)); return result; diff --git a/src-network-providers/transactionReceipt.ts b/src-network-providers/transactionReceipt.ts index 0cad1476..07e72fb5 100644 --- a/src-network-providers/transactionReceipt.ts +++ b/src-network-providers/transactionReceipt.ts @@ -1,9 +1,9 @@ -import { IBech32Address } from "./interface"; -import { Bech32Address } from "./primitives"; +import { IAddress } from "./interface"; +import { Address } from "./primitives"; export class TransactionReceipt { value: string = ""; - sender: IBech32Address = new Bech32Address(""); + sender: IAddress = new Address(""); data: string = ""; hash: string = ""; @@ -16,7 +16,7 @@ export class TransactionReceipt { let receipt = new TransactionReceipt(); receipt.value = (response.value || 0).toString(); - receipt.sender = new Bech32Address(response.sender); + receipt.sender = new Address(response.sender); receipt.data = response.data; receipt.hash = response.txHash; diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index 37ce8061..95bee527 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -1,7 +1,7 @@ import { TransactionStatus } from "./transactionStatus"; import { ContractResults } from "./contractResults"; -import { Bech32Address } from "./primitives"; -import { IBech32Address } from "./interface"; +import { Address } from "./primitives"; +import { IAddress } from "./interface"; import { TransactionCompletionStrategyOnAPI, TransactionCompletionStrategyOnProxy } from "./transactionCompletionStrategy"; import { TransactionLogs } from "./transactionLogs"; import { TransactionReceipt } from "./transactionReceipt"; @@ -14,8 +14,8 @@ export class TransactionOnNetwork { round: number = 0; epoch: number = 0; value: string = ""; - receiver: IBech32Address = new Bech32Address(""); - sender: IBech32Address = new Bech32Address(""); + receiver: IAddress = new Address(""); + sender: IAddress = new Address(""); gasLimit: number = 0; gasPrice: number = 0; data: Buffer = Buffer.from([]); @@ -60,8 +60,8 @@ export class TransactionOnNetwork { result.round = response.round; result.epoch = response.epoch || 0; result.value = (response.value || 0).toString(); - result.sender = new Bech32Address(response.sender); - result.receiver = new Bech32Address(response.receiver); + result.sender = new Address(response.sender); + result.receiver = new Address(response.receiver); result.gasPrice = response.gasPrice || 0; result.gasLimit = response.gasLimit || 0; result.data = Buffer.from(response.data || "", "base64"); From 86aa8072931dc4a5e9e32ef8ada23c53157ec8af Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 12 Apr 2022 21:53:49 +0300 Subject: [PATCH 068/133] Implement ProxyNetworkProvider.getDefinitionOfFungibleToken(). --- src-network-providers/constants.ts | 1 + src-network-providers/contractQueryRequest.ts | 4 +- .../providers.dev.net.spec.ts | 6 +-- src-network-providers/proxyNetworkProvider.ts | 17 +++++-- src-network-providers/tokenDefinitions.ts | 49 ++++++++++++++++++- 5 files changed, 66 insertions(+), 11 deletions(-) diff --git a/src-network-providers/constants.ts b/src-network-providers/constants.ts index c79f74a6..932f9595 100644 --- a/src-network-providers/constants.ts +++ b/src-network-providers/constants.ts @@ -2,3 +2,4 @@ import BigNumber from "bignumber.js"; import { Address } from "./primitives"; export const MaxUint64AsBigNumber = new BigNumber("18446744073709551615"); +export const EsdtContractAddress = new Address("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"); diff --git a/src-network-providers/contractQueryRequest.ts b/src-network-providers/contractQueryRequest.ts index 69b9cebb..d64183c9 100644 --- a/src-network-providers/contractQueryRequest.ts +++ b/src-network-providers/contractQueryRequest.ts @@ -11,9 +11,9 @@ export class ContractQueryRequest { let request: any = {}; let query = this.query; request.scAddress = query.address.bech32(); - request.caller = query.caller.bech32() ? query.caller.bech32() : undefined; + request.caller = query.caller?.bech32() ? query.caller.bech32() : undefined; request.funcName = query.func.toString(); - request.value = query.value.toString(); + request.value = query.value ? query.value.toString() : undefined; request.args = query.getEncodedArguments(); return request; diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index c9a9f48d..7c5e16dd 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -164,12 +164,10 @@ describe("test network providers on devnet: Proxy and API", function () { for (const identifier of identifiers) { let apiResponse = await apiProvider.getDefinitionOfFungibleToken(identifier); + let proxyResponse = await proxyProvider.getDefinitionOfFungibleToken(identifier); assert.equal(apiResponse.identifier, identifier); - - // TODO: Uncomment after implementing the function in the proxy provider. - // let proxyResponse = await proxyProvider.getDefinitionOfFungibleToken(identifier); - // assert.deepEqual(apiResponse, proxyResponse); + assert.deepEqual(apiResponse, proxyResponse); } }); diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index f7b3d579..0fc6d4e5 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -13,6 +13,7 @@ import { NetworkStatus } from "./networkStatus"; import { ContractQueryResponse } from "./contractQueryResponse"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; import { ContractQueryRequest } from "./contractQueryRequest"; +import { EsdtContractAddress } from "./constants"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ProxyNetworkProvider implements INetworkProvider { @@ -125,10 +126,18 @@ export class ProxyNetworkProvider implements INetworkProvider { } } - async getDefinitionOfFungibleToken(_tokenIdentifier: string): Promise { - // TODO: Implement wrt.: - // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/esdt/esdt.service.ts#L221 - throw new Error("Method not implemented."); + async getDefinitionOfFungibleToken(tokenIdentifier: string): Promise { + let encodedTokenIdentifier = Buffer.from(tokenIdentifier).toString("hex"); + + let queryResponse = await this.queryContract({ + address: EsdtContractAddress, + func: "getTokenProperties", + getEncodedArguments: () => [encodedTokenIdentifier] + }); + + let dataParts = queryResponse.getReturnDataParts(); + let definition = DefinitionOfFungibleTokenOnNetwork.fromResponseOfGetTokenProperties(tokenIdentifier, dataParts); + return definition; } async getDefinitionOfTokenCollection(_collection: string): Promise { diff --git a/src-network-providers/tokenDefinitions.ts b/src-network-providers/tokenDefinitions.ts index 0a7f156d..8e43150f 100644 --- a/src-network-providers/tokenDefinitions.ts +++ b/src-network-providers/tokenDefinitions.ts @@ -36,10 +36,57 @@ export class DefinitionOfFungibleTokenOnNetwork { result.canPause = payload.canPause || false; result.canFreeze = payload.canFreeze || false; result.canWipe = payload.canWipe || false; - result.canAddSpecialRoles = payload.canAddSpecialRoles || false; return result; } + + /** + * The implementation has been moved here from the following location: + * https://github.com/ElrondNetwork/elrond-sdk-erdjs/blob/release/v9/src/token.ts + */ + static fromResponseOfGetTokenProperties(identifier: string, data: Buffer[]): DefinitionOfFungibleTokenOnNetwork { + let result = new DefinitionOfFungibleTokenOnNetwork(); + + let [tokenName, _tokenType, owner, supply, ...propertiesBuffers] = data; + let properties = this.parseTokenProperties(propertiesBuffers); + + result.identifier = identifier; + result.name = tokenName.toString(); + result.ticker = identifier; + result.owner = Address.fromPubkey(owner); + result.decimals = properties.NumDecimals.toNumber(); + result.supply = new BigNumber(supply.toString()).shiftedBy(-result.decimals); + result.isPaused = properties.IsPaused; + result.canUpgrade = properties.CanUpgrade; + result.canMint = properties.CanMint; + result.canBurn = properties.CanBurn; + result.canChangeOwner = properties.CanChangeOwner; + result.canPause = properties.CanPause; + result.canFreeze = properties.CanFreeze; + result.canWipe = properties.CanWipe; + + return result; + } + + private static parseTokenProperties(propertiesBuffers: Buffer[]): Record { + let properties: Record = {}; + + for (let buffer of propertiesBuffers) { + let [name, value] = buffer.toString().split("-"); + properties[name] = this.parseValueOfTokenProperty(value); + } + + return properties; + } + + // This only handles booleans and numbers. + private static parseValueOfTokenProperty(value: string): any { + switch (value) { + case "true": return true; + case "false": return false; + default: return new BigNumber(value); + } + } } export class DefinitionOfTokenCollectionOnNetwork { From 9740713b22d20591434a763fa34a5838bcc1831c Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Tue, 12 Apr 2022 22:10:54 +0300 Subject: [PATCH 069/133] Implement ProxyNetworkProvider.getDefinitionOfTokenCollection(). --- .../providers.dev.net.spec.ts | 6 +- src-network-providers/proxyNetworkProvider.ts | 17 +++-- src-network-providers/tokenDefinitions.ts | 71 +++++++++++++------ 3 files changed, 62 insertions(+), 32 deletions(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 7c5e16dd..3c67faf0 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -178,12 +178,10 @@ describe("test network providers on devnet: Proxy and API", function () { for (const collection of collections) { let apiResponse = await apiProvider.getDefinitionOfTokenCollection(collection); + let proxyResponse = await proxyProvider.getDefinitionOfTokenCollection(collection); assert.equal(apiResponse.collection, collection); - - // TODO: Uncomment after implementing the function in the proxy provider. - // let proxyResponse = await proxyProvider.getDefinitionOfTokenCollection(identifier); - // assert.deepEqual(apiResponse, proxyResponse); + assert.deepEqual(apiResponse, proxyResponse); } }); diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 0fc6d4e5..ffa47431 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -140,11 +140,18 @@ export class ProxyNetworkProvider implements INetworkProvider { return definition; } - async getDefinitionOfTokenCollection(_collection: string): Promise { - // TODO: Implement wrt.: - // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/collections/collection.service.ts - // https://docs.elrond.com/developers/esdt-tokens/#get-esdt-token-properties - throw new Error("Method not implemented."); + async getDefinitionOfTokenCollection(collection: string): Promise { + let encodedCollection = Buffer.from(collection).toString("hex"); + + let queryResponse = await this.queryContract({ + address: EsdtContractAddress, + func: "getTokenProperties", + getEncodedArguments: () => [encodedCollection] + }); + + let dataParts = queryResponse.getReturnDataParts(); + let definition = DefinitionOfTokenCollectionOnNetwork.fromResponseOfGetTokenProperties(collection, dataParts); + return definition; } async getNonFungibleToken(_collection: string, _nonce: number): Promise { diff --git a/src-network-providers/tokenDefinitions.ts b/src-network-providers/tokenDefinitions.ts index 8e43150f..d769f0dd 100644 --- a/src-network-providers/tokenDefinitions.ts +++ b/src-network-providers/tokenDefinitions.ts @@ -48,7 +48,7 @@ export class DefinitionOfFungibleTokenOnNetwork { let result = new DefinitionOfFungibleTokenOnNetwork(); let [tokenName, _tokenType, owner, supply, ...propertiesBuffers] = data; - let properties = this.parseTokenProperties(propertiesBuffers); + let properties = parseTokenProperties(propertiesBuffers); result.identifier = identifier; result.name = tokenName.toString(); @@ -67,26 +67,6 @@ export class DefinitionOfFungibleTokenOnNetwork { return result; } - - private static parseTokenProperties(propertiesBuffers: Buffer[]): Record { - let properties: Record = {}; - - for (let buffer of propertiesBuffers) { - let [name, value] = buffer.toString().split("-"); - properties[name] = this.parseValueOfTokenProperty(value); - } - - return properties; - } - - // This only handles booleans and numbers. - private static parseValueOfTokenProperty(value: string): any { - switch (value) { - case "true": return true; - case "false": return false; - default: return new BigNumber(value); - } - } } export class DefinitionOfTokenCollectionOnNetwork { @@ -99,7 +79,7 @@ export class DefinitionOfTokenCollectionOnNetwork { canPause: boolean = false; canFreeze: boolean = false; canWipe: boolean = false; - canTransferRole: boolean = false; + canTransferNftCreateRole: boolean = false; static fromApiHttpResponse(payload: any): DefinitionOfTokenCollectionOnNetwork { let result = new DefinitionOfTokenCollectionOnNetwork(); @@ -113,8 +93,53 @@ export class DefinitionOfTokenCollectionOnNetwork { result.canPause = payload.canPause || false; result.canFreeze = payload.canFreeze || false; result.canWipe = payload.canWipe || false; - result.canTransferRole = payload.canTransferRole || false; + result.canTransferNftCreateRole = payload.canTransferNftCreateRole || false; return result; } + + /** + * The implementation has been moved here from the following location: + * https://github.com/ElrondNetwork/elrond-sdk-erdjs/blob/release/v9/src/token.ts + */ + static fromResponseOfGetTokenProperties(collection: string, data: Buffer[]): DefinitionOfTokenCollectionOnNetwork { + let result = new DefinitionOfTokenCollectionOnNetwork(); + + let [tokenName, tokenType, owner, _, __, ...propertiesBuffers] = data; + let properties = parseTokenProperties(propertiesBuffers); + + result.collection = collection; + result.type = tokenType.toString(); + result.name = tokenName.toString(); + result.ticker = collection; + result.owner = Address.fromPubkey(owner); + result.decimals = properties.NumDecimals.toNumber(); + result.canPause = properties.CanPause; + result.canFreeze = properties.CanFreeze; + result.canWipe = properties.CanWipe; + result.canTransferNftCreateRole = properties.CanTransferNFTCreateRole; + + return result; + } +} + +// Token properties have the following format: {PropertyName}-{PropertyValue}. +function parseTokenProperties(propertiesBuffers: Buffer[]): Record { + let properties: Record = {}; + + for (let buffer of propertiesBuffers) { + let [name, value] = buffer.toString().split("-"); + properties[name] = parseValueOfTokenProperty(value); + } + + return properties; +} + +// This only handles booleans and numbers. +function parseValueOfTokenProperty(value: string): any { + switch (value) { + case "true": return true; + case "false": return false; + default: return new BigNumber(value); + } } From 64634c9096b9cf7379ae31025c69a47ce50b9b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Wed, 13 Apr 2022 11:18:10 +0300 Subject: [PATCH 070/133] Update src/accounts.ts Co-authored-by: Claudiu-Marcel Bruda --- src-network-providers/accounts.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-network-providers/accounts.ts b/src-network-providers/accounts.ts index 637248ac..4a2958ea 100644 --- a/src-network-providers/accounts.ts +++ b/src-network-providers/accounts.ts @@ -19,7 +19,7 @@ import { Address } from "./primitives"; static fromHttpResponse(payload: any): AccountOnNetwork { let result = new AccountOnNetwork(); - result.address = new Address(payload["address"] || 0); + result.address = new Address(payload["address"] || ""); result.nonce = Number(payload["nonce"] || 0); result.balance = new BigNumber(payload["balance"] || 0); result.code = payload["code"] || ""; From 07962a1f69293395f15f07e9a7cb5b421aadb790 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 13 Apr 2022 11:23:04 +0300 Subject: [PATCH 071/133] Fix after review. --- src-network-providers/primitives.spec.ts | 15 +++++++++++ src-network-providers/proxyNetworkProvider.ts | 27 +++++++++---------- 2 files changed, 27 insertions(+), 15 deletions(-) create mode 100644 src-network-providers/primitives.spec.ts diff --git a/src-network-providers/primitives.spec.ts b/src-network-providers/primitives.spec.ts new file mode 100644 index 00000000..e8f3a0c3 --- /dev/null +++ b/src-network-providers/primitives.spec.ts @@ -0,0 +1,15 @@ +import { assert } from "chai"; +import { Address } from "./primitives"; + +describe("test primitives", function () { + it("should create address from bech32 and from pubkey", async function () { + let aliceBech32 = "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"; + let bobBech32 = "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"; + let alicePubkey = Buffer.from("0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", "hex"); + let bobPubkey = Buffer.from("8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8", "hex"); + + assert.equal(new Address(aliceBech32).bech32(), Address.fromPubkey(alicePubkey).bech32()); + assert.equal(new Address(bobBech32).bech32(), Address.fromPubkey(bobPubkey).bech32()); + }); +}); + diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index ffa47431..8cce89f1 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -127,30 +127,27 @@ export class ProxyNetworkProvider implements INetworkProvider { } async getDefinitionOfFungibleToken(tokenIdentifier: string): Promise { - let encodedTokenIdentifier = Buffer.from(tokenIdentifier).toString("hex"); - - let queryResponse = await this.queryContract({ - address: EsdtContractAddress, - func: "getTokenProperties", - getEncodedArguments: () => [encodedTokenIdentifier] - }); - - let dataParts = queryResponse.getReturnDataParts(); - let definition = DefinitionOfFungibleTokenOnNetwork.fromResponseOfGetTokenProperties(tokenIdentifier, dataParts); + let properties = await this.getTokenProperties(tokenIdentifier); + let definition = DefinitionOfFungibleTokenOnNetwork.fromResponseOfGetTokenProperties(tokenIdentifier, properties); return definition; } - async getDefinitionOfTokenCollection(collection: string): Promise { - let encodedCollection = Buffer.from(collection).toString("hex"); + private async getTokenProperties(identifier: string): Promise { + let encodedIdentifier = Buffer.from(identifier).toString("hex"); let queryResponse = await this.queryContract({ address: EsdtContractAddress, func: "getTokenProperties", - getEncodedArguments: () => [encodedCollection] + getEncodedArguments: () => [encodedIdentifier] }); - let dataParts = queryResponse.getReturnDataParts(); - let definition = DefinitionOfTokenCollectionOnNetwork.fromResponseOfGetTokenProperties(collection, dataParts); + let properties = queryResponse.getReturnDataParts(); + return properties; + } + + async getDefinitionOfTokenCollection(collection: string): Promise { + let properties = await this.getTokenProperties(collection); + let definition = DefinitionOfTokenCollectionOnNetwork.fromResponseOfGetTokenProperties(collection, properties); return definition; } From 1092457241c288799a401069a9c1a9edfe302479 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Mon, 18 Apr 2022 10:50:15 +0300 Subject: [PATCH 072/133] Less console.debug(). Update readme. --- src-network-providers/apiNetworkProvider.ts | 2 -- src-network-providers/proxyNetworkProvider.ts | 2 -- 2 files changed, 4 deletions(-) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index dea1f7c3..b02aac8b 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -157,7 +157,6 @@ export class ApiNetworkProvider implements INetworkProvider { private async doGet(resourceUrl: string): Promise { let url = `${this.url}/${resourceUrl}`; - console.debug(`ApiNetworkProvider.doGet(): ${url}`); try { let response = await axios.get(url, this.config); @@ -169,7 +168,6 @@ export class ApiNetworkProvider implements INetworkProvider { private async doPost(resourceUrl: string, payload: any): Promise { let url = `${this.url}/${resourceUrl}`; - console.debug(`ApiNetworkProvider.doPost(): ${url}`); try { let response = await axios.post(url, payload, { diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 8cce89f1..9e540f23 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -167,7 +167,6 @@ export class ProxyNetworkProvider implements INetworkProvider { private async doGet(resourceUrl: string): Promise { let url = `${this.url}/${resourceUrl}`; - console.debug(`ProxyNetworkProvider.doGet(): ${url}`); try { let response = await axios.get(url, this.config); @@ -180,7 +179,6 @@ export class ProxyNetworkProvider implements INetworkProvider { private async doPost(resourceUrl: string, payload: any): Promise { let url = `${this.url}/${resourceUrl}`; - console.debug(`ProxyNetworkProvider.doPost(): ${url}`); try { let response = await axios.post(url, payload, { From 36583fe31811aea2cb4e12f79baadcdf47891c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Fri, 29 Apr 2022 16:31:15 +0300 Subject: [PATCH 073/133] Sketch fix for assets. --- src-network-providers/providers.dev.net.spec.ts | 5 ++++- src-network-providers/tokenDefinitions.ts | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 3c67faf0..de2d8ed9 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -160,12 +160,15 @@ describe("test network providers on devnet: Proxy and API", function () { it("should have same response for getDefinitionOfFungibleToken()", async function () { this.timeout(10000); - let identifiers = ["FOO-b6f543", "BAR-c80d29", "COUNTER-b7401d"]; + let identifiers = ["FOO-b6f543", "BAR-c80d29", "COUNTER-b7401d", "WEB-5d08be"]; for (const identifier of identifiers) { let apiResponse = await apiProvider.getDefinitionOfFungibleToken(identifier); let proxyResponse = await proxyProvider.getDefinitionOfFungibleToken(identifier); + // Assets are only present on API response. + apiResponse.assets = {}; + assert.equal(apiResponse.identifier, identifier); assert.deepEqual(apiResponse, proxyResponse); } diff --git a/src-network-providers/tokenDefinitions.ts b/src-network-providers/tokenDefinitions.ts index d769f0dd..fab66f39 100644 --- a/src-network-providers/tokenDefinitions.ts +++ b/src-network-providers/tokenDefinitions.ts @@ -18,6 +18,7 @@ export class DefinitionOfFungibleTokenOnNetwork { canFreeze: boolean = false; canWipe: boolean = false; canAddSpecialRoles: boolean = false; + assets: Record = {}; static fromApiHttpResponse(payload: any): DefinitionOfFungibleTokenOnNetwork { let result = new DefinitionOfFungibleTokenOnNetwork(); @@ -36,6 +37,7 @@ export class DefinitionOfFungibleTokenOnNetwork { result.canPause = payload.canPause || false; result.canFreeze = payload.canFreeze || false; result.canWipe = payload.canWipe || false; + result.assets = payload.assets || {}; return result; } From e35cf0c9e986f403fd5f2d2728a8f33aaa14dfcb Mon Sep 17 00:00:00 2001 From: schimih Date: Tue, 14 Jun 2022 14:46:01 +0300 Subject: [PATCH 074/133] DefinitionOfTokenCollectionOnNetwork update --- src-network-providers/tokenDefinitions.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src-network-providers/tokenDefinitions.ts b/src-network-providers/tokenDefinitions.ts index d769f0dd..f5ec9b2d 100644 --- a/src-network-providers/tokenDefinitions.ts +++ b/src-network-providers/tokenDefinitions.ts @@ -1,4 +1,4 @@ -import { BigNumber } from "bignumber.js"; +import BigNumber from "bignumber.js"; import { Address } from "./primitives"; import { IAddress } from "./interface"; @@ -79,7 +79,11 @@ export class DefinitionOfTokenCollectionOnNetwork { canPause: boolean = false; canFreeze: boolean = false; canWipe: boolean = false; + canUpgrade: boolean = false; + canChangeOwner: boolean = false; + canAddSpecialRoles: boolean = false; canTransferNftCreateRole: boolean = false; + canCreateMultiShard: boolean = false; static fromApiHttpResponse(payload: any): DefinitionOfTokenCollectionOnNetwork { let result = new DefinitionOfTokenCollectionOnNetwork(); @@ -102,7 +106,7 @@ export class DefinitionOfTokenCollectionOnNetwork { * The implementation has been moved here from the following location: * https://github.com/ElrondNetwork/elrond-sdk-erdjs/blob/release/v9/src/token.ts */ - static fromResponseOfGetTokenProperties(collection: string, data: Buffer[]): DefinitionOfTokenCollectionOnNetwork { + static fromResponseOfGetTokenProperties(collection: string, data: Buffer[]): DefinitionOfTokenCollectionOnNetwork { let result = new DefinitionOfTokenCollectionOnNetwork(); let [tokenName, tokenType, owner, _, __, ...propertiesBuffers] = data; @@ -117,7 +121,11 @@ export class DefinitionOfTokenCollectionOnNetwork { result.canPause = properties.CanPause; result.canFreeze = properties.CanFreeze; result.canWipe = properties.CanWipe; + result.canUpgrade = properties.CanUpgrade; + result.canChangeOwner = properties.CanChngeOwner; + result.canAddSpecialRoles = properties.CandAddSpecialRoles; result.canTransferNftCreateRole = properties.CanTransferNFTCreateRole; + result.canCreateMultiShard = properties.CanCreateMultiShard; return result; } From 622fd514ac0c12e3b4b727a654dfaa1a0b88ba1f Mon Sep 17 00:00:00 2001 From: schimih Date: Tue, 14 Jun 2022 14:52:14 +0300 Subject: [PATCH 075/133] fix --- src-network-providers/tokenDefinitions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src-network-providers/tokenDefinitions.ts b/src-network-providers/tokenDefinitions.ts index f5ec9b2d..dafc6fb8 100644 --- a/src-network-providers/tokenDefinitions.ts +++ b/src-network-providers/tokenDefinitions.ts @@ -122,8 +122,8 @@ export class DefinitionOfTokenCollectionOnNetwork { result.canFreeze = properties.CanFreeze; result.canWipe = properties.CanWipe; result.canUpgrade = properties.CanUpgrade; - result.canChangeOwner = properties.CanChngeOwner; - result.canAddSpecialRoles = properties.CandAddSpecialRoles; + result.canChangeOwner = properties.CanChangeOwner; + result.canAddSpecialRoles = properties.CanAddSpecialRoles; result.canTransferNftCreateRole = properties.CanTransferNFTCreateRole; result.canCreateMultiShard = properties.CanCreateMultiShard; From 041788b22830d908f8f7016f936e9bdd4c4337f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Fri, 1 Jul 2022 12:50:36 +0300 Subject: [PATCH 076/133] Fix (remove) logs, bump version. --- src-network-providers/apiNetworkProvider.ts | 1 - src-network-providers/proxyNetworkProvider.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index b02aac8b..ed0f4667 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -185,7 +185,6 @@ export class ApiNetworkProvider implements INetworkProvider { private handleApiError(error: any, resourceUrl: string) { if (!error.response) { - console.warn(error); throw new ErrNetworkProvider(resourceUrl, error.toString(), error); } diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 9e540f23..a8e0fff0 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -208,7 +208,6 @@ export class ProxyNetworkProvider implements INetworkProvider { private handleApiError(error: any, resourceUrl: string) { if (!error.response) { - console.warn(error); throw new ErrNetworkProvider(resourceUrl, error.toString(), error); } From 98b8b07594e03fe3d75ab5932f7ba5ba0b56511e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Mon, 18 Jul 2022 19:50:19 +0300 Subject: [PATCH 077/133] Increase default axios timeout. --- src-network-providers/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-network-providers/config.ts b/src-network-providers/config.ts index a5b2215b..ffee0f22 100644 --- a/src-network-providers/config.ts +++ b/src-network-providers/config.ts @@ -3,7 +3,7 @@ import { IPagination } from "./interface"; const JSONbig = require("json-bigint"); export const defaultAxiosConfig = { - timeout: 1000, + timeout: 5000, // See: https://github.com/axios/axios/issues/983 regarding transformResponse transformResponse: [ function (data: any) { From 2ff1f4bddb5736312b24d7a88ecefb9f55369cca Mon Sep 17 00:00:00 2001 From: Cristi Corcoveanu Date: Thu, 4 Aug 2022 15:22:34 +0300 Subject: [PATCH 078/133] add more infos for tokens api andpoints --- src-network-providers/tokens.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src-network-providers/tokens.ts b/src-network-providers/tokens.ts index 5a574507..41b13868 100644 --- a/src-network-providers/tokens.ts +++ b/src-network-providers/tokens.ts @@ -5,12 +5,14 @@ import { IAddress } from "./interface"; export class FungibleTokenOfAccountOnNetwork { identifier: string = ""; balance: BigNumber = new BigNumber(0); + plainTokenData: any = {}; static fromHttpResponse(payload: any): FungibleTokenOfAccountOnNetwork { let result = new FungibleTokenOfAccountOnNetwork(); result.identifier = payload.tokenIdentifier || payload.identifier || ""; result.balance = new BigNumber(payload.balance || 0); + result.plainTokenData = payload; return result; } @@ -29,6 +31,7 @@ export class NonFungibleTokenOfAccountOnNetwork { decimals: number = 0; royalties: BigNumber = new BigNumber(0); assets: string[] = []; + balance: BigNumber = new BigNumber(0); constructor(init?: Partial) { Object.assign(this, init); @@ -78,6 +81,7 @@ export class NonFungibleTokenOfAccountOnNetwork { result.supply = new BigNumber(payload.balance || 1); result.royalties = new BigNumber(payload.royalties || 0); result.assets = payload.assets || []; + result.balance = new BigNumber(payload.balance || 0); return result; } From 425155abbfe3ca35a3615b2ca72b222c0b8924a7 Mon Sep 17 00:00:00 2001 From: Cristi Corcoveanu Date: Tue, 9 Aug 2022 12:39:37 +0300 Subject: [PATCH 079/133] property rename - fix after review --- src-network-providers/tokens.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src-network-providers/tokens.ts b/src-network-providers/tokens.ts index 41b13868..31f685b5 100644 --- a/src-network-providers/tokens.ts +++ b/src-network-providers/tokens.ts @@ -5,14 +5,14 @@ import { IAddress } from "./interface"; export class FungibleTokenOfAccountOnNetwork { identifier: string = ""; balance: BigNumber = new BigNumber(0); - plainTokenData: any = {}; + rawResponse: any = {}; static fromHttpResponse(payload: any): FungibleTokenOfAccountOnNetwork { let result = new FungibleTokenOfAccountOnNetwork(); result.identifier = payload.tokenIdentifier || payload.identifier || ""; result.balance = new BigNumber(payload.balance || 0); - result.plainTokenData = payload; + result.rawResponse = payload; return result; } From 0fc73e521731db1c23b2408fed12d0795f6ea348 Mon Sep 17 00:00:00 2001 From: Cristi Corcoveanu Date: Tue, 16 Aug 2022 17:29:48 +0300 Subject: [PATCH 080/133] pairs endpoint implementation --- src-network-providers/apiNetworkProvider.ts | 12 ++++ src-network-providers/pairs.ts | 55 +++++++++++++++++++ .../providers.dev.net.spec.ts | 2 +- 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src-network-providers/pairs.ts diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index ed0f4667..2d69261c 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -15,6 +15,7 @@ import { defaultAxiosConfig, defaultPagination } from "./config"; import { NetworkStatus } from "./networkStatus"; import { ContractQueryResponse } from "./contractQueryResponse"; import { ContractQueryRequest } from "./contractQueryRequest"; +import {PairOnNetwork} from "./pairs"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ApiNetworkProvider implements INetworkProvider { @@ -91,6 +92,17 @@ export class ApiNetworkProvider implements INetworkProvider { return tokenData; } + async getMexPairs(pagination?: IPagination): Promise { + let url = `mex/pairs`; + if (pagination) { + url = `${url}?from=${pagination.from}&size=${pagination.size}`; + } + + let response: any[] = await this.doGetGeneric(url); + + return response.map(item => PairOnNetwork.fromApiHttpResponse(item)); + } + async getTransaction(txHash: string): Promise { let response = await this.doGetGeneric(`transactions/${txHash}`); let transaction = TransactionOnNetwork.fromApiHttpResponse(txHash, response); diff --git a/src-network-providers/pairs.ts b/src-network-providers/pairs.ts new file mode 100644 index 00000000..723c25b7 --- /dev/null +++ b/src-network-providers/pairs.ts @@ -0,0 +1,55 @@ +import {Address} from "./primitives"; +import {IAddress} from "./interface"; +import BigNumber from "bignumber.js"; + +export class PairOnNetwork { + address: IAddress = new Address(""); + id: string = ""; + symbol: string = ""; + name: string = ""; + price: BigNumber = new BigNumber(0); + baseId: string = ""; + basePrice: BigNumber = new BigNumber(0); + baseSymbol: string = ""; + baseName: string = ""; + quoteId: string = ""; + quotePrice: BigNumber = new BigNumber(0); + quoteSymbol: string = ""; + quoteName: string = ""; + totalValue: BigNumber = new BigNumber(0); + volume24h: BigNumber = new BigNumber(0); + state: string = ""; + type: string = ""; + + rawResponse: any = {}; + + constructor(init?: Partial) { + Object.assign(this, init); + } + + static fromApiHttpResponse(payload: any): PairOnNetwork { + let result = new PairOnNetwork(); + + result.address = new Address(payload.address || ""); + result.id = payload.id || ""; + result.symbol = payload.symbol || ""; + result.name = payload.name || ""; + result.price = new BigNumber(payload.price || 0); + result.baseId = payload.baseId || ""; + result.basePrice = new BigNumber(payload.basePrice || 0); + result.baseSymbol = payload.baseSymbol || ""; + result.baseName = payload.baseName || ""; + result.quoteId = payload.quoteId || ""; + result.quotePrice = new BigNumber(payload.quotePrice || 0); + result.quoteSymbol = payload.quoteSymbol || ""; + result.quoteName = payload.quoteName || ""; + result.totalValue = new BigNumber(payload.totalValue || 0); + result.volume24h = new BigNumber(payload.volume24h || 0); + result.state = payload.state || ""; + result.type = payload.type || ""; + + result.rawResponse = payload; + + return result; + } +} diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 3c67faf0..017b8418 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -13,7 +13,7 @@ describe("test network providers on devnet: Proxy and API", function () { let carol = new Address("erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8"); let dan = new Address("erd1kyaqzaprcdnv4luvanah0gfxzzsnpaygsy6pytrexll2urtd05ts9vegu7"); - let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 10000 }); + let apiProvider: ApiNetworkProvider = new ApiNetworkProvider("https://api.elrond.com", { timeout: 10000 }); let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.elrond.com", { timeout: 10000 }); it("should have same response for getNetworkConfig()", async function () { From fbc06eccb26b8e617c1affde48d2f70f30ef1803 Mon Sep 17 00:00:00 2001 From: Cristi Corcoveanu Date: Fri, 19 Aug 2022 12:47:45 +0300 Subject: [PATCH 081/133] reverted test --- src-network-providers/providers.dev.net.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 017b8418..3c67faf0 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -13,7 +13,7 @@ describe("test network providers on devnet: Proxy and API", function () { let carol = new Address("erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8"); let dan = new Address("erd1kyaqzaprcdnv4luvanah0gfxzzsnpaygsy6pytrexll2urtd05ts9vegu7"); - let apiProvider: ApiNetworkProvider = new ApiNetworkProvider("https://api.elrond.com", { timeout: 10000 }); + let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 10000 }); let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.elrond.com", { timeout: 10000 }); it("should have same response for getNetworkConfig()", async function () { From 9572232c2eb24ee5e626e869994a49f07a9a09eb Mon Sep 17 00:00:00 2001 From: Cristi Corcoveanu Date: Fri, 19 Aug 2022 12:57:45 +0300 Subject: [PATCH 082/133] added new method on the interface --- src-network-providers/interface.ts | 6 ++++++ src-network-providers/proxyNetworkProvider.ts | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index 4d44c32e..9d7c9528 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -8,6 +8,7 @@ import { NetworkStatus } from "./networkStatus"; import { ContractQueryResponse } from "./contractQueryResponse"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; +import {PairOnNetwork} from "./pairs"; /** * An interface that defines the endpoints of an HTTP API Provider. @@ -58,6 +59,11 @@ export interface INetworkProvider { */ getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: number): Promise; + /** + * Fetches data about available mex pairs. + */ + getMexPairs(pagination?: IPagination): Promise; + /** * Fetches the state of a transaction. */ diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index a8e0fff0..f7f5ed50 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -14,6 +14,7 @@ import { ContractQueryResponse } from "./contractQueryResponse"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; import { ContractQueryRequest } from "./contractQueryRequest"; import { EsdtContractAddress } from "./constants"; +import {PairOnNetwork} from "./pairs"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ProxyNetworkProvider implements INetworkProvider { @@ -93,6 +94,10 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokenData; } + async getMexPairs(_?: IPagination): Promise { + throw new Error("Method not implemented."); + } + async getTransaction(txHash: string): Promise { let url = this.buildUrlWithQueryParameters(`transaction/${txHash}`, { withResults: "true" }); let response = await this.doGetGeneric(url); From a23e7d949b16ec51f99b61cc291b9e932328ead2 Mon Sep 17 00:00:00 2001 From: Cristi Corcoveanu Date: Fri, 19 Aug 2022 13:20:10 +0300 Subject: [PATCH 083/133] removed method from interface --- src-network-providers/interface.ts | 5 ----- src-network-providers/proxyNetworkProvider.ts | 4 ---- 2 files changed, 9 deletions(-) diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index 9d7c9528..ef7dbbda 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -59,11 +59,6 @@ export interface INetworkProvider { */ getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: number): Promise; - /** - * Fetches data about available mex pairs. - */ - getMexPairs(pagination?: IPagination): Promise; - /** * Fetches the state of a transaction. */ diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index f7f5ed50..0bc866f3 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -94,10 +94,6 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokenData; } - async getMexPairs(_?: IPagination): Promise { - throw new Error("Method not implemented."); - } - async getTransaction(txHash: string): Promise { let url = this.buildUrlWithQueryParameters(`transaction/${txHash}`, { withResults: "true" }); let response = await this.doGetGeneric(url); From 0607faea6b6e1cbacc9bd834184c60cd475f442b Mon Sep 17 00:00:00 2001 From: Cristi Corcoveanu Date: Fri, 19 Aug 2022 13:22:07 +0300 Subject: [PATCH 084/133] removed importr --- src-network-providers/interface.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index ef7dbbda..4d44c32e 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -8,7 +8,6 @@ import { NetworkStatus } from "./networkStatus"; import { ContractQueryResponse } from "./contractQueryResponse"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; -import {PairOnNetwork} from "./pairs"; /** * An interface that defines the endpoints of an HTTP API Provider. From 4c6f161c4a573be9187740577fbe75234608be43 Mon Sep 17 00:00:00 2001 From: Cristi Corcoveanu Date: Fri, 19 Aug 2022 13:22:30 +0300 Subject: [PATCH 085/133] removed importr --- src-network-providers/proxyNetworkProvider.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 0bc866f3..a8e0fff0 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -14,7 +14,6 @@ import { ContractQueryResponse } from "./contractQueryResponse"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; import { ContractQueryRequest } from "./contractQueryRequest"; import { EsdtContractAddress } from "./constants"; -import {PairOnNetwork} from "./pairs"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ProxyNetworkProvider implements INetworkProvider { From 9bce67a94fa1f76b7eac033992ec052256912482 Mon Sep 17 00:00:00 2001 From: Traian Anghel Date: Thu, 15 Sep 2022 12:33:18 +0300 Subject: [PATCH 086/133] pass headers when performing post api calls --- src-network-providers/apiNetworkProvider.ts | 1 + src-network-providers/proxyNetworkProvider.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 2d69261c..4fea6117 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -186,6 +186,7 @@ export class ApiNetworkProvider implements INetworkProvider { ...this.config, headers: { "Content-Type": "application/json", + ...this.config.headers, }, }); let responsePayload = response.data; diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index a8e0fff0..972ac32f 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -185,6 +185,7 @@ export class ProxyNetworkProvider implements INetworkProvider { ...this.config, headers: { "Content-Type": "application/json", + ...this.config.headers, }, }); let responsePayload = response.data.data; From d897ddabcbf1737d9c53932706227b04d1a70232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Tue, 18 Oct 2022 23:04:02 +0300 Subject: [PATCH 087/133] Add address.toString(). --- src-network-providers/primitives.spec.ts | 2 ++ src-network-providers/primitives.ts | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src-network-providers/primitives.spec.ts b/src-network-providers/primitives.spec.ts index e8f3a0c3..202a9dfe 100644 --- a/src-network-providers/primitives.spec.ts +++ b/src-network-providers/primitives.spec.ts @@ -10,6 +10,8 @@ describe("test primitives", function () { assert.equal(new Address(aliceBech32).bech32(), Address.fromPubkey(alicePubkey).bech32()); assert.equal(new Address(bobBech32).bech32(), Address.fromPubkey(bobPubkey).bech32()); + assert.equal(new Address(aliceBech32).toString(), aliceBech32); + assert.equal(new Address(bobBech32).toString(), bobBech32); }); }); diff --git a/src-network-providers/primitives.ts b/src-network-providers/primitives.ts index fecbbace..150e758c 100644 --- a/src-network-providers/primitives.ts +++ b/src-network-providers/primitives.ts @@ -22,6 +22,10 @@ export class Address implements IAddress { bech32(): string { return this.value; } + + toString() { + return this.value; + } } export class Nonce { From df2335161438d255922b4a9ef3b8284fe8c55be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Wed, 19 Oct 2022 11:18:52 +0300 Subject: [PATCH 088/133] Fix after review. --- src-network-providers/primitives.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-network-providers/primitives.ts b/src-network-providers/primitives.ts index 150e758c..ed50b4ef 100644 --- a/src-network-providers/primitives.ts +++ b/src-network-providers/primitives.ts @@ -24,7 +24,7 @@ export class Address implements IAddress { } toString() { - return this.value; + return this.bech32(); } } From 4e0a57a8a5cfe7ced57d7ce5b6d575eb21da4c13 Mon Sep 17 00:00:00 2001 From: Well Date: Mon, 7 Nov 2022 20:09:38 +0100 Subject: [PATCH 089/133] Add proxy method to send transaction in bulk --- src-network-providers/interface.ts | 5 +++++ src-network-providers/proxyNetworkProvider.ts | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index 4d44c32e..fe24c8c7 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -73,6 +73,11 @@ export interface INetworkProvider { */ sendTransaction(tx: ITransaction): Promise; + /** + * Broadcasts a list of already-signed transactions. + */ + sendBulkTransaction(tx: ITransaction[]): Promise; + /** * Simulates the processing of an already-signed transaction. * diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 972ac32f..c4aa3f04 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -111,6 +111,15 @@ export class ProxyNetworkProvider implements INetworkProvider { return response.txHash; } + async sendBulkTransaction(txs: ITransaction[]): Promise { + let sendable: any = []; + txs.forEach((tx) => { + sendable.push(tx.toSendable()); + }); + let response = await this.doPostGeneric("transaction/send-multiple", sendable); + return response.txsHashes; + } + async simulateTransaction(tx: ITransaction): Promise { let response = await this.doPostGeneric("transaction/simulate", tx.toSendable()); return response; From 1630913f7720040a1de001f398ee594d9c2309c1 Mon Sep 17 00:00:00 2001 From: Well Date: Mon, 7 Nov 2022 20:19:40 +0100 Subject: [PATCH 090/133] fix sendBulkTransaction api --- src-network-providers/apiNetworkProvider.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 4fea6117..b94a7d24 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -120,6 +120,15 @@ export class ApiNetworkProvider implements INetworkProvider { return response.txHash; } + async sendBulkTransaction(txs: ITransaction[]): Promise { + let sendable: any = []; + txs.forEach((tx) => { + sendable.push(tx.toSendable()); + }); + let response = await this.doPostGeneric("transaction/send-multiple", sendable); + return response.txsHashes; + } + async simulateTransaction(tx: ITransaction): Promise { return await this.backingProxyNetworkProvider.simulateTransaction(tx); } From add11e3919939f6fed44e67da8ac5f56c8da379f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Mon, 14 Nov 2022 15:58:58 +0200 Subject: [PATCH 091/133] Fix axios deserialization, ignore "_constructor". --- src-network-providers/config.ts | 2 +- src-network-providers/serialization.spec.ts | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src-network-providers/serialization.spec.ts diff --git a/src-network-providers/config.ts b/src-network-providers/config.ts index ffee0f22..8239bfda 100644 --- a/src-network-providers/config.ts +++ b/src-network-providers/config.ts @@ -1,6 +1,6 @@ import { IPagination } from "./interface"; -const JSONbig = require("json-bigint"); +const JSONbig = require("json-bigint")({ constructorAction: 'ignore' }); export const defaultAxiosConfig = { timeout: 5000, diff --git a/src-network-providers/serialization.spec.ts b/src-network-providers/serialization.spec.ts new file mode 100644 index 00000000..6ffc8309 --- /dev/null +++ b/src-network-providers/serialization.spec.ts @@ -0,0 +1,16 @@ +import assert from "assert"; + +describe("test JSON serialization", function () { + it("should not deserialize", async function () { + const JSONbig = require("json-bigint"); + const data = `{"Costum":{"foo_constructor":1}}`; + assert.throws(() => JSONbig.parse(data)); + }); + + it("should deserialize", async function () { + const JSONbig = require("json-bigint")({ constructorAction: 'ignore' }); + const data = `{"Costum":{"foo_constructor":1}}`; + JSONbig.parse(data); + }); +}); + From 7fb3910f6bc923370cadf912cc1a1f30193dceba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Mon, 19 Dec 2022 17:51:00 +0200 Subject: [PATCH 092/133] Fix after community PR (send transactions in bulk). --- src-network-providers/apiNetworkProvider.ts | 29 ++++++++----------- src-network-providers/interface.ts | 12 ++++---- src-network-providers/proxyNetworkProvider.ts | 27 ++++++++--------- 3 files changed, 30 insertions(+), 38 deletions(-) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index b94a7d24..a1b33394 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -1,21 +1,21 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; -import { IAddress, IContractQuery, INetworkProvider, ITransaction, IPagination } from "./interface"; +import { defaultAxiosConfig, defaultPagination } from "./config"; +import { ContractQueryRequest } from "./contractQueryRequest"; +import { ContractQueryResponse } from "./contractQueryResponse"; +import { ErrContractQuery, ErrNetworkProvider } from "./errors"; +import { IAddress, IContractQuery, INetworkProvider, IPagination, ITransaction } from "./interface"; import { NetworkConfig } from "./networkConfig"; -import { NetworkStake } from "./networkStake"; import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; +import { NetworkStake } from "./networkStake"; +import { NetworkStatus } from "./networkStatus"; +import { PairOnNetwork } from "./pairs"; +import { Nonce } from "./primitives"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; -import { Nonce } from "./primitives"; -import { ErrContractQuery, ErrNetworkProvider } from "./errors"; -import { defaultAxiosConfig, defaultPagination } from "./config"; -import { NetworkStatus } from "./networkStatus"; -import { ContractQueryResponse } from "./contractQueryResponse"; -import { ContractQueryRequest } from "./contractQueryRequest"; -import {PairOnNetwork} from "./pairs"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ApiNetworkProvider implements INetworkProvider { @@ -73,7 +73,7 @@ export class ApiNetworkProvider implements INetworkProvider { let url = `accounts/${address.bech32()}/nfts?${this.buildPaginationParams(pagination)}`; let response: any[] = await this.doGetGeneric(url); let tokens = response.map(item => NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(item)); - + // TODO: Fix sorting tokens.sort((a, b) => a.identifier.localeCompare(b.identifier)); return tokens; @@ -120,13 +120,8 @@ export class ApiNetworkProvider implements INetworkProvider { return response.txHash; } - async sendBulkTransaction(txs: ITransaction[]): Promise { - let sendable: any = []; - txs.forEach((tx) => { - sendable.push(tx.toSendable()); - }); - let response = await this.doPostGeneric("transaction/send-multiple", sendable); - return response.txsHashes; + async sendTransactions(txs: ITransaction[]): Promise> { + return await this.backingProxyNetworkProvider.sendTransactions(txs); } async simulateTransaction(tx: ITransaction): Promise { diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index fe24c8c7..9d979904 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -1,13 +1,13 @@ import { AccountOnNetwork } from "./accounts"; +import { ContractQueryResponse } from "./contractQueryResponse"; import { NetworkConfig } from "./networkConfig"; -import { NetworkStake } from "./networkStake"; import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; -import { TransactionOnNetwork } from "./transactions"; -import { TransactionStatus } from "./transactionStatus"; +import { NetworkStake } from "./networkStake"; import { NetworkStatus } from "./networkStatus"; -import { ContractQueryResponse } from "./contractQueryResponse"; -import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; +import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; +import { TransactionOnNetwork } from "./transactions"; +import { TransactionStatus } from "./transactionStatus"; /** * An interface that defines the endpoints of an HTTP API Provider. @@ -76,7 +76,7 @@ export interface INetworkProvider { /** * Broadcasts a list of already-signed transactions. */ - sendBulkTransaction(tx: ITransaction[]): Promise; + sendTransactions(txs: ITransaction[]): Promise>; /** * Simulates the processing of an already-signed transaction. diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index c4aa3f04..ccaef834 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -1,19 +1,19 @@ import axios, { AxiosRequestConfig } from "axios"; import { AccountOnNetwork } from "./accounts"; +import { defaultAxiosConfig } from "./config"; +import { EsdtContractAddress } from "./constants"; +import { ContractQueryRequest } from "./contractQueryRequest"; +import { ContractQueryResponse } from "./contractQueryResponse"; +import { ErrContractQuery, ErrNetworkProvider } from "./errors"; import { IAddress, IContractQuery, INetworkProvider, IPagination, ITransaction } from "./interface"; import { NetworkConfig } from "./networkConfig"; -import { NetworkStake } from "./networkStake"; import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; +import { NetworkStake } from "./networkStake"; +import { NetworkStatus } from "./networkStatus"; +import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; -import { ErrContractQuery, ErrNetworkProvider } from "./errors"; -import { defaultAxiosConfig } from "./config"; -import { NetworkStatus } from "./networkStatus"; -import { ContractQueryResponse } from "./contractQueryResponse"; -import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; -import { ContractQueryRequest } from "./contractQueryRequest"; -import { EsdtContractAddress } from "./constants"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ProxyNetworkProvider implements INetworkProvider { @@ -111,15 +111,12 @@ export class ProxyNetworkProvider implements INetworkProvider { return response.txHash; } - async sendBulkTransaction(txs: ITransaction[]): Promise { - let sendable: any = []; - txs.forEach((tx) => { - sendable.push(tx.toSendable()); - }); - let response = await this.doPostGeneric("transaction/send-multiple", sendable); + async sendTransactions(txs: ITransaction[]): Promise> { + const data: any = txs.map(tx => tx.toSendable()); + const response = await this.doPostGeneric("transaction/send-multiple", data); return response.txsHashes; } - + async simulateTransaction(tx: ITransaction): Promise { let response = await this.doPostGeneric("transaction/simulate", tx.toSendable()); return response; From 9de774e7db498a14626581cd764a2cb1f3ec52ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Mon, 19 Dec 2022 19:30:02 +0200 Subject: [PATCH 093/133] Unit tests, fix response. --- src-network-providers/apiNetworkProvider.ts | 2 +- src-network-providers/interface.ts | 2 +- .../providers.dev.net.spec.ts | 66 +++++++++++++++++-- src-network-providers/proxyNetworkProvider.ts | 10 ++- 4 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index a1b33394..9942b980 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -120,7 +120,7 @@ export class ApiNetworkProvider implements INetworkProvider { return response.txHash; } - async sendTransactions(txs: ITransaction[]): Promise> { + async sendTransactions(txs: ITransaction[]): Promise { return await this.backingProxyNetworkProvider.sendTransactions(txs); } diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index 9d979904..e5eaa243 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -76,7 +76,7 @@ export interface INetworkProvider { /** * Broadcasts a list of already-signed transactions. */ - sendTransactions(txs: ITransaction[]): Promise>; + sendTransactions(txs: ITransaction[]): Promise; /** * Simulates the processing of an already-signed transaction. diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 3c67faf0..d8209fb4 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -1,11 +1,11 @@ import { assert } from "chai"; +import { ApiNetworkProvider } from "./apiNetworkProvider"; import { INetworkProvider } from "./interface"; -import { TransactionOnNetwork } from "./transactions"; -import { TransactionStatus } from "./transactionStatus"; import { Address } from "./primitives"; -import { MockQuery } from "./testscommon/dummyQuery"; -import { ApiNetworkProvider } from "./apiNetworkProvider"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; +import { MockQuery } from "./testscommon/dummyQuery"; +import { TransactionOnNetwork } from "./transactions"; +import { TransactionStatus } from "./transactionStatus"; describe("test network providers on devnet: Proxy and API", function () { let alice = new Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); @@ -99,6 +99,62 @@ describe("test network providers on devnet: Proxy and API", function () { } }); + it("should be able to send transaction(s)", async function () { + this.timeout(5000); + + const txs = [ + { + toSendable: function () { + return { + "nonce": 42, + "value": "1", + "receiver": "erd1testnlersh4z0wsv8kjx39me4rmnvjkwu8dsaea7ukdvvc9z396qykv7z7", + "sender": "erd15x2panzqvfxul2lvstfrmdcl5t4frnsylfrhng8uunwdssxw4y9succ9sq", + "gasPrice": 1000000000, + "gasLimit": 50000, + "chainID": "D", + "version": 1, + "signature": "c8eb539e486db7d703d8c70cab3b7679113f77c4685d8fcc94db027ceacc6b8605115034355386dffd7aa12e63dbefa03251a2f1b1d971f52250187298d12900" + } + } + }, + { + toSendable: function () { + return { + "nonce": 43, + "value": "1", + "receiver": "erd1testnlersh4z0wsv8kjx39me4rmnvjkwu8dsaea7ukdvvc9z396qykv7z7", + "sender": "erd15x2panzqvfxul2lvstfrmdcl5t4frnsylfrhng8uunwdssxw4y9succ9sq", + "gasPrice": 1000000000, + "gasLimit": 50000, + "chainID": "D", + "version": 1, + "signature": "9c4c22d0ae1b5a10c39583a5ab9020b00b27aa69d4ac8ab4922620dbf0df4036ed890f9946d38a9d0c85d6ac485c0d9b2eac0005e752f249fd0ad863b0471d02" + } + } + }, + { + toSendable: function () { + return { + "nonce": 44 + } + } + } + ]; + + const expectedHashes = [ + "6e2fa63ea02937f00d7549f3e4eb9af241e4ac13027aa65a5300816163626c01", + "37d7e84313a5baea2a61c6ab10bb29b52bc54f7ac9e3918a9faeb1e08f42081c", + null + ] + + assert.equal(await apiProvider.sendTransaction(txs[0]), expectedHashes[0]); + assert.equal(await proxyProvider.sendTransaction(txs[1]), expectedHashes[1]); + + assert.deepEqual(await apiProvider.sendTransactions(txs), expectedHashes); + assert.deepEqual(await proxyProvider.sendTransactions(txs), expectedHashes); + }); + it("should have same response for getTransaction()", async function () { this.timeout(20000); @@ -256,7 +312,7 @@ describe("test network providers on devnet: Proxy and API", function () { let apiResponse = await apiProvider.queryContract(query); let proxyResponse = await proxyProvider.queryContract(query); - + assert.deepEqual(apiResponse, proxyResponse); assert.deepEqual(apiResponse.getReturnDataParts(), proxyResponse.getReturnDataParts()); }); diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index ccaef834..1a7ef38f 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -111,10 +111,16 @@ export class ProxyNetworkProvider implements INetworkProvider { return response.txHash; } - async sendTransactions(txs: ITransaction[]): Promise> { + async sendTransactions(txs: ITransaction[]): Promise { const data: any = txs.map(tx => tx.toSendable()); const response = await this.doPostGeneric("transaction/send-multiple", data); - return response.txsHashes; + const hashes = Array(txs.length).fill(null); + + for (let i = 0; i < txs.length; i++) { + hashes[i] = response.txsHashes[i.toString()] || null; + } + + return hashes; } async simulateTransaction(tx: ITransaction): Promise { From a11a24d17f2a2eeb701c750665fcff1650eb4233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Mon, 19 Dec 2022 19:49:52 +0200 Subject: [PATCH 094/133] Fix comment, formatting etc. --- src-network-providers/providers.dev.net.spec.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index de2d8ed9..d0b3969d 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -1,11 +1,11 @@ import { assert } from "chai"; +import { ApiNetworkProvider } from "./apiNetworkProvider"; import { INetworkProvider } from "./interface"; -import { TransactionOnNetwork } from "./transactions"; -import { TransactionStatus } from "./transactionStatus"; import { Address } from "./primitives"; -import { MockQuery } from "./testscommon/dummyQuery"; -import { ApiNetworkProvider } from "./apiNetworkProvider"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; +import { MockQuery } from "./testscommon/dummyQuery"; +import { TransactionOnNetwork } from "./transactions"; +import { TransactionStatus } from "./transactionStatus"; describe("test network providers on devnet: Proxy and API", function () { let alice = new Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); @@ -166,7 +166,7 @@ describe("test network providers on devnet: Proxy and API", function () { let apiResponse = await apiProvider.getDefinitionOfFungibleToken(identifier); let proxyResponse = await proxyProvider.getDefinitionOfFungibleToken(identifier); - // Assets are only present on API response. + // Assets are only present on API responses, thus we ignore them for comparison. apiResponse.assets = {}; assert.equal(apiResponse.identifier, identifier); @@ -259,7 +259,7 @@ describe("test network providers on devnet: Proxy and API", function () { let apiResponse = await apiProvider.queryContract(query); let proxyResponse = await proxyProvider.queryContract(query); - + assert.deepEqual(apiResponse, proxyResponse); assert.deepEqual(apiResponse.getReturnDataParts(), proxyResponse.getReturnDataParts()); }); From 5ba013124acf24ad4264a2198ffb352baab889c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Fri, 6 Jan 2023 20:01:29 +0200 Subject: [PATCH 095/133] Rename Elrond to MultiversX. --- src-network-providers/providers.dev.net.spec.ts | 4 ++-- src-network-providers/proxyNetworkProvider.ts | 4 ++-- src-network-providers/tokenDefinitions.ts | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 1d159116..cb58f22a 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -13,8 +13,8 @@ describe("test network providers on devnet: Proxy and API", function () { let carol = new Address("erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8"); let dan = new Address("erd1kyaqzaprcdnv4luvanah0gfxzzsnpaygsy6pytrexll2urtd05ts9vegu7"); - let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.elrond.com", { timeout: 10000 }); - let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.elrond.com", { timeout: 10000 }); + let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.multiversx.com", { timeout: 10000 }); + let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { timeout: 10000 }); it("should have same response for getNetworkConfig()", async function () { let apiResponse = await apiProvider.getNetworkConfig(); diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 1a7ef38f..8eb1f582 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -39,13 +39,13 @@ export class ProxyNetworkProvider implements INetworkProvider { async getNetworkStakeStatistics(): Promise { // TODO: Implement wrt.: - // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/stake/stake.service.ts + // https://github.com/multiversx/mx-api-service/blob/main/src/endpoints/stake/stake.service.ts throw new Error("Method not implemented."); } async getNetworkGeneralStatistics(): Promise { // TODO: Implement wrt. (full implementation may not be possible): - // https://github.com/ElrondNetwork/api.elrond.com/blob/main/src/endpoints/network/network.service.ts + // https://github.com/multiversx/mx-api-service/blob/main/src/endpoints/network/network.service.ts throw new Error("Method not implemented."); } diff --git a/src-network-providers/tokenDefinitions.ts b/src-network-providers/tokenDefinitions.ts index 2c1bf1c9..519e03e4 100644 --- a/src-network-providers/tokenDefinitions.ts +++ b/src-network-providers/tokenDefinitions.ts @@ -1,6 +1,6 @@ import BigNumber from "bignumber.js"; -import { Address } from "./primitives"; import { IAddress } from "./interface"; +import { Address } from "./primitives"; export class DefinitionOfFungibleTokenOnNetwork { identifier: string = ""; @@ -18,7 +18,7 @@ export class DefinitionOfFungibleTokenOnNetwork { canFreeze: boolean = false; canWipe: boolean = false; canAddSpecialRoles: boolean = false; - assets: Record = {}; + assets: Record = {}; static fromApiHttpResponse(payload: any): DefinitionOfFungibleTokenOnNetwork { let result = new DefinitionOfFungibleTokenOnNetwork(); @@ -44,7 +44,7 @@ export class DefinitionOfFungibleTokenOnNetwork { /** * The implementation has been moved here from the following location: - * https://github.com/ElrondNetwork/elrond-sdk-erdjs/blob/release/v9/src/token.ts + * https://github.com/multiversx/mx-sdk-erdjs/blob/release/v9/src/token.ts */ static fromResponseOfGetTokenProperties(identifier: string, data: Buffer[]): DefinitionOfFungibleTokenOnNetwork { let result = new DefinitionOfFungibleTokenOnNetwork(); @@ -106,7 +106,7 @@ export class DefinitionOfTokenCollectionOnNetwork { /** * The implementation has been moved here from the following location: - * https://github.com/ElrondNetwork/elrond-sdk-erdjs/blob/release/v9/src/token.ts + * https://github.com/multiversx/mx-sdk-erdjs/blob/release/v9/src/token.ts */ static fromResponseOfGetTokenProperties(collection: string, data: Buffer[]): DefinitionOfTokenCollectionOnNetwork { let result = new DefinitionOfTokenCollectionOnNetwork(); From 9429911ed601efddc68c13625ad413687cc3d375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Tue, 10 Jan 2023 21:13:21 +0200 Subject: [PATCH 096/133] Rename erdjs to sdk-js. --- src-network-providers/interface.ts | 4 ++-- src-network-providers/tokenDefinitions.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index e5eaa243..64109723 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -105,12 +105,12 @@ export interface INetworkProvider { getNonFungibleToken(collection: string, nonce: number): Promise; /** - * Performs a generic GET action against the provider (useful for new HTTP endpoints, not yet supported by erdjs). + * Performs a generic GET action against the provider (useful for new HTTP endpoints). */ doGetGeneric(resourceUrl: string): Promise; /** - * Performs a generic POST action against the provider (useful for new HTTP endpoints, not yet supported by erdjs). + * Performs a generic POST action against the provider (useful for new HTTP endpoints). */ doPostGeneric(resourceUrl: string, payload: any): Promise; } diff --git a/src-network-providers/tokenDefinitions.ts b/src-network-providers/tokenDefinitions.ts index 519e03e4..b0444028 100644 --- a/src-network-providers/tokenDefinitions.ts +++ b/src-network-providers/tokenDefinitions.ts @@ -44,7 +44,7 @@ export class DefinitionOfFungibleTokenOnNetwork { /** * The implementation has been moved here from the following location: - * https://github.com/multiversx/mx-sdk-erdjs/blob/release/v9/src/token.ts + * https://github.com/multiversx/mx-sdk-js/blob/release/v9/src/token.ts */ static fromResponseOfGetTokenProperties(identifier: string, data: Buffer[]): DefinitionOfFungibleTokenOnNetwork { let result = new DefinitionOfFungibleTokenOnNetwork(); @@ -106,7 +106,7 @@ export class DefinitionOfTokenCollectionOnNetwork { /** * The implementation has been moved here from the following location: - * https://github.com/multiversx/mx-sdk-erdjs/blob/release/v9/src/token.ts + * https://github.com/multiversx/mx-sdk-js/blob/release/v9/src/token.ts */ static fromResponseOfGetTokenProperties(collection: string, data: Buffer[]): DefinitionOfTokenCollectionOnNetwork { let result = new DefinitionOfTokenCollectionOnNetwork(); From 7e1f47ffb3cdfe69799e71c0f19a89fbc1affdab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Wed, 11 Jan 2023 11:13:31 +0200 Subject: [PATCH 097/133] Rename package: sdk-network-providers. --- src-network-providers/tokenDefinitions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src-network-providers/tokenDefinitions.ts b/src-network-providers/tokenDefinitions.ts index b0444028..fc97af03 100644 --- a/src-network-providers/tokenDefinitions.ts +++ b/src-network-providers/tokenDefinitions.ts @@ -44,7 +44,7 @@ export class DefinitionOfFungibleTokenOnNetwork { /** * The implementation has been moved here from the following location: - * https://github.com/multiversx/mx-sdk-js/blob/release/v9/src/token.ts + * https://github.com/multiversx/mx-sdk-js-core/blob/release/v9/src/token.ts */ static fromResponseOfGetTokenProperties(identifier: string, data: Buffer[]): DefinitionOfFungibleTokenOnNetwork { let result = new DefinitionOfFungibleTokenOnNetwork(); @@ -106,7 +106,7 @@ export class DefinitionOfTokenCollectionOnNetwork { /** * The implementation has been moved here from the following location: - * https://github.com/multiversx/mx-sdk-js/blob/release/v9/src/token.ts + * https://github.com/multiversx/mx-sdk-js-core/blob/release/v9/src/token.ts */ static fromResponseOfGetTokenProperties(collection: string, data: Buffer[]): DefinitionOfTokenCollectionOnNetwork { let result = new DefinitionOfTokenCollectionOnNetwork(); From 8c92cff5ff7123206466d3ab40b08d27d16c97bf Mon Sep 17 00:00:00 2001 From: andreibancioiu Date: Mon, 23 Jan 2023 14:38:38 +0200 Subject: [PATCH 098/133] Redo PR 33 (error handling). --- src-network-providers/apiNetworkProvider.ts | 4 ++-- src-network-providers/proxyNetworkProvider.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 9942b980..98b57fa4 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -205,8 +205,8 @@ export class ApiNetworkProvider implements INetworkProvider { throw new ErrNetworkProvider(resourceUrl, error.toString(), error); } - let errorData = error.response.data; - let originalErrorMessage = errorData.error || errorData.message || JSON.stringify(errorData); + const errorData = error.response.data; + const originalErrorMessage = errorData.message || errorData.error || JSON.stringify(errorData); throw new ErrNetworkProvider(resourceUrl, originalErrorMessage, error); } } diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 8eb1f582..fad7ae2d 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -224,8 +224,8 @@ export class ProxyNetworkProvider implements INetworkProvider { throw new ErrNetworkProvider(resourceUrl, error.toString(), error); } - let errorData = error.response.data; - let originalErrorMessage = errorData.error || errorData.message || JSON.stringify(errorData); + const errorData = error.response.data; + const originalErrorMessage = errorData.message || errorData.error || JSON.stringify(errorData); throw new ErrNetworkProvider(resourceUrl, originalErrorMessage, error); } } From 33c5ebc415d525ef0b450c57b958f2e984fb2c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 13 Apr 2023 11:35:01 +0300 Subject: [PATCH 099/133] Implement getGuardianData(). --- src-network-providers/accounts.ts | 43 ++++++++++++++++++- src-network-providers/apiNetworkProvider.ts | 6 ++- src-network-providers/proxyNetworkProvider.ts | 8 +++- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src-network-providers/accounts.ts b/src-network-providers/accounts.ts index 4a2958ea..c7e83f89 100644 --- a/src-network-providers/accounts.ts +++ b/src-network-providers/accounts.ts @@ -5,7 +5,7 @@ import { Address } from "./primitives"; /** * A plain view of an account, as queried from the Network. */ - export class AccountOnNetwork { +export class AccountOnNetwork { address: IAddress = new Address(""); nonce: number = 0; balance: BigNumber = new BigNumber(0); @@ -29,3 +29,44 @@ import { Address } from "./primitives"; } } +export class GuardianData { + guarded: boolean = false; + activeGuardian?: Guardian; + pendingGuardian?: Guardian; + + constructor(init?: Partial) { + Object.assign(this, init); + } + + static fromHttpResponse(payload: any): GuardianData { + const result = new GuardianData(); + + result.guarded = payload["guarded"] || false; + + if (payload["activeGuardian"]) { + result.activeGuardian = Guardian.fromHttpResponse(payload["activeGuardian"]); + } + + if (payload["pendingGuardian"]) { + result.pendingGuardian = Guardian.fromHttpResponse(payload["pendingGuardian"]); + } + + return result; + } +} + +class Guardian { + activationEpoch: number = 0; + address: IAddress = new Address(""); + serviceUID: string = ""; + + static fromHttpResponse(responsePart: any): Guardian { + const result = new Guardian(); + + result.activationEpoch = Number(responsePart["activationEpoch"] || 0); + result.address = new Address(responsePart["address"] || ""); + result.serviceUID = responsePart["serviceUID"] || ""; + + return result; + } +} diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 98b57fa4..eecea7e3 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -1,5 +1,5 @@ import axios, { AxiosRequestConfig } from "axios"; -import { AccountOnNetwork } from "./accounts"; +import { AccountOnNetwork, GuardianData } from "./accounts"; import { defaultAxiosConfig, defaultPagination } from "./config"; import { ContractQueryRequest } from "./contractQueryRequest"; import { ContractQueryResponse } from "./contractQueryResponse"; @@ -55,6 +55,10 @@ export class ApiNetworkProvider implements INetworkProvider { return account; } + async getGuardianData(address: IAddress): Promise { + return await this.backingProxyNetworkProvider.getGuardianData(address); + } + async getFungibleTokensOfAccount(address: IAddress, pagination?: IPagination): Promise { pagination = pagination || defaultPagination; diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index fad7ae2d..2e428b8d 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -1,5 +1,5 @@ import axios, { AxiosRequestConfig } from "axios"; -import { AccountOnNetwork } from "./accounts"; +import { AccountOnNetwork, GuardianData } from "./accounts"; import { defaultAxiosConfig } from "./config"; import { EsdtContractAddress } from "./constants"; import { ContractQueryRequest } from "./contractQueryRequest"; @@ -55,6 +55,12 @@ export class ProxyNetworkProvider implements INetworkProvider { return account; } + async getGuardianData(address: IAddress): Promise { + const response = await this.doGetGeneric(`address/${address.bech32()}/guardian-data`); + const accountGuardian = GuardianData.fromHttpResponse(response.guardianData); + return accountGuardian; + } + async getFungibleTokensOfAccount(address: IAddress, _pagination?: IPagination): Promise { let url = `address/${address.bech32()}/esdt`; let response = await this.doGetGeneric(url); From 930f2488cfe483e4e832283a571545c6ec8de49f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 13 Apr 2023 11:46:29 +0300 Subject: [PATCH 100/133] Rename param. --- src-network-providers/accounts.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src-network-providers/accounts.ts b/src-network-providers/accounts.ts index c7e83f89..c94780bd 100644 --- a/src-network-providers/accounts.ts +++ b/src-network-providers/accounts.ts @@ -38,17 +38,17 @@ export class GuardianData { Object.assign(this, init); } - static fromHttpResponse(payload: any): GuardianData { + static fromHttpResponse(response: any): GuardianData { const result = new GuardianData(); - result.guarded = payload["guarded"] || false; + result.guarded = response["guarded"] || false; - if (payload["activeGuardian"]) { - result.activeGuardian = Guardian.fromHttpResponse(payload["activeGuardian"]); + if (response["activeGuardian"]) { + result.activeGuardian = Guardian.fromHttpResponse(response["activeGuardian"]); } - if (payload["pendingGuardian"]) { - result.pendingGuardian = Guardian.fromHttpResponse(payload["pendingGuardian"]); + if (response["pendingGuardian"]) { + result.pendingGuardian = Guardian.fromHttpResponse(response["pendingGuardian"]); } return result; From af389df6ab14ada9057e395ca1b61e6db67768d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 13 Apr 2023 13:12:05 +0300 Subject: [PATCH 101/133] Add "getCurrentGuardianAddress". --- src-network-providers/accounts.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src-network-providers/accounts.ts b/src-network-providers/accounts.ts index c94780bd..7c2a29dc 100644 --- a/src-network-providers/accounts.ts +++ b/src-network-providers/accounts.ts @@ -53,6 +53,14 @@ export class GuardianData { return result; } + + getCurrentGuardianAddress(): IAddress | undefined { + if (!this.guarded) { + return undefined; + } + + return this.activeGuardian?.address; + } } class Guardian { From 4ba9d93b858865b75077284ae098e277a18e2942 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Mon, 26 Jun 2023 15:03:24 +0300 Subject: [PATCH 102/133] add `TransactionEventData` class --- .../providers.dev.net.spec.ts | 20 +++++++++++++ src-network-providers/transactionEvents.ts | 28 +++++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index cb58f22a..c8162de9 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -193,6 +193,26 @@ describe("test network providers on devnet: Proxy and API", function () { proxyResponse.hyperblockHash = ""; } + it.only("should have the same response for transactions with events", async function () { + const hash = "c451566a6168e38d2980fcb83d4ea154f78d53f7abf3264dd51c2c7c585671aa"; + + let apiResponse = await apiProvider.getTransaction(hash); + let proxyResponse = await proxyProvider.getTransaction(hash); + + assert.exists(apiResponse.logs); + assert.exists(proxyResponse.logs); + assert.exists(apiResponse.logs.events) + assert.exists(proxyResponse.logs.events) + assert.equal(apiResponse.logs.events[0].topics[0].hex(), "5745474c442d643763366262") + assert.equal(apiResponse.logs.events[0].topics[1].hex(), "") + assert.equal(apiResponse.logs.events[0].topics[2].hex(), "0de0b6b3a7640000") + assert.equal(apiResponse.logs.events[0].topics[3].hex(), "00000000000000000500e01285f90311fb5925a9623a1dc62eee41fa8c869a0d") + assert.equal(proxyResponse.logs.events[0].topics[0].hex(), "5745474c442d643763366262") + assert.equal(proxyResponse.logs.events[0].topics[1].hex(), "") + assert.equal(proxyResponse.logs.events[0].topics[2].hex(), "0de0b6b3a7640000") + assert.equal(proxyResponse.logs.events[0].topics[3].hex(), "00000000000000000500e01285f90311fb5925a9623a1dc62eee41fa8c869a0d") + }); + // TODO: Fix differences of "tx.status", then enable this test. it.skip("should have same response for getTransactionStatus()", async function () { this.timeout(20000); diff --git a/src-network-providers/transactionEvents.ts b/src-network-providers/transactionEvents.ts index 780a1034..0fc958dd 100644 --- a/src-network-providers/transactionEvents.ts +++ b/src-network-providers/transactionEvents.ts @@ -5,6 +5,7 @@ export class TransactionEvent { address: IAddress = new Address(""); identifier: string = ""; topics: TransactionEventTopic[] = []; + data_payload: TransactionEventData = new TransactionEventData(Buffer.from("", "utf8")); data: string = ""; constructor(init?: Partial) { @@ -21,8 +22,11 @@ export class TransactionEvent { result.address = new Address(responsePart.address); result.identifier = responsePart.identifier || ""; result.topics = (responsePart.topics || []).map(topic => new TransactionEventTopic(topic)); - result.data = Buffer.from(responsePart.data || "", "base64").toString(); - + + const raw_data = Buffer.from(responsePart.data || "", "base64") + result.data_payload = new TransactionEventData(raw_data); + result.data = raw_data.toString(); + return result; } @@ -35,6 +39,26 @@ export class TransactionEvent { } } +export class TransactionEventData { + private readonly raw: Buffer; + + constructor(data: Buffer) { + this.raw = data; + } + + toString(): string { + return this.raw.toString("utf8"); + } + + hex(): string { + return this.raw.toString("hex"); + } + + valueOf(): Buffer { + return this.raw; + } +} + export class TransactionEventTopic { private readonly raw: Buffer; From b61dd61e36f34e5c9a5baffd53941451d0dabde4 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Mon, 26 Jun 2023 15:05:04 +0300 Subject: [PATCH 103/133] fix --- src-network-providers/transactionEvents.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src-network-providers/transactionEvents.ts b/src-network-providers/transactionEvents.ts index 0fc958dd..2d911ca4 100644 --- a/src-network-providers/transactionEvents.ts +++ b/src-network-providers/transactionEvents.ts @@ -5,7 +5,7 @@ export class TransactionEvent { address: IAddress = new Address(""); identifier: string = ""; topics: TransactionEventTopic[] = []; - data_payload: TransactionEventData = new TransactionEventData(Buffer.from("", "utf8")); + dataPayload: TransactionEventData = new TransactionEventData(Buffer.from("", "utf8")); data: string = ""; constructor(init?: Partial) { @@ -24,7 +24,7 @@ export class TransactionEvent { result.topics = (responsePart.topics || []).map(topic => new TransactionEventTopic(topic)); const raw_data = Buffer.from(responsePart.data || "", "base64") - result.data_payload = new TransactionEventData(raw_data); + result.dataPayload = new TransactionEventData(raw_data); result.data = raw_data.toString(); return result; From 88e409d1695ca21b253f5adf358a9c5ed640cde2 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Mon, 26 Jun 2023 15:10:52 +0300 Subject: [PATCH 104/133] rename variable --- src-network-providers/transactionEvents.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src-network-providers/transactionEvents.ts b/src-network-providers/transactionEvents.ts index 2d911ca4..3c8cb1d8 100644 --- a/src-network-providers/transactionEvents.ts +++ b/src-network-providers/transactionEvents.ts @@ -23,9 +23,9 @@ export class TransactionEvent { result.identifier = responsePart.identifier || ""; result.topics = (responsePart.topics || []).map(topic => new TransactionEventTopic(topic)); - const raw_data = Buffer.from(responsePart.data || "", "base64") - result.dataPayload = new TransactionEventData(raw_data); - result.data = raw_data.toString(); + const rawData = Buffer.from(responsePart.data || "", "base64") + result.dataPayload = new TransactionEventData(rawData); + result.data = rawData.toString(); return result; } From f1076f9a61349d74649f1829569b3a2dec9fc83e Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Tue, 11 Jul 2023 14:58:34 +0300 Subject: [PATCH 105/133] new tx status for proxy --- src-network-providers/proxyNetworkProvider.ts | 20 +++++- .../transactionCompletionStrategy.ts | 69 ------------------- src-network-providers/transactions.ts | 22 ++++-- 3 files changed, 32 insertions(+), 79 deletions(-) delete mode 100644 src-network-providers/transactionCompletionStrategy.ts diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 2e428b8d..337155a8 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -99,15 +99,29 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokenData; } - async getTransaction(txHash: string): Promise { + async getTransaction(txHash: string, with_process_status?: boolean): Promise { + let processStatusPromise: Promise | undefined; + + if (with_process_status === true) { + processStatusPromise = this.getTransactionStatus(txHash); + } + let url = this.buildUrlWithQueryParameters(`transaction/${txHash}`, { withResults: "true" }); let response = await this.doGetGeneric(url); - let transaction = TransactionOnNetwork.fromProxyHttpResponse(txHash, response.transaction); + + let transaction: TransactionOnNetwork; + if (processStatusPromise !== undefined) { + const processStatus = await processStatusPromise; + transaction = TransactionOnNetwork.fromProxyHttpResponse(txHash, response.transaction, processStatus); + } + else { + transaction = TransactionOnNetwork.fromProxyHttpResponse(txHash, response.transaction); + } return transaction; } async getTransactionStatus(txHash: string): Promise { - let response = await this.doGetGeneric(`transaction/${txHash}/status`); + let response = await this.doGetGeneric(`transaction/${txHash}/process-status`); let status = new TransactionStatus(response.status); return status; } diff --git a/src-network-providers/transactionCompletionStrategy.ts b/src-network-providers/transactionCompletionStrategy.ts deleted file mode 100644 index cd072c20..00000000 --- a/src-network-providers/transactionCompletionStrategy.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { TransactionStatus } from "./transactionStatus"; -import { TransactionLogs } from "./transactionLogs"; -import { isPaddedHex } from "./primitives"; - -interface ITransactionOnNetwork { - logs: TransactionLogs; - status: TransactionStatus; - hyperblockNonce: number; - data: Buffer; -} - -const WellKnownCompletionEvents = ["completedTxEvent", "SCDeploy", "signalError"]; - -/** - * Algorithm for detecting transaction completion. - * Based on some heuristics (a bit imprecise therefore, at this moment). - */ -export class TransactionCompletionStrategyOnProxy { - isCompleted(transaction: ITransactionOnNetwork): boolean { - if (transaction.status.isPending()) { - // Certainly not completed. - return false; - } - - // Handle gateway mechanics: - for (const completionEvent of WellKnownCompletionEvents) { - if (transaction.logs.findFirstOrNoneEvent(completionEvent)) { - // Certainly completed. - console.debug("TransactionCompletionStrategy.isCompleted(), found event:", completionEvent); - return true; - } - } - - if (this.isCertainlyMoveBalance(transaction.data)) { - return transaction.status.isExecuted(); - } - - let hyperblockNonce = transaction.hyperblockNonce; - - // Imprecise condition, uncertain completion (usually sufficient, though). - // This is WRONG when (at least): timeOf(block with execution at destination is notarized) < timeOf(the "completedTxEvent" occurs). - if (hyperblockNonce > 0) { - console.debug("TransactionCompletionStrategy.isCompleted(), found hyperblock nonce:", hyperblockNonce); - return true; - } - - return false; - } - - private isCertainlyMoveBalance(transactionData: Buffer): boolean { - let parts = transactionData.toString().split("@"); - let prefix = parts[0]; - let otherParts = parts.slice(1); - let emptyPrefix = !prefix; - let somePartsAreNotValidArguments = !otherParts.every(part => this.looksLikeValidArgument(part)); - - return emptyPrefix || somePartsAreNotValidArguments; - } - - private looksLikeValidArgument(arg: string) { - return isPaddedHex(arg); - } -} - -export class TransactionCompletionStrategyOnAPI { - isCompleted(transaction: ITransactionOnNetwork): boolean { - return !transaction.status.isPending(); - } -} diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index 95bee527..42e6836b 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -2,12 +2,11 @@ import { TransactionStatus } from "./transactionStatus"; import { ContractResults } from "./contractResults"; import { Address } from "./primitives"; import { IAddress } from "./interface"; -import { TransactionCompletionStrategyOnAPI, TransactionCompletionStrategyOnProxy } from "./transactionCompletionStrategy"; import { TransactionLogs } from "./transactionLogs"; import { TransactionReceipt } from "./transactionReceipt"; export class TransactionOnNetwork { - isCompleted: boolean = false; + isCompleted?: boolean; hash: string = ""; type: string = ""; nonce: number = 0; @@ -35,19 +34,28 @@ export class TransactionOnNetwork { Object.assign(this, init); } - static fromProxyHttpResponse(txHash: string, response: any): TransactionOnNetwork { + static fromProxyHttpResponse(txHash: string, response: any, process_status?: TransactionStatus | undefined): TransactionOnNetwork { let result = TransactionOnNetwork.fromHttpResponse(txHash, response); result.contractResults = ContractResults.fromProxyHttpResponse(response.smartContractResults || []); - result.isCompleted = new TransactionCompletionStrategyOnProxy().isCompleted(result); - // TODO: uniformize transaction status. + + if (process_status !== undefined) { + result.status = process_status; + + if (result.status.isSuccessful() || result.status.isFailed()) { + result.isCompleted = true; + } + else { + result.isCompleted = false; + } + } + return result; } static fromApiHttpResponse(txHash: string, response: any): TransactionOnNetwork { let result = TransactionOnNetwork.fromHttpResponse(txHash, response); result.contractResults = ContractResults.fromApiHttpResponse(response.results || []); - result.isCompleted = new TransactionCompletionStrategyOnAPI().isCompleted(result); - // TODO: uniformize transaction status. + result.isCompleted = !result.status.isPending(); return result; } From a08003272445645d47d5ff16c6ccc97d1dc786e9 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Tue, 11 Jul 2023 15:57:42 +0300 Subject: [PATCH 106/133] started to fix tests --- .../providers.dev.net.spec.ts | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index c8162de9..251c552c 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -1,6 +1,6 @@ import { assert } from "chai"; import { ApiNetworkProvider } from "./apiNetworkProvider"; -import { INetworkProvider } from "./interface"; +import { INetworkProvider, IPagination } from "./interface"; import { Address } from "./primitives"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { MockQuery } from "./testscommon/dummyQuery"; @@ -27,7 +27,15 @@ describe("test network providers on devnet: Proxy and API", function () { let apiResponse = await apiProvider.getNetworkStatus(); let proxyResponse = await proxyProvider.getNetworkStatus(); - assert.deepEqual(apiResponse, proxyResponse); + assert.equal(apiResponse.CurrentRound, proxyResponse.CurrentRound); + assert.equal(apiResponse.EpochNumber, proxyResponse.EpochNumber); + assert.equal(apiResponse.NonceAtEpochStart, proxyResponse.NonceAtEpochStart); + assert.equal(apiResponse.RoundAtEpochStart, proxyResponse.RoundAtEpochStart); + assert.equal(apiResponse.RoundsPerEpoch, proxyResponse.RoundsPerEpoch); + // done this way because the nonces may change until both requests are executed + assert.approximately(apiResponse.HighestFinalNonce, proxyResponse.HighestFinalNonce, 1); + assert.approximately(apiResponse.Nonce, proxyResponse.Nonce, 1); + assert.approximately(apiResponse.NoncesPassedInCurrentEpoch, proxyResponse.NoncesPassedInCurrentEpoch, 1); }); // TODO: Enable test after implementing ProxyNetworkProvider.getNetworkStakeStatistics(). @@ -57,28 +65,29 @@ describe("test network providers on devnet: Proxy and API", function () { it("should have same response for getFungibleTokensOfAccount(), getFungibleTokenOfAccount()", async function () { this.timeout(30000); - + // can't assert for deepequal because the raw response it's not the same for (const user of [carol, dan]) { - let apiResponse = await apiProvider.getFungibleTokensOfAccount(user); - let proxyResponse = await proxyProvider.getFungibleTokensOfAccount(user); - - assert.deepEqual(apiResponse.slice(0, 100), proxyResponse.slice(0, 100)); - - for (const item of apiResponse.slice(0, 5)) { - let apiResponse = await apiProvider.getFungibleTokenOfAccount(user, item.identifier); - let proxyResponse = await proxyProvider.getFungibleTokenOfAccount(user, item.identifier); - - assert.deepEqual(apiResponse, proxyResponse, `user: ${user.bech32()}, token: ${item.identifier}`); + let apiResponse = (await apiProvider.getFungibleTokensOfAccount(user)).slice(0, 20); + let proxyResponse = (await proxyProvider.getFungibleTokensOfAccount(user)).slice(0, 20); + + for (let i = 0; i < apiResponse.length; i++) { + console.log(apiResponse[i]); + console.log(proxyResponse[i]); + assert.equal(apiResponse[i].identifier, proxyResponse[i].identifier); + assert.equal(apiResponse[i].balance.valueOf, proxyResponse[i].balance.valueOf); } } }); - it("should have same response for getNonFungibleTokensOfAccount(), getNonFungibleTokenOfAccount", async function () { + it.only("should have same response for getNonFungibleTokensOfAccount(), getNonFungibleTokenOfAccount", async function () { this.timeout(30000); for (const user of [alice, bob, carol, dan]) { let apiResponse = await apiProvider.getNonFungibleTokensOfAccount(user); let proxyResponse = await proxyProvider.getNonFungibleTokensOfAccount(user); + console.log(apiResponse[0]); + console.log(proxyResponse[0]); + return for (const item of apiResponse) { // Gateway does not provide "type". @@ -193,7 +202,7 @@ describe("test network providers on devnet: Proxy and API", function () { proxyResponse.hyperblockHash = ""; } - it.only("should have the same response for transactions with events", async function () { + it("should have the same response for transactions with events", async function () { const hash = "c451566a6168e38d2980fcb83d4ea154f78d53f7abf3264dd51c2c7c585671aa"; let apiResponse = await apiProvider.getTransaction(hash); From 275e1801e8639bd6f9c3d3e5ee3e529f000fa711 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Tue, 11 Jul 2023 16:07:23 +0300 Subject: [PATCH 107/133] change variable names to camel case --- src-network-providers/proxyNetworkProvider.ts | 4 ++-- src-network-providers/transactions.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 337155a8..ebc25443 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -99,10 +99,10 @@ export class ProxyNetworkProvider implements INetworkProvider { return tokenData; } - async getTransaction(txHash: string, with_process_status?: boolean): Promise { + async getTransaction(txHash: string, withProcessStatus?: boolean): Promise { let processStatusPromise: Promise | undefined; - if (with_process_status === true) { + if (withProcessStatus === true) { processStatusPromise = this.getTransactionStatus(txHash); } diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index 42e6836b..d1e98105 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -34,12 +34,12 @@ export class TransactionOnNetwork { Object.assign(this, init); } - static fromProxyHttpResponse(txHash: string, response: any, process_status?: TransactionStatus | undefined): TransactionOnNetwork { + static fromProxyHttpResponse(txHash: string, response: any, processStatus?: TransactionStatus | undefined): TransactionOnNetwork { let result = TransactionOnNetwork.fromHttpResponse(txHash, response); result.contractResults = ContractResults.fromProxyHttpResponse(response.smartContractResults || []); - if (process_status !== undefined) { - result.status = process_status; + if (processStatus !== undefined) { + result.status = processStatus; if (result.status.isSuccessful() || result.status.isFailed()) { result.isCompleted = true; From b95ca008ad47342dfc220ef5469136cb855c81a2 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Tue, 11 Jul 2023 17:45:54 +0300 Subject: [PATCH 108/133] fix tests --- src-network-providers/interface.ts | 2 +- .../providers.dev.net.spec.ts | 71 +++++++++---------- src-network-providers/tokenDefinitions.ts | 20 +++--- src-network-providers/tokens.ts | 2 +- 4 files changed, 46 insertions(+), 49 deletions(-) diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index 64109723..fa15abf2 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -61,7 +61,7 @@ export interface INetworkProvider { /** * Fetches the state of a transaction. */ - getTransaction(txHash: string): Promise; + getTransaction(txHash: string, withProcessStatus?: boolean): Promise; /** * Queries the status of a transaction. diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 251c552c..361192b9 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -71,41 +71,43 @@ describe("test network providers on devnet: Proxy and API", function () { let proxyResponse = (await proxyProvider.getFungibleTokensOfAccount(user)).slice(0, 20); for (let i = 0; i < apiResponse.length; i++) { - console.log(apiResponse[i]); - console.log(proxyResponse[i]); assert.equal(apiResponse[i].identifier, proxyResponse[i].identifier); assert.equal(apiResponse[i].balance.valueOf, proxyResponse[i].balance.valueOf); } } }); - it.only("should have same response for getNonFungibleTokensOfAccount(), getNonFungibleTokenOfAccount", async function () { + it("should have same response for getNonFungibleTokensOfAccount(), getNonFungibleTokenOfAccount", async function () { this.timeout(30000); - for (const user of [alice, bob, carol, dan]) { - let apiResponse = await apiProvider.getNonFungibleTokensOfAccount(user); - let proxyResponse = await proxyProvider.getNonFungibleTokensOfAccount(user); - console.log(apiResponse[0]); - console.log(proxyResponse[0]); - return - - for (const item of apiResponse) { - // Gateway does not provide "type". - item.type = ""; - } + let apiResponse = (await apiProvider.getNonFungibleTokensOfAccount(dan)).slice(0, 20); + let proxyResponse = (await proxyProvider.getNonFungibleTokensOfAccount(dan)).slice(0, 20); + + // unset unconsistent fields + for (let i = 0; i < apiResponse.length; i++) { + apiResponse[i].type = ""; + proxyResponse[i].type = ""; + apiResponse[i].name = ""; + proxyResponse[i].name = ""; + apiResponse[i].decimals = 0; + apiResponse[i].decimals = 0; + } - assert.deepEqual(apiResponse.slice(0, 100), proxyResponse.slice(0, 100)); + assert.deepEqual(apiResponse, proxyResponse); - for (const item of apiResponse.slice(0, 5)) { - let apiResponse = await apiProvider.getNonFungibleTokenOfAccount(user, item.collection, item.nonce); - let proxyResponse = await proxyProvider.getNonFungibleTokenOfAccount(user, item.collection, item.nonce); + const item = apiResponse[0]; + let apiItemResponse = await apiProvider.getNonFungibleTokenOfAccount(dan, item.collection, item.nonce); + let proxyItemResponse = await proxyProvider.getNonFungibleTokenOfAccount(dan, item.collection, item.nonce); - // Gateway does not provide "type". - apiResponse.type = ""; + // unset unconsistent fields + apiItemResponse.type = ""; + proxyItemResponse.type = ""; + apiItemResponse.name = ""; + proxyItemResponse.name = ""; + apiItemResponse.decimals = 0; + proxyItemResponse.decimals = 0; - assert.deepEqual(apiResponse, proxyResponse, `user: ${user.bech32()}, token: ${item.identifier}`); - } - } + assert.deepEqual(apiResponse, proxyResponse, `user: ${dan.bech32()}, token: ${item.identifier}`); }); it("should be able to send transaction(s)", async function () { @@ -168,17 +170,13 @@ describe("test network providers on devnet: Proxy and API", function () { this.timeout(20000); let hashes = [ - "a069c663831002651fd542479869cc61103465f3284dace772e7480f81429fa8", - "de3bc87f3e057e28ea6a625acd6d6d332e24f35ea73e820462b71256c8ecffb7", - "dbefa0299fe6b2336eb0bc3123fa623845c276e5c6e2a175adf1a562d5e77718", - "2a8ccbd91b7d9460a86174b5a8d4e6aa073b38674d1ee8107e728980a66f0676", - // TODO: uncomment after fix (SCR missing on API) - // "be7914b1eb4c6bd352ba1d86991959b443e446e0ad49fb796be3495c287b2472" + "2e6bd2671dbb57f1f1013c89f044359c2465f1514e0ea718583900e43c1931fe", + "c451566a6168e38d2980fcb83d4ea154f78d53f7abf3264dd51c2c7c585671aa" ]; for (const hash of hashes) { let apiResponse = await apiProvider.getTransaction(hash); - let proxyResponse = await proxyProvider.getTransaction(hash); + let proxyResponse = await proxyProvider.getTransaction(hash, true); ignoreKnownTransactionDifferencesBetweenProviders(apiResponse, proxyResponse); assert.deepEqual(apiResponse, proxyResponse, `transaction: ${hash}`); @@ -222,16 +220,13 @@ describe("test network providers on devnet: Proxy and API", function () { assert.equal(proxyResponse.logs.events[0].topics[3].hex(), "00000000000000000500e01285f90311fb5925a9623a1dc62eee41fa8c869a0d") }); - // TODO: Fix differences of "tx.status", then enable this test. - it.skip("should have same response for getTransactionStatus()", async function () { + it("should have same response for getTransactionStatus()", async function () { this.timeout(20000); let hashes = [ - "a069c663831002651fd542479869cc61103465f3284dace772e7480f81429fa8", - "de3bc87f3e057e28ea6a625acd6d6d332e24f35ea73e820462b71256c8ecffb7", - "dbefa0299fe6b2336eb0bc3123fa623845c276e5c6e2a175adf1a562d5e77718", - "2a8ccbd91b7d9460a86174b5a8d4e6aa073b38674d1ee8107e728980a66f0676", - "be7914b1eb4c6bd352ba1d86991959b443e446e0ad49fb796be3495c287b2472" + "2e6bd2671dbb57f1f1013c89f044359c2465f1514e0ea718583900e43c1931fe", + "c451566a6168e38d2980fcb83d4ea154f78d53f7abf3264dd51c2c7c585671aa", + "cd2da63a51fd422c8b69a1b5ebcb9edbbf0eb9750c3fe8e199d39ed5d82000e9" ]; for (const hash of hashes) { @@ -245,7 +240,7 @@ describe("test network providers on devnet: Proxy and API", function () { it("should have same response for getDefinitionOfFungibleToken()", async function () { this.timeout(10000); - let identifiers = ["FOO-b6f543", "BAR-c80d29", "COUNTER-b7401d", "WEB-5d08be"]; + let identifiers = ["FOO-b6f543", "BAR-c80d29", "COUNTER-b7401d"]; for (const identifier of identifiers) { let apiResponse = await apiProvider.getDefinitionOfFungibleToken(identifier); diff --git a/src-network-providers/tokenDefinitions.ts b/src-network-providers/tokenDefinitions.ts index fc97af03..ea469b8f 100644 --- a/src-network-providers/tokenDefinitions.ts +++ b/src-network-providers/tokenDefinitions.ts @@ -99,6 +99,8 @@ export class DefinitionOfTokenCollectionOnNetwork { result.canPause = payload.canPause || false; result.canFreeze = payload.canFreeze || false; result.canWipe = payload.canWipe || false; + result.canUpgrade = payload.canUpgrade || false; + result.canAddSpecialRoles = payload.canAddSpecialRoles || false; result.canTransferNftCreateRole = payload.canTransferNftCreateRole || false; return result; @@ -119,15 +121,15 @@ export class DefinitionOfTokenCollectionOnNetwork { result.name = tokenName.toString(); result.ticker = collection; result.owner = Address.fromPubkey(owner); - result.decimals = properties.NumDecimals.toNumber(); - result.canPause = properties.CanPause; - result.canFreeze = properties.CanFreeze; - result.canWipe = properties.CanWipe; - result.canUpgrade = properties.CanUpgrade; - result.canChangeOwner = properties.CanChangeOwner; - result.canAddSpecialRoles = properties.CanAddSpecialRoles; - result.canTransferNftCreateRole = properties.CanTransferNFTCreateRole; - result.canCreateMultiShard = properties.CanCreateMultiShard; + result.decimals = properties.NumDecimals.toNumber() || 0; + result.canPause = properties.CanPause || false; + result.canFreeze = properties.CanFreeze || false; + result.canWipe = properties.CanWipe || false; + result.canUpgrade = properties.CanUpgrade || false; + result.canChangeOwner = properties.CanChangeOwner || false; + result.canAddSpecialRoles = properties.CanAddSpecialRoles || false; + result.canTransferNftCreateRole = properties.CanTransferNFTCreateRole || false; + result.canCreateMultiShard = properties.CanCreateMultiShard || false; return result; } diff --git a/src-network-providers/tokens.ts b/src-network-providers/tokens.ts index 31f685b5..855d2428 100644 --- a/src-network-providers/tokens.ts +++ b/src-network-providers/tokens.ts @@ -81,7 +81,7 @@ export class NonFungibleTokenOfAccountOnNetwork { result.supply = new BigNumber(payload.balance || 1); result.royalties = new BigNumber(payload.royalties || 0); result.assets = payload.assets || []; - result.balance = new BigNumber(payload.balance || 0); + result.balance = new BigNumber(payload.balance || 1); return result; } From a2c07bc8733b64dcce841672c37a085ff1b19620 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Wed, 12 Jul 2023 11:02:46 +0300 Subject: [PATCH 109/133] fix after review --- src-network-providers/proxyNetworkProvider.ts | 10 +++------- src-network-providers/transactions.ts | 9 ++------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index ebc25443..995f7ac4 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -109,15 +109,11 @@ export class ProxyNetworkProvider implements INetworkProvider { let url = this.buildUrlWithQueryParameters(`transaction/${txHash}`, { withResults: "true" }); let response = await this.doGetGeneric(url); - let transaction: TransactionOnNetwork; - if (processStatusPromise !== undefined) { + if (processStatusPromise) { const processStatus = await processStatusPromise; - transaction = TransactionOnNetwork.fromProxyHttpResponse(txHash, response.transaction, processStatus); + return TransactionOnNetwork.fromProxyHttpResponse(txHash, response.transaction, processStatus); } - else { - transaction = TransactionOnNetwork.fromProxyHttpResponse(txHash, response.transaction); - } - return transaction; + return TransactionOnNetwork.fromProxyHttpResponse(txHash, response.transaction); } async getTransactionStatus(txHash: string): Promise { diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index d1e98105..5d701e2b 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -38,15 +38,10 @@ export class TransactionOnNetwork { let result = TransactionOnNetwork.fromHttpResponse(txHash, response); result.contractResults = ContractResults.fromProxyHttpResponse(response.smartContractResults || []); - if (processStatus !== undefined) { + if (processStatus) { result.status = processStatus; - if (result.status.isSuccessful() || result.status.isFailed()) { - result.isCompleted = true; - } - else { - result.isCompleted = false; - } + result.isCompleted = result.status.isSuccessful() || result.status.isFailed() } return result; From a9e35e440bc75e1fa23ffbef6fc261cda0d404be Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Wed, 12 Jul 2023 14:08:30 +0300 Subject: [PATCH 110/133] small fixes & tests refactoring --- .../providers.dev.net.spec.ts | 45 +++++++++---------- src-network-providers/transactions.ts | 1 - 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 361192b9..dcf1a210 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -1,11 +1,11 @@ import { assert } from "chai"; import { ApiNetworkProvider } from "./apiNetworkProvider"; -import { INetworkProvider, IPagination } from "./interface"; +import { INetworkProvider } from "./interface"; import { Address } from "./primitives"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { MockQuery } from "./testscommon/dummyQuery"; import { TransactionOnNetwork } from "./transactions"; -import { TransactionStatus } from "./transactionStatus"; +import { NonFungibleTokenOfAccountOnNetwork } from "./tokens"; describe("test network providers on devnet: Proxy and API", function () { let alice = new Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); @@ -55,7 +55,7 @@ describe("test network providers on devnet: Proxy and API", function () { }); it("should have same response for getAccount()", async function () { - for (const user of [bob, carol, dan]) { + for (const user of [alice, bob, carol, dan]) { let apiResponse = await apiProvider.getAccount(user); let proxyResponse = await proxyProvider.getAccount(user); @@ -65,7 +65,7 @@ describe("test network providers on devnet: Proxy and API", function () { it("should have same response for getFungibleTokensOfAccount(), getFungibleTokenOfAccount()", async function () { this.timeout(30000); - // can't assert for deepequal because the raw response it's not the same + for (const user of [carol, dan]) { let apiResponse = (await apiProvider.getFungibleTokensOfAccount(user)).slice(0, 20); let proxyResponse = (await proxyProvider.getFungibleTokensOfAccount(user)).slice(0, 20); @@ -83,14 +83,10 @@ describe("test network providers on devnet: Proxy and API", function () { let apiResponse = (await apiProvider.getNonFungibleTokensOfAccount(dan)).slice(0, 20); let proxyResponse = (await proxyProvider.getNonFungibleTokensOfAccount(dan)).slice(0, 20); - // unset unconsistent fields + assert.equal(apiResponse.length, proxyResponse.length); + for (let i = 0; i < apiResponse.length; i++) { - apiResponse[i].type = ""; - proxyResponse[i].type = ""; - apiResponse[i].name = ""; - proxyResponse[i].name = ""; - apiResponse[i].decimals = 0; - apiResponse[i].decimals = 0; + removeInconsistencyForNonFungibleTokenOfAccount(apiResponse[i], proxyResponse[i]); } assert.deepEqual(apiResponse, proxyResponse); @@ -99,17 +95,21 @@ describe("test network providers on devnet: Proxy and API", function () { let apiItemResponse = await apiProvider.getNonFungibleTokenOfAccount(dan, item.collection, item.nonce); let proxyItemResponse = await proxyProvider.getNonFungibleTokenOfAccount(dan, item.collection, item.nonce); - // unset unconsistent fields - apiItemResponse.type = ""; - proxyItemResponse.type = ""; - apiItemResponse.name = ""; - proxyItemResponse.name = ""; - apiItemResponse.decimals = 0; - proxyItemResponse.decimals = 0; - + removeInconsistencyForNonFungibleTokenOfAccount(apiItemResponse, proxyItemResponse); assert.deepEqual(apiResponse, proxyResponse, `user: ${dan.bech32()}, token: ${item.identifier}`); }); + // TODO: Strive to have as little differences as possible between Proxy and API. + function removeInconsistencyForNonFungibleTokenOfAccount(apiResponse: NonFungibleTokenOfAccountOnNetwork, proxyResponse: NonFungibleTokenOfAccountOnNetwork) { + // unset unconsistent fields + apiResponse.type = ""; + proxyResponse.type = ""; + apiResponse.name = ""; + proxyResponse.name = ""; + apiResponse.decimals = 0; + apiResponse.decimals = 0; + } + it("should be able to send transaction(s)", async function () { this.timeout(5000); @@ -178,7 +178,7 @@ describe("test network providers on devnet: Proxy and API", function () { let apiResponse = await apiProvider.getTransaction(hash); let proxyResponse = await proxyProvider.getTransaction(hash, true); - ignoreKnownTransactionDifferencesBetweenProviders(apiResponse, proxyResponse); + ignoreKnownTransactionDifferencesBetweenProviders(proxyResponse); assert.deepEqual(apiResponse, proxyResponse, `transaction: ${hash}`); // Also assert completion @@ -188,10 +188,7 @@ describe("test network providers on devnet: Proxy and API", function () { }); // TODO: Strive to have as little differences as possible between Proxy and API. - function ignoreKnownTransactionDifferencesBetweenProviders(apiResponse: TransactionOnNetwork, proxyResponse: TransactionOnNetwork) { - // TODO: Remove this once "tx.status" is uniformized. - apiResponse.status = proxyResponse.status = new TransactionStatus("ignore"); - + function ignoreKnownTransactionDifferencesBetweenProviders(proxyResponse: TransactionOnNetwork) { // Ignore fields which are not present on API response: proxyResponse.type = ""; proxyResponse.epoch = 0; diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index 5d701e2b..18fcd1d4 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -40,7 +40,6 @@ export class TransactionOnNetwork { if (processStatus) { result.status = processStatus; - result.isCompleted = result.status.isSuccessful() || result.status.isFailed() } From 94ee687abd810af120f6bab18e23f18616ea61fc Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Wed, 12 Jul 2023 14:21:36 +0300 Subject: [PATCH 111/133] update test --- src-network-providers/providers.dev.net.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index dcf1a210..9106baf4 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -55,7 +55,7 @@ describe("test network providers on devnet: Proxy and API", function () { }); it("should have same response for getAccount()", async function () { - for (const user of [alice, bob, carol, dan]) { + for (const user of [alice, bob]) { let apiResponse = await apiProvider.getAccount(user); let proxyResponse = await proxyProvider.getAccount(user); From 19166b435404a2da4257b67b9539f6ff2ec33365 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Wed, 12 Jul 2023 14:31:57 +0300 Subject: [PATCH 112/133] update test --- src-network-providers/providers.dev.net.spec.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 9106baf4..e406e3d7 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -54,13 +54,11 @@ describe("test network providers on devnet: Proxy and API", function () { assert.deepEqual(apiResponse, proxyResponse); }); - it("should have same response for getAccount()", async function () { - for (const user of [alice, bob]) { - let apiResponse = await apiProvider.getAccount(user); - let proxyResponse = await proxyProvider.getAccount(user); + it.only("should have same response for getAccount()", async function () { + let apiResponse = await apiProvider.getAccount(alice); + let proxyResponse = await proxyProvider.getAccount(alice); - assert.deepEqual(apiResponse, proxyResponse); - } + assert.deepEqual(apiResponse, proxyResponse); }); it("should have same response for getFungibleTokensOfAccount(), getFungibleTokenOfAccount()", async function () { From 996426d19d3fe6c0b45fa9e1fe9222bab6050c06 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Thu, 13 Jul 2023 12:06:21 +0300 Subject: [PATCH 113/133] fixes after review --- src-network-providers/providers.dev.net.spec.ts | 14 +++++++------- src-network-providers/tokenDefinitions.ts | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index e406e3d7..30eaaf4f 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -9,9 +9,9 @@ import { NonFungibleTokenOfAccountOnNetwork } from "./tokens"; describe("test network providers on devnet: Proxy and API", function () { let alice = new Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); - let bob = new Address("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"); let carol = new Address("erd1k2s324ww2g0yj38qn2ch2jwctdy8mnfxep94q9arncc6xecg3xaq6mjse8"); let dan = new Address("erd1kyaqzaprcdnv4luvanah0gfxzzsnpaygsy6pytrexll2urtd05ts9vegu7"); + const MAX_NUMBER_OF_ITEMS_BY_DEFAULT = 20; let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.multiversx.com", { timeout: 10000 }); let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { timeout: 10000 }); @@ -54,7 +54,7 @@ describe("test network providers on devnet: Proxy and API", function () { assert.deepEqual(apiResponse, proxyResponse); }); - it.only("should have same response for getAccount()", async function () { + it("should have same response for getAccount()", async function () { let apiResponse = await apiProvider.getAccount(alice); let proxyResponse = await proxyProvider.getAccount(alice); @@ -65,8 +65,8 @@ describe("test network providers on devnet: Proxy and API", function () { this.timeout(30000); for (const user of [carol, dan]) { - let apiResponse = (await apiProvider.getFungibleTokensOfAccount(user)).slice(0, 20); - let proxyResponse = (await proxyProvider.getFungibleTokensOfAccount(user)).slice(0, 20); + let apiResponse = (await apiProvider.getFungibleTokensOfAccount(user)).slice(0, MAX_NUMBER_OF_ITEMS_BY_DEFAULT); + let proxyResponse = (await proxyProvider.getFungibleTokensOfAccount(user)).slice(0, MAX_NUMBER_OF_ITEMS_BY_DEFAULT); for (let i = 0; i < apiResponse.length; i++) { assert.equal(apiResponse[i].identifier, proxyResponse[i].identifier); @@ -78,8 +78,8 @@ describe("test network providers on devnet: Proxy and API", function () { it("should have same response for getNonFungibleTokensOfAccount(), getNonFungibleTokenOfAccount", async function () { this.timeout(30000); - let apiResponse = (await apiProvider.getNonFungibleTokensOfAccount(dan)).slice(0, 20); - let proxyResponse = (await proxyProvider.getNonFungibleTokensOfAccount(dan)).slice(0, 20); + let apiResponse = (await apiProvider.getNonFungibleTokensOfAccount(dan)).slice(0, MAX_NUMBER_OF_ITEMS_BY_DEFAULT); + let proxyResponse = (await proxyProvider.getNonFungibleTokensOfAccount(dan)).slice(0, MAX_NUMBER_OF_ITEMS_BY_DEFAULT); assert.equal(apiResponse.length, proxyResponse.length); @@ -105,7 +105,7 @@ describe("test network providers on devnet: Proxy and API", function () { apiResponse.name = ""; proxyResponse.name = ""; apiResponse.decimals = 0; - apiResponse.decimals = 0; + proxyResponse.decimals = 0; } it("should be able to send transaction(s)", async function () { diff --git a/src-network-providers/tokenDefinitions.ts b/src-network-providers/tokenDefinitions.ts index ea469b8f..63bfa523 100644 --- a/src-network-providers/tokenDefinitions.ts +++ b/src-network-providers/tokenDefinitions.ts @@ -121,7 +121,7 @@ export class DefinitionOfTokenCollectionOnNetwork { result.name = tokenName.toString(); result.ticker = collection; result.owner = Address.fromPubkey(owner); - result.decimals = properties.NumDecimals.toNumber() || 0; + result.decimals = properties.NumDecimals.toNumber() ?? 0; result.canPause = properties.CanPause || false; result.canFreeze = properties.CanFreeze || false; result.canWipe = properties.CanWipe || false; From 809494c3fd81df4a10e54d8787738e12fa1ba6b8 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Wed, 23 Aug 2023 10:26:40 +0300 Subject: [PATCH 114/133] fix test --- src-network-providers/providers.dev.net.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 30eaaf4f..5b49a9ad 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -27,12 +27,12 @@ describe("test network providers on devnet: Proxy and API", function () { let apiResponse = await apiProvider.getNetworkStatus(); let proxyResponse = await proxyProvider.getNetworkStatus(); - assert.equal(apiResponse.CurrentRound, proxyResponse.CurrentRound); assert.equal(apiResponse.EpochNumber, proxyResponse.EpochNumber); assert.equal(apiResponse.NonceAtEpochStart, proxyResponse.NonceAtEpochStart); assert.equal(apiResponse.RoundAtEpochStart, proxyResponse.RoundAtEpochStart); assert.equal(apiResponse.RoundsPerEpoch, proxyResponse.RoundsPerEpoch); // done this way because the nonces may change until both requests are executed + assert.approximately(apiResponse.CurrentRound, proxyResponse.CurrentRound, 1); assert.approximately(apiResponse.HighestFinalNonce, proxyResponse.HighestFinalNonce, 1); assert.approximately(apiResponse.Nonce, proxyResponse.Nonce, 1); assert.approximately(apiResponse.NoncesPassedInCurrentEpoch, proxyResponse.NoncesPassedInCurrentEpoch, 1); From 2a18abd8d82fcffdac0ef1a85663729c615f341f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Tue, 31 Oct 2023 21:50:38 +0200 Subject: [PATCH 115/133] For Sirius: handle logs.events.additionalData. --- .../providers.dev.net.spec.ts | 35 ++++++++++++++++++- src-network-providers/transactionEvents.ts | 20 ++++++++--- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 5b49a9ad..de534875 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -4,8 +4,9 @@ import { INetworkProvider } from "./interface"; import { Address } from "./primitives"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { MockQuery } from "./testscommon/dummyQuery"; -import { TransactionOnNetwork } from "./transactions"; import { NonFungibleTokenOfAccountOnNetwork } from "./tokens"; +import { TransactionEventData } from "./transactionEvents"; +import { TransactionOnNetwork } from "./transactions"; describe("test network providers on devnet: Proxy and API", function () { let alice = new Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); @@ -338,5 +339,37 @@ describe("test network providers on devnet: Proxy and API", function () { assert.deepEqual(apiResponse, proxyResponse); assert.deepEqual(apiResponse.getReturnDataParts(), proxyResponse.getReturnDataParts()); }); + + it.only("should handle events data on < Sirius and >= Sirius", async function () { + this.timeout(50000); + + const beforeSiriusApiProvider = new ApiNetworkProvider("https://devnet2-api.multiversx.com"); + const beforeSiriusProxyProvider = new ProxyNetworkProvider("https://devnet2-gateway.multiversx.com"); + + // We use the Testnet services, since they are backed by nodes with version >= Sirius (November 2023). + const afterSiriusApiProvider = new ApiNetworkProvider("https://testnet-api.multiversx.com"); + const afterSiriusProxyProvider = new ProxyNetworkProvider("https://testnet-gateway.multiversx.com"); + + const beforeSiriusApiResponse = await beforeSiriusApiProvider.getTransaction("51e53c6345c25fc4a454e64b96f43812e4a6cf3d01bbe4384da39e562b136aac"); + const beforeSiriusProxyResponse = await beforeSiriusProxyProvider.getTransaction("51e53c6345c25fc4a454e64b96f43812e4a6cf3d01bbe4384da39e562b136aac"); + + const afterSiriusApiResponse = await afterSiriusApiProvider.getTransaction("532087e5021c9ab8be8a4db5ad843cfe0610761f6334d9693b3765992fd05f67"); + // Contract result of "5320...5f67": + const afterSiriusProxyResponse = await afterSiriusProxyProvider.getTransaction("4bb22e85895b41bc3cd195079afa761cc4b430fb4ea19a6862f083de53f110ab"); + + assert.equal(beforeSiriusApiResponse.logs.events[0].data, "@6f7574206f662066756e6473"); + assert.equal(beforeSiriusProxyResponse.logs.events[0].data, "@6f7574206f662066756e6473"); + assert.deepEqual(beforeSiriusApiResponse.logs.events[0].dataPayload, TransactionEventData.fromBase64("QDZmNzU3NDIwNmY2NjIwNjY3NTZlNjQ3Mw==")); + assert.deepEqual(beforeSiriusProxyResponse.logs.events[0].dataPayload, TransactionEventData.fromBase64("QDZmNzU3NDIwNmY2NjIwNjY3NTZlNjQ3Mw==")); + + assert.equal(afterSiriusApiResponse.contractResults.items[0].logs.events[1].data, Buffer.from("AAAAAAAAA9sAAAA=", "base64").toString()); + assert.equal(afterSiriusProxyResponse.logs.events[1].data, Buffer.from("AAAAAAAAA9sAAAA=", "base64").toString()); + assert.deepEqual(afterSiriusApiResponse.contractResults.items[0].logs.events[1].dataPayload, TransactionEventData.fromBase64("AAAAAAAAA9sAAAA=")); + assert.deepEqual(afterSiriusProxyResponse.logs.events[1].dataPayload, TransactionEventData.fromBase64("AAAAAAAAA9sAAAA=")); + assert.deepEqual(afterSiriusApiResponse.contractResults.items[0].logs.events[1].additionalData, [TransactionEventData.fromBase64("AAAAAAAAA9sAAAA=")]); + + // This should be changed once the Gateway is updated. + assert.deepEqual(afterSiriusProxyResponse.logs.events[1].additionalData, []); + }); }); diff --git a/src-network-providers/transactionEvents.ts b/src-network-providers/transactionEvents.ts index 3c8cb1d8..b37d47ab 100644 --- a/src-network-providers/transactionEvents.ts +++ b/src-network-providers/transactionEvents.ts @@ -5,8 +5,13 @@ export class TransactionEvent { address: IAddress = new Address(""); identifier: string = ""; topics: TransactionEventTopic[] = []; - dataPayload: TransactionEventData = new TransactionEventData(Buffer.from("", "utf8")); + + /** + * @deprecated Use "dataPayload" instead. + */ data: string = ""; + dataPayload: TransactionEventData = new TransactionEventData(Buffer.from("", "utf8")); + additionalData: TransactionEventData[] = []; constructor(init?: Partial) { Object.assign(this, init); @@ -16,16 +21,17 @@ export class TransactionEvent { address: string, identifier: string, topics: string[], - data: string + data: string, + additionalData?: string[] }): TransactionEvent { let result = new TransactionEvent(); result.address = new Address(responsePart.address); result.identifier = responsePart.identifier || ""; result.topics = (responsePart.topics || []).map(topic => new TransactionEventTopic(topic)); - const rawData = Buffer.from(responsePart.data || "", "base64") - result.dataPayload = new TransactionEventData(rawData); - result.data = rawData.toString(); + result.dataPayload = TransactionEventData.fromBase64(responsePart.data); + result.additionalData = (responsePart.additionalData || []).map(TransactionEventData.fromBase64); + result.data = result.dataPayload.toString(); return result; } @@ -46,6 +52,10 @@ export class TransactionEventData { this.raw = data; } + static fromBase64(str: string): TransactionEventData { + return new TransactionEventData(Buffer.from(str || "", "base64")); + } + toString(): string { return this.raw.toString("utf8"); } From 46f3afc04c31fae3726fc480fc1fef388794f8a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 9 Nov 2023 10:07:54 +0200 Subject: [PATCH 116/133] Fix tests. --- src-network-providers/providers.dev.net.spec.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index de534875..750d2c3e 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -340,11 +340,11 @@ describe("test network providers on devnet: Proxy and API", function () { assert.deepEqual(apiResponse.getReturnDataParts(), proxyResponse.getReturnDataParts()); }); - it.only("should handle events data on < Sirius and >= Sirius", async function () { + it("should handle events data on < Sirius and >= Sirius", async function () { this.timeout(50000); - const beforeSiriusApiProvider = new ApiNetworkProvider("https://devnet2-api.multiversx.com"); - const beforeSiriusProxyProvider = new ProxyNetworkProvider("https://devnet2-gateway.multiversx.com"); + const beforeSiriusApiProvider = new ApiNetworkProvider("https://devnet-api.multiversx.com"); + const beforeSiriusProxyProvider = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com"); // We use the Testnet services, since they are backed by nodes with version >= Sirius (November 2023). const afterSiriusApiProvider = new ApiNetworkProvider("https://testnet-api.multiversx.com"); @@ -357,19 +357,22 @@ describe("test network providers on devnet: Proxy and API", function () { // Contract result of "5320...5f67": const afterSiriusProxyResponse = await afterSiriusProxyProvider.getTransaction("4bb22e85895b41bc3cd195079afa761cc4b430fb4ea19a6862f083de53f110ab"); + // Before Sirius assert.equal(beforeSiriusApiResponse.logs.events[0].data, "@6f7574206f662066756e6473"); assert.equal(beforeSiriusProxyResponse.logs.events[0].data, "@6f7574206f662066756e6473"); + assert.deepEqual(beforeSiriusApiResponse.logs.events[0].dataPayload, TransactionEventData.fromBase64("QDZmNzU3NDIwNmY2NjIwNjY3NTZlNjQ3Mw==")); assert.deepEqual(beforeSiriusProxyResponse.logs.events[0].dataPayload, TransactionEventData.fromBase64("QDZmNzU3NDIwNmY2NjIwNjY3NTZlNjQ3Mw==")); + // After Sirius assert.equal(afterSiriusApiResponse.contractResults.items[0].logs.events[1].data, Buffer.from("AAAAAAAAA9sAAAA=", "base64").toString()); assert.equal(afterSiriusProxyResponse.logs.events[1].data, Buffer.from("AAAAAAAAA9sAAAA=", "base64").toString()); + assert.deepEqual(afterSiriusApiResponse.contractResults.items[0].logs.events[1].dataPayload, TransactionEventData.fromBase64("AAAAAAAAA9sAAAA=")); assert.deepEqual(afterSiriusProxyResponse.logs.events[1].dataPayload, TransactionEventData.fromBase64("AAAAAAAAA9sAAAA=")); - assert.deepEqual(afterSiriusApiResponse.contractResults.items[0].logs.events[1].additionalData, [TransactionEventData.fromBase64("AAAAAAAAA9sAAAA=")]); - // This should be changed once the Gateway is updated. - assert.deepEqual(afterSiriusProxyResponse.logs.events[1].additionalData, []); + assert.deepEqual(afterSiriusApiResponse.contractResults.items[0].logs.events[1].additionalData, [TransactionEventData.fromBase64("AAAAAAAAA9sAAAA=")]); + assert.deepEqual(afterSiriusProxyResponse.logs.events[1].additionalData, [TransactionEventData.fromBase64("AAAAAAAAA9sAAAA=")]); }); }); From 04517d1b69600e6d092bdc92d2e09bbd653be361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 9 Nov 2023 10:32:14 +0200 Subject: [PATCH 117/133] Fix tests. --- .../providers.dev.net.spec.ts | 72 +++++-------------- 1 file changed, 16 insertions(+), 56 deletions(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 750d2c3e..35980d96 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -82,6 +82,7 @@ describe("test network providers on devnet: Proxy and API", function () { let apiResponse = (await apiProvider.getNonFungibleTokensOfAccount(dan)).slice(0, MAX_NUMBER_OF_ITEMS_BY_DEFAULT); let proxyResponse = (await proxyProvider.getNonFungibleTokensOfAccount(dan)).slice(0, MAX_NUMBER_OF_ITEMS_BY_DEFAULT); + assert.isTrue(apiResponse.length > 0, "For the sake of the test, there should be at least one item."); assert.equal(apiResponse.length, proxyResponse.length); for (let i = 0; i < apiResponse.length; i++) { @@ -169,8 +170,8 @@ describe("test network providers on devnet: Proxy and API", function () { this.timeout(20000); let hashes = [ - "2e6bd2671dbb57f1f1013c89f044359c2465f1514e0ea718583900e43c1931fe", - "c451566a6168e38d2980fcb83d4ea154f78d53f7abf3264dd51c2c7c585671aa" + "08acf8cbd71306a56eb58f9593cb2e23f109c94e27acdd906c82a5c3a5f84d9d", + "410efb1db2ab86678b8dbc503beb695b5b7d52754fb0de86c09cbb433de5f6a8" ]; for (const hash of hashes) { @@ -197,7 +198,7 @@ describe("test network providers on devnet: Proxy and API", function () { } it("should have the same response for transactions with events", async function () { - const hash = "c451566a6168e38d2980fcb83d4ea154f78d53f7abf3264dd51c2c7c585671aa"; + const hash = "1b04eb849cf87f2d3086c77b4b825d126437b88014327bbf01437476751cb040"; let apiResponse = await apiProvider.getTransaction(hash); let proxyResponse = await proxyProvider.getTransaction(hash); @@ -206,23 +207,22 @@ describe("test network providers on devnet: Proxy and API", function () { assert.exists(proxyResponse.logs); assert.exists(apiResponse.logs.events) assert.exists(proxyResponse.logs.events) - assert.equal(apiResponse.logs.events[0].topics[0].hex(), "5745474c442d643763366262") + assert.equal(apiResponse.logs.events[0].topics[0].hex(), "414c4943452d353632376631") assert.equal(apiResponse.logs.events[0].topics[1].hex(), "") - assert.equal(apiResponse.logs.events[0].topics[2].hex(), "0de0b6b3a7640000") - assert.equal(apiResponse.logs.events[0].topics[3].hex(), "00000000000000000500e01285f90311fb5925a9623a1dc62eee41fa8c869a0d") - assert.equal(proxyResponse.logs.events[0].topics[0].hex(), "5745474c442d643763366262") + assert.equal(apiResponse.logs.events[0].topics[2].hex(), "01") + assert.equal(apiResponse.logs.events[0].topics[3].hex(), "0000000000000000050032e141d21536e2dfc3d64b9e7dd0c2c53f201dc469e1") + assert.equal(proxyResponse.logs.events[0].topics[0].hex(), "414c4943452d353632376631") assert.equal(proxyResponse.logs.events[0].topics[1].hex(), "") - assert.equal(proxyResponse.logs.events[0].topics[2].hex(), "0de0b6b3a7640000") - assert.equal(proxyResponse.logs.events[0].topics[3].hex(), "00000000000000000500e01285f90311fb5925a9623a1dc62eee41fa8c869a0d") + assert.equal(proxyResponse.logs.events[0].topics[2].hex(), "01") + assert.equal(proxyResponse.logs.events[0].topics[3].hex(), "0000000000000000050032e141d21536e2dfc3d64b9e7dd0c2c53f201dc469e1") }); it("should have same response for getTransactionStatus()", async function () { this.timeout(20000); let hashes = [ - "2e6bd2671dbb57f1f1013c89f044359c2465f1514e0ea718583900e43c1931fe", - "c451566a6168e38d2980fcb83d4ea154f78d53f7abf3264dd51c2c7c585671aa", - "cd2da63a51fd422c8b69a1b5ebcb9edbbf0eb9750c3fe8e199d39ed5d82000e9" + "08acf8cbd71306a56eb58f9593cb2e23f109c94e27acdd906c82a5c3a5f84d9d", + "410efb1db2ab86678b8dbc503beb695b5b7d52754fb0de86c09cbb433de5f6a8" ]; for (const hash of hashes) { @@ -236,7 +236,7 @@ describe("test network providers on devnet: Proxy and API", function () { it("should have same response for getDefinitionOfFungibleToken()", async function () { this.timeout(10000); - let identifiers = ["FOO-b6f543", "BAR-c80d29", "COUNTER-b7401d"]; + let identifiers = ["BEER-b16c6d", "CHOCOLATE-daf625"]; for (const identifier of identifiers) { let apiResponse = await apiProvider.getDefinitionOfFungibleToken(identifier); @@ -253,7 +253,7 @@ describe("test network providers on devnet: Proxy and API", function () { it("should have same response for getDefinitionOfTokenCollection()", async function () { this.timeout(10000); - let collections = ["ERDJS-38f249"]; + let collections = ["TEST-37adcf"]; for (const collection of collections) { let apiResponse = await apiProvider.getDefinitionOfTokenCollection(collection); @@ -267,7 +267,7 @@ describe("test network providers on devnet: Proxy and API", function () { it("should have same response for getNonFungibleToken()", async function () { this.timeout(10000); - let tokens = [{ id: "ERDJS-38f249", nonce: 1 }]; + let tokens = [{ id: "TEST-37adcf", nonce: 1 }]; for (const token of tokens) { let apiResponse = await apiProvider.getNonFungibleToken(token.id, token.nonce); @@ -285,7 +285,7 @@ describe("test network providers on devnet: Proxy and API", function () { // Query: get sum (of adder contract) let query = new MockQuery({ - address: new Address("erd1qqqqqqqqqqqqqpgquykqja5c4v33zdmnwglj3jphqwrelzdn396qlc9g33"), + address: new Address("erd1qqqqqqqqqqqqqpgqfzydqmdw7m2vazsp6u5p95yxz76t2p9rd8ss0zp9ts"), func: "getSum" }); @@ -298,46 +298,6 @@ describe("test network providers on devnet: Proxy and API", function () { assert.deepEqual(apiResponse, proxyResponse); assert.deepEqual(apiResponse.getReturnDataParts(), proxyResponse.getReturnDataParts()); - - // Query: increment counter - query = new MockQuery({ - address: new Address("erd1qqqqqqqqqqqqqpgqzeq07xvhs5g7cg4ama85upaqarrcgu49396q0gz4yf"), - func: "increment", - args: [] - }); - - apiResponse = await apiProvider.queryContract(query); - proxyResponse = await proxyProvider.queryContract(query); - - // Ignore "gasUsed" due to numerical imprecision (API). - apiResponse.gasUsed = 0; - proxyResponse.gasUsed = 0; - - assert.deepEqual(apiResponse, proxyResponse); - assert.deepEqual(apiResponse.getReturnDataParts(), proxyResponse.getReturnDataParts()); - }); - - it.skip("should have same response for queryContract() (2)", async function () { - this.timeout(10000); - - // Query: issue ESDT - let query = new MockQuery({ - address: new Address("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"), - func: "issue", - value: "50000000000000000", - args: [ - Buffer.from("HELLO").toString("hex"), - Buffer.from("WORLD").toString("hex"), - "0A", // Supply - "03" // Decimals - ] - }); - - let apiResponse = await apiProvider.queryContract(query); - let proxyResponse = await proxyProvider.queryContract(query); - - assert.deepEqual(apiResponse, proxyResponse); - assert.deepEqual(apiResponse.getReturnDataParts(), proxyResponse.getReturnDataParts()); }); it("should handle events data on < Sirius and >= Sirius", async function () { From a0393e3bf8d7001950962cb483344668b2349b81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Tue, 9 Jan 2024 18:38:20 +0200 Subject: [PATCH 118/133] Fix integration test. --- .../providers.dev.net.spec.ts | 37 +++++-------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 35980d96..8ff2f6ea 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -300,39 +300,20 @@ describe("test network providers on devnet: Proxy and API", function () { assert.deepEqual(apiResponse.getReturnDataParts(), proxyResponse.getReturnDataParts()); }); - it("should handle events data on < Sirius and >= Sirius", async function () { + it("should handle events 'data' and 'additionalData'", async function () { this.timeout(50000); - const beforeSiriusApiProvider = new ApiNetworkProvider("https://devnet-api.multiversx.com"); - const beforeSiriusProxyProvider = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com"); + const apiResponse = await apiProvider.getTransaction("a419271407a2ec217739811805e3a751e30dbc72ae0777e3b4c825f036995184"); + const proxyResponse = await proxyProvider.getTransaction("a419271407a2ec217739811805e3a751e30dbc72ae0777e3b4c825f036995184"); - // We use the Testnet services, since they are backed by nodes with version >= Sirius (November 2023). - const afterSiriusApiProvider = new ApiNetworkProvider("https://testnet-api.multiversx.com"); - const afterSiriusProxyProvider = new ProxyNetworkProvider("https://testnet-gateway.multiversx.com"); + assert.equal(apiResponse.logs.events[0].data, Buffer.from("test").toString()); + assert.equal(proxyResponse.logs.events[0].data, Buffer.from("test").toString()); - const beforeSiriusApiResponse = await beforeSiriusApiProvider.getTransaction("51e53c6345c25fc4a454e64b96f43812e4a6cf3d01bbe4384da39e562b136aac"); - const beforeSiriusProxyResponse = await beforeSiriusProxyProvider.getTransaction("51e53c6345c25fc4a454e64b96f43812e4a6cf3d01bbe4384da39e562b136aac"); + assert.deepEqual(apiResponse.logs.events[0].dataPayload, TransactionEventData.fromBase64("dGVzdA==")); + assert.deepEqual(proxyResponse.logs.events[0].dataPayload, TransactionEventData.fromBase64("dGVzdA==")); - const afterSiriusApiResponse = await afterSiriusApiProvider.getTransaction("532087e5021c9ab8be8a4db5ad843cfe0610761f6334d9693b3765992fd05f67"); - // Contract result of "5320...5f67": - const afterSiriusProxyResponse = await afterSiriusProxyProvider.getTransaction("4bb22e85895b41bc3cd195079afa761cc4b430fb4ea19a6862f083de53f110ab"); - - // Before Sirius - assert.equal(beforeSiriusApiResponse.logs.events[0].data, "@6f7574206f662066756e6473"); - assert.equal(beforeSiriusProxyResponse.logs.events[0].data, "@6f7574206f662066756e6473"); - - assert.deepEqual(beforeSiriusApiResponse.logs.events[0].dataPayload, TransactionEventData.fromBase64("QDZmNzU3NDIwNmY2NjIwNjY3NTZlNjQ3Mw==")); - assert.deepEqual(beforeSiriusProxyResponse.logs.events[0].dataPayload, TransactionEventData.fromBase64("QDZmNzU3NDIwNmY2NjIwNjY3NTZlNjQ3Mw==")); - - // After Sirius - assert.equal(afterSiriusApiResponse.contractResults.items[0].logs.events[1].data, Buffer.from("AAAAAAAAA9sAAAA=", "base64").toString()); - assert.equal(afterSiriusProxyResponse.logs.events[1].data, Buffer.from("AAAAAAAAA9sAAAA=", "base64").toString()); - - assert.deepEqual(afterSiriusApiResponse.contractResults.items[0].logs.events[1].dataPayload, TransactionEventData.fromBase64("AAAAAAAAA9sAAAA=")); - assert.deepEqual(afterSiriusProxyResponse.logs.events[1].dataPayload, TransactionEventData.fromBase64("AAAAAAAAA9sAAAA=")); - - assert.deepEqual(afterSiriusApiResponse.contractResults.items[0].logs.events[1].additionalData, [TransactionEventData.fromBase64("AAAAAAAAA9sAAAA=")]); - assert.deepEqual(afterSiriusProxyResponse.logs.events[1].additionalData, [TransactionEventData.fromBase64("AAAAAAAAA9sAAAA=")]); + assert.deepEqual(apiResponse.logs.events[0].additionalData, [TransactionEventData.fromBase64("dGVzdA==")]); + assert.deepEqual(proxyResponse.logs.events[0].additionalData, [TransactionEventData.fromBase64("dGVzdA==")]); }); }); From bf426bb2892f53144a4ac91bd379e8904c071f85 Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Fri, 16 Feb 2024 17:09:09 +0200 Subject: [PATCH 119/133] add suport for TransactionNext --- src-network-providers/apiNetworkProvider.ts | 18 ++++--- src-network-providers/interface.ts | 20 +++++++- .../providers.dev.net.spec.ts | 50 ++++++++++++++++++- src-network-providers/proxyNetworkProvider.ts | 34 ++++++++++--- src-network-providers/transactions.ts | 22 +++++++- 5 files changed, 126 insertions(+), 18 deletions(-) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index eecea7e3..88ed0bbc 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -4,7 +4,7 @@ import { defaultAxiosConfig, defaultPagination } from "./config"; import { ContractQueryRequest } from "./contractQueryRequest"; import { ContractQueryResponse } from "./contractQueryResponse"; import { ErrContractQuery, ErrNetworkProvider } from "./errors"; -import { IAddress, IContractQuery, INetworkProvider, IPagination, ITransaction } from "./interface"; +import { IAddress, IContractQuery, INetworkProvider, IPagination, ITransaction, ITransactionNext } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; import { NetworkStake } from "./networkStake"; @@ -14,7 +14,7 @@ import { Nonce } from "./primitives"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; -import { TransactionOnNetwork } from "./transactions"; +import { TransactionOnNetwork, prepareTransactionNextForBroadcasting } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". @@ -119,16 +119,22 @@ export class ApiNetworkProvider implements INetworkProvider { return status; } - async sendTransaction(tx: ITransaction): Promise { - let response = await this.doPostGeneric("transactions", tx.toSendable()); + async sendTransaction(tx: ITransaction | ITransactionNext): Promise { + if ("toSendable" in tx){ + const response = await this.doPostGeneric("transactions", tx.toSendable()); + return response.txHash; + } + + const transaction = prepareTransactionNextForBroadcasting(tx); + const response = await this.doPostGeneric("transactions", transaction); return response.txHash; } - async sendTransactions(txs: ITransaction[]): Promise { + async sendTransactions(txs: ITransaction[] | ITransactionNext[]): Promise { return await this.backingProxyNetworkProvider.sendTransactions(txs); } - async simulateTransaction(tx: ITransaction): Promise { + async simulateTransaction(tx: ITransaction | ITransactionNext): Promise { return await this.backingProxyNetworkProvider.simulateTransaction(tx); } diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index fa15abf2..1d2d45fc 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -71,7 +71,7 @@ export interface INetworkProvider { /** * Broadcasts an already-signed transaction. */ - sendTransaction(tx: ITransaction): Promise; + sendTransaction(tx: ITransaction | ITransactionNext): Promise; /** * Broadcasts a list of already-signed transactions. @@ -133,3 +133,21 @@ export interface ITransaction { } export interface IAddress { bech32(): string; } + +export interface ITransactionNext { + sender: string; + receiver: string; + gasLimit: bigint; + chainID: string; + nonce: bigint; + value: bigint; + senderUsername: string; + receiverUsername: string; + gasPrice: bigint; + data: Uint8Array; + version: number; + options: number; + guardian: string; + signature: Uint8Array; + guardianSignature: Uint8Array; + } diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 8ff2f6ea..3b2242e6 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -1,6 +1,6 @@ import { assert } from "chai"; import { ApiNetworkProvider } from "./apiNetworkProvider"; -import { INetworkProvider } from "./interface"; +import { INetworkProvider, ITransactionNext } from "./interface"; import { Address } from "./primitives"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { MockQuery } from "./testscommon/dummyQuery"; @@ -315,5 +315,51 @@ describe("test network providers on devnet: Proxy and API", function () { assert.deepEqual(apiResponse.logs.events[0].additionalData, [TransactionEventData.fromBase64("dGVzdA==")]); assert.deepEqual(proxyResponse.logs.events[0].additionalData, [TransactionEventData.fromBase64("dGVzdA==")]); }); -}); + it.only("should send both `Transaction` and `TransactionNext`", async function () { + this.timeout(50000); + + const transaction = { + toSendable: function () { + return { + "nonce": 7, + "value": "0", + "receiver": "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + "sender": "erd1zztjf9fhwvuvquzsllknq4qcmffwad6n0hjtn5dyzytr5tgz7uas0mkgrq", + "gasPrice": 1000000000, + "gasLimit": 50000, + "chainID": "D", + "version": 2, + "signature": "149f1d8296efcb9489c5b3142ae659aacfa3a7daef3645f1d3747a96dc9cee377070dd8b83b322997c15ba3c305ac18daaee0fd25760eba334b14a9272b34802" + } + } + } + + const transactionNext: ITransactionNext = { + nonce: BigInt(8), + value: BigInt(0), + receiver: "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th", + sender: "erd1zztjf9fhwvuvquzsllknq4qcmffwad6n0hjtn5dyzytr5tgz7uas0mkgrq", + data: new Uint8Array(Buffer.from("test")), + gasPrice: BigInt(1000000000), + gasLimit: BigInt(80000), + chainID: "D", + version: 2, + signature: new Uint8Array(Buffer.from("3fa42d97b4f85442850340a11411a3cbd63885e06ff3f84c7a75d0ef59c780f7a18aa4f331cf460300bc8bd99352aea10b7c3bc17e40287337ae9f9842470205", "hex")), + senderUsername: "", + receiverUsername: "", + guardian: "", + guardianSignature: new Uint8Array(), + options: 0 + } + + const apiLegacyTxHash = await apiProvider.sendTransaction(transaction); + const apiTxNextHash = await apiProvider.sendTransaction(transactionNext); + + const proxyLegacyTxHash = await apiProvider.sendTransaction(transaction); + const proxyTxNextHash = await apiProvider.sendTransaction(transactionNext); + + assert.equal(apiLegacyTxHash, proxyLegacyTxHash); + assert.equal(apiTxNextHash, proxyTxNextHash); + }); +}); diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 995f7ac4..653ea4e6 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -5,14 +5,14 @@ import { EsdtContractAddress } from "./constants"; import { ContractQueryRequest } from "./contractQueryRequest"; import { ContractQueryResponse } from "./contractQueryResponse"; import { ErrContractQuery, ErrNetworkProvider } from "./errors"; -import { IAddress, IContractQuery, INetworkProvider, IPagination, ITransaction } from "./interface"; +import { IAddress, IContractQuery, INetworkProvider, IPagination, ITransaction, ITransactionNext } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; import { NetworkStake } from "./networkStake"; import { NetworkStatus } from "./networkStatus"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; -import { TransactionOnNetwork } from "./transactions"; +import { TransactionOnNetwork, prepareTransactionNextForBroadcasting } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". @@ -122,13 +122,25 @@ export class ProxyNetworkProvider implements INetworkProvider { return status; } - async sendTransaction(tx: ITransaction): Promise { - let response = await this.doPostGeneric("transaction/send", tx.toSendable()); + async sendTransaction(tx: ITransaction | ITransactionNext): Promise { + if ("toSendable" in tx){ + const response = await this.doPostGeneric("transactions", tx.toSendable()); + return response.txHash; + } + + const transaction = prepareTransactionNextForBroadcasting(tx); + const response = await this.doPostGeneric("transactions", transaction); return response.txHash; } - async sendTransactions(txs: ITransaction[]): Promise { - const data: any = txs.map(tx => tx.toSendable()); + async sendTransactions(txs: ITransaction[] | ITransactionNext[]): Promise { + let data: any[]; + if ("toSendable" in txs[0]){ + data = (txs as ITransaction[]).map(tx => tx.toSendable()); + } else { + data = (txs as ITransactionNext[]).map(tx => prepareTransactionNextForBroadcasting(tx)); + } + const response = await this.doPostGeneric("transaction/send-multiple", data); const hashes = Array(txs.length).fill(null); @@ -139,8 +151,14 @@ export class ProxyNetworkProvider implements INetworkProvider { return hashes; } - async simulateTransaction(tx: ITransaction): Promise { - let response = await this.doPostGeneric("transaction/simulate", tx.toSendable()); + async simulateTransaction(tx: ITransaction | ITransactionNext): Promise { + if ("toSendable" in tx){ + const response = await this.doPostGeneric("transaction/simulate", tx.toSendable()); + return response; + } + + const transaction = prepareTransactionNextForBroadcasting(tx); + const response = await this.doPostGeneric("transaction/simulate", transaction); return response; } diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index 18fcd1d4..941bb9d0 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -1,10 +1,30 @@ import { TransactionStatus } from "./transactionStatus"; import { ContractResults } from "./contractResults"; import { Address } from "./primitives"; -import { IAddress } from "./interface"; +import { IAddress, ITransactionNext } from "./interface"; import { TransactionLogs } from "./transactionLogs"; import { TransactionReceipt } from "./transactionReceipt"; +export function prepareTransactionNextForBroadcasting(transaction: ITransactionNext): any { + return { + nonce: Number(transaction.nonce), + value: transaction.value.toString(), + receiver: transaction.receiver, + sender: transaction.sender, + senderUsername: transaction.senderUsername ? Buffer.from(transaction.senderUsername).toString("base64") : undefined, + receiverUsername: transaction.receiverUsername ? Buffer.from(transaction.receiverUsername).toString("base64") : undefined, + gasPrice: Number(transaction.gasPrice), + gasLimit: Number(transaction.gasLimit), + data: transaction.data.length === 0 ? undefined : Buffer.from(transaction.data).toString("base64"), + chainID: transaction.chainID, + version: transaction.version, + options: transaction.options, + guardian: transaction.guardian || undefined, + signature: Buffer.from(transaction.signature).toString("hex"), + guardianSignature: transaction.guardianSignature.length === 0 ? undefined : Buffer.from(transaction.guardianSignature).toString("hex"), + } +} + export class TransactionOnNetwork { isCompleted?: boolean; hash: string = ""; From ab6f64a1d9ac0f06ddbd6b3b897ae2880d290cac Mon Sep 17 00:00:00 2001 From: Alexandru Popenta Date: Mon, 19 Feb 2024 13:32:38 +0200 Subject: [PATCH 120/133] fixes after review --- src-network-providers/apiNetworkProvider.ts | 11 +++----- src-network-providers/errors.ts | 1 - src-network-providers/interface.ts | 2 +- .../providers.dev.net.spec.ts | 8 +++--- src-network-providers/proxyNetworkProvider.ts | 27 +++++-------------- src-network-providers/transactions.ts | 8 ++++-- 6 files changed, 20 insertions(+), 37 deletions(-) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 88ed0bbc..086980c4 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -14,7 +14,7 @@ import { Nonce } from "./primitives"; import { ProxyNetworkProvider } from "./proxyNetworkProvider"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; -import { TransactionOnNetwork, prepareTransactionNextForBroadcasting } from "./transactions"; +import { TransactionOnNetwork, prepareTransactionForBroadcasting } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". @@ -120,17 +120,12 @@ export class ApiNetworkProvider implements INetworkProvider { } async sendTransaction(tx: ITransaction | ITransactionNext): Promise { - if ("toSendable" in tx){ - const response = await this.doPostGeneric("transactions", tx.toSendable()); - return response.txHash; - } - - const transaction = prepareTransactionNextForBroadcasting(tx); + const transaction = prepareTransactionForBroadcasting(tx); const response = await this.doPostGeneric("transactions", transaction); return response.txHash; } - async sendTransactions(txs: ITransaction[] | ITransactionNext[]): Promise { + async sendTransactions(txs: (ITransaction | ITransactionNext)[]): Promise { return await this.backingProxyNetworkProvider.sendTransactions(txs); } diff --git a/src-network-providers/errors.ts b/src-network-providers/errors.ts index 73882ecd..6b297bfd 100644 --- a/src-network-providers/errors.ts +++ b/src-network-providers/errors.ts @@ -29,7 +29,6 @@ export class ErrNetworkProvider extends Err { } } - /** * Signals a generic error in the context of querying Smart Contracts. */ diff --git a/src-network-providers/interface.ts b/src-network-providers/interface.ts index 1d2d45fc..144f0583 100644 --- a/src-network-providers/interface.ts +++ b/src-network-providers/interface.ts @@ -76,7 +76,7 @@ export interface INetworkProvider { /** * Broadcasts a list of already-signed transactions. */ - sendTransactions(txs: ITransaction[]): Promise; + sendTransactions(txs: (ITransaction | ITransactionNext)[]): Promise; /** * Simulates the processing of an already-signed transaction. diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 3b2242e6..690b8074 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -316,7 +316,7 @@ describe("test network providers on devnet: Proxy and API", function () { assert.deepEqual(proxyResponse.logs.events[0].additionalData, [TransactionEventData.fromBase64("dGVzdA==")]); }); - it.only("should send both `Transaction` and `TransactionNext`", async function () { + it("should send both `Transaction` and `TransactionNext`", async function () { this.timeout(50000); const transaction = { @@ -345,7 +345,7 @@ describe("test network providers on devnet: Proxy and API", function () { gasLimit: BigInt(80000), chainID: "D", version: 2, - signature: new Uint8Array(Buffer.from("3fa42d97b4f85442850340a11411a3cbd63885e06ff3f84c7a75d0ef59c780f7a18aa4f331cf460300bc8bd99352aea10b7c3bc17e40287337ae9f9842470205", "hex")), + signature: Buffer.from("3fa42d97b4f85442850340a11411a3cbd63885e06ff3f84c7a75d0ef59c780f7a18aa4f331cf460300bc8bd99352aea10b7c3bc17e40287337ae9f9842470205", "hex"), senderUsername: "", receiverUsername: "", guardian: "", @@ -356,8 +356,8 @@ describe("test network providers on devnet: Proxy and API", function () { const apiLegacyTxHash = await apiProvider.sendTransaction(transaction); const apiTxNextHash = await apiProvider.sendTransaction(transactionNext); - const proxyLegacyTxHash = await apiProvider.sendTransaction(transaction); - const proxyTxNextHash = await apiProvider.sendTransaction(transactionNext); + const proxyLegacyTxHash = await proxyProvider.sendTransaction(transaction); + const proxyTxNextHash = await proxyProvider.sendTransaction(transactionNext); assert.equal(apiLegacyTxHash, proxyLegacyTxHash); assert.equal(apiTxNextHash, proxyTxNextHash); diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 653ea4e6..a3d8d2d1 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -12,7 +12,7 @@ import { NetworkStake } from "./networkStake"; import { NetworkStatus } from "./networkStatus"; import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; -import { TransactionOnNetwork, prepareTransactionNextForBroadcasting } from "./transactions"; +import { TransactionOnNetwork, prepareTransactionForBroadcasting } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". @@ -123,23 +123,13 @@ export class ProxyNetworkProvider implements INetworkProvider { } async sendTransaction(tx: ITransaction | ITransactionNext): Promise { - if ("toSendable" in tx){ - const response = await this.doPostGeneric("transactions", tx.toSendable()); - return response.txHash; - } - - const transaction = prepareTransactionNextForBroadcasting(tx); - const response = await this.doPostGeneric("transactions", transaction); + const transaction = prepareTransactionForBroadcasting(tx); + const response = await this.doPostGeneric("transaction/send", transaction); return response.txHash; } - async sendTransactions(txs: ITransaction[] | ITransactionNext[]): Promise { - let data: any[]; - if ("toSendable" in txs[0]){ - data = (txs as ITransaction[]).map(tx => tx.toSendable()); - } else { - data = (txs as ITransactionNext[]).map(tx => prepareTransactionNextForBroadcasting(tx)); - } + async sendTransactions(txs: (ITransaction | ITransactionNext)[]): Promise { + const data = (txs).map((tx) => prepareTransactionForBroadcasting(tx)); const response = await this.doPostGeneric("transaction/send-multiple", data); const hashes = Array(txs.length).fill(null); @@ -152,12 +142,7 @@ export class ProxyNetworkProvider implements INetworkProvider { } async simulateTransaction(tx: ITransaction | ITransactionNext): Promise { - if ("toSendable" in tx){ - const response = await this.doPostGeneric("transaction/simulate", tx.toSendable()); - return response; - } - - const transaction = prepareTransactionNextForBroadcasting(tx); + const transaction = prepareTransactionForBroadcasting(tx); const response = await this.doPostGeneric("transaction/simulate", transaction); return response; } diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index 941bb9d0..0db59e8f 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -1,11 +1,15 @@ import { TransactionStatus } from "./transactionStatus"; import { ContractResults } from "./contractResults"; import { Address } from "./primitives"; -import { IAddress, ITransactionNext } from "./interface"; +import { IAddress, ITransaction, ITransactionNext } from "./interface"; import { TransactionLogs } from "./transactionLogs"; import { TransactionReceipt } from "./transactionReceipt"; -export function prepareTransactionNextForBroadcasting(transaction: ITransactionNext): any { +export function prepareTransactionForBroadcasting(transaction: ITransaction | ITransactionNext): any { + if ("toSendable" in transaction){ + return transaction.toSendable(); + } + return { nonce: Number(transaction.nonce), value: transaction.value.toString(), From fc9cd7e3ed09b16bccc07547a9ddbc06442a31c5 Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Thu, 14 Mar 2024 17:50:15 +0200 Subject: [PATCH 121/133] Add TransactionOnNetwork.function. --- src-network-providers/transactions.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src-network-providers/transactions.ts b/src-network-providers/transactions.ts index 0db59e8f..beaecc0a 100644 --- a/src-network-providers/transactions.ts +++ b/src-network-providers/transactions.ts @@ -41,6 +41,7 @@ export class TransactionOnNetwork { sender: IAddress = new Address(""); gasLimit: number = 0; gasPrice: number = 0; + function: string = ""; data: Buffer = Buffer.from([]); signature: string = ""; status: TransactionStatus = TransactionStatus.createUnknown(); @@ -90,6 +91,7 @@ export class TransactionOnNetwork { result.receiver = new Address(response.receiver); result.gasPrice = response.gasPrice || 0; result.gasLimit = response.gasLimit || 0; + result.function = response.function || ""; result.data = Buffer.from(response.data || "", "base64"); result.status = new TransactionStatus(response.status); result.timestamp = response.timestamp || 0; From da9293537436abf5f903cdedb19c85d9a3bf133d Mon Sep 17 00:00:00 2001 From: Andrei Bancioiu Date: Wed, 20 Mar 2024 22:52:43 +0200 Subject: [PATCH 122/133] Ignore some differences. --- src-network-providers/providers.dev.net.spec.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 690b8074..e6ad6155 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -178,7 +178,7 @@ describe("test network providers on devnet: Proxy and API", function () { let apiResponse = await apiProvider.getTransaction(hash); let proxyResponse = await proxyProvider.getTransaction(hash, true); - ignoreKnownTransactionDifferencesBetweenProviders(proxyResponse); + ignoreKnownTransactionDifferencesBetweenProviders(apiResponse, proxyResponse); assert.deepEqual(apiResponse, proxyResponse, `transaction: ${hash}`); // Also assert completion @@ -188,7 +188,10 @@ describe("test network providers on devnet: Proxy and API", function () { }); // TODO: Strive to have as little differences as possible between Proxy and API. - function ignoreKnownTransactionDifferencesBetweenProviders(proxyResponse: TransactionOnNetwork) { + function ignoreKnownTransactionDifferencesBetweenProviders(apiResponse: TransactionOnNetwork, proxyResponse: TransactionOnNetwork) { + // Proxy and API exhibit differences in the "function" field, in case of move-balance transactions. + apiResponse.function = proxyResponse.function + // Ignore fields which are not present on API response: proxyResponse.type = ""; proxyResponse.epoch = 0; From 445bd03716e6eb2876b4a9f1ccb4a5a733120abb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Fri, 22 Mar 2024 14:22:55 +0200 Subject: [PATCH 123/133] Export "TransactionEventData". --- src-network-providers/index.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src-network-providers/index.ts b/src-network-providers/index.ts index 5f578c85..804b15b6 100644 --- a/src-network-providers/index.ts +++ b/src-network-providers/index.ts @@ -1,19 +1,20 @@ -export { ProxyNetworkProvider } from "./proxyNetworkProvider"; export { ApiNetworkProvider } from "./apiNetworkProvider"; +export { ProxyNetworkProvider } from "./proxyNetworkProvider"; export { AccountOnNetwork } from "./accounts"; -export { TransactionOnNetwork } from "./transactions"; -export { TransactionEvent, TransactionEventTopic } from "./transactionEvents"; +export { ContractQueryResponse } from "./contractQueryResponse"; +export { ContractResultItem, ContractResults } from "./contractResults"; +export { TransactionEvent, TransactionEventData, TransactionEventTopic } from "./transactionEvents"; export { TransactionLogs } from "./transactionLogs"; export { TransactionReceipt } from "./transactionReceipt"; export { TransactionStatus } from "./transactionStatus"; -export { ContractQueryResponse } from "./contractQueryResponse"; -export { ContractResults, ContractResultItem } from "./contractResults"; +export { TransactionOnNetwork } from "./transactions"; -export { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; export { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwork } from "./tokenDefinitions"; +export { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; export { NetworkConfig } from "./networkConfig"; export { NetworkGeneralStatistics } from "./networkGeneralStatistics"; export { NetworkStake } from "./networkStake"; export { NetworkStatus } from "./networkStatus"; + From e08524ed4b501a88b1d0ae347997e473cc605c9d Mon Sep 17 00:00:00 2001 From: danielailie Date: Wed, 31 Jul 2024 14:44:39 +0300 Subject: [PATCH 124/133] Fix tests and update dependency --- .../providers.dev.net.spec.ts | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index e6ad6155..c277159f 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -193,7 +193,6 @@ describe("test network providers on devnet: Proxy and API", function () { apiResponse.function = proxyResponse.function // Ignore fields which are not present on API response: - proxyResponse.type = ""; proxyResponse.epoch = 0; proxyResponse.blockNonce = 0; proxyResponse.hyperblockNonce = 0; @@ -236,21 +235,18 @@ describe("test network providers on devnet: Proxy and API", function () { } }); - it("should have same response for getDefinitionOfFungibleToken()", async function () { + it.only("should have same response for getDefinitionOfFungibleToken()", async function () { this.timeout(10000); - let identifiers = ["BEER-b16c6d", "CHOCOLATE-daf625"]; - - for (const identifier of identifiers) { - let apiResponse = await apiProvider.getDefinitionOfFungibleToken(identifier); - let proxyResponse = await proxyProvider.getDefinitionOfFungibleToken(identifier); + let identifier = "CHOCOLATE-daf625"; + let apiResponse = await apiProvider.getDefinitionOfFungibleToken(identifier); + let proxyResponse = await proxyProvider.getDefinitionOfFungibleToken(identifier); + // Assets are only present on API responses, thus we ignore them for comparison. + apiResponse.assets = {}; - // Assets are only present on API responses, thus we ignore them for comparison. - apiResponse.assets = {}; + assert.equal(apiResponse.identifier, identifier); + assert.deepEqual(apiResponse, proxyResponse); - assert.equal(apiResponse.identifier, identifier); - assert.deepEqual(apiResponse, proxyResponse); - } }); it("should have same response for getDefinitionOfTokenCollection()", async function () { From 6a09e666b724ddccf784aff58951b8b80a9fdedb Mon Sep 17 00:00:00 2001 From: danielailie Date: Wed, 31 Jul 2024 14:45:29 +0300 Subject: [PATCH 125/133] Add empty line --- src-network-providers/providers.dev.net.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index c277159f..579ac9c1 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -239,8 +239,10 @@ describe("test network providers on devnet: Proxy and API", function () { this.timeout(10000); let identifier = "CHOCOLATE-daf625"; + let apiResponse = await apiProvider.getDefinitionOfFungibleToken(identifier); let proxyResponse = await proxyProvider.getDefinitionOfFungibleToken(identifier); + // Assets are only present on API responses, thus we ignore them for comparison. apiResponse.assets = {}; From 4ccd63b47ebe3616a3862ff624334fd04564c3ab Mon Sep 17 00:00:00 2001 From: danielailie Date: Wed, 31 Jul 2024 14:50:04 +0300 Subject: [PATCH 126/133] remove only from tests --- src-network-providers/providers.dev.net.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 579ac9c1..f4f4399a 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -235,7 +235,7 @@ describe("test network providers on devnet: Proxy and API", function () { } }); - it.only("should have same response for getDefinitionOfFungibleToken()", async function () { + it("should have same response for getDefinitionOfFungibleToken()", async function () { this.timeout(10000); let identifier = "CHOCOLATE-daf625"; From 3c06d22703586a9072633efc45aa7bd05137946e Mon Sep 17 00:00:00 2001 From: danielailie Date: Mon, 26 Aug 2024 17:48:25 +0300 Subject: [PATCH 127/133] Add user agent info --- src-network-providers/apiNetworkProvider.ts | 19 +++++++++++++++++-- src-network-providers/proxyNetworkProvider.ts | 18 ++++++++++++++++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 086980c4..42c5a7fc 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -1,4 +1,4 @@ -import axios, { AxiosRequestConfig } from "axios"; +import axios, { AxiosHeaders, AxiosRequestConfig } from "axios"; import { AccountOnNetwork, GuardianData } from "./accounts"; import { defaultAxiosConfig, defaultPagination } from "./config"; import { ContractQueryRequest } from "./contractQueryRequest"; @@ -22,11 +22,26 @@ export class ApiNetworkProvider implements INetworkProvider { private url: string; private config: AxiosRequestConfig; private backingProxyNetworkProvider; + private userAgentPrefix = 'sdk-network-providers/api' - constructor(url: string, config?: AxiosRequestConfig) { + constructor(url: string, config?: AxiosRequestConfig, clientName?: string) { this.url = url; this.config = { ...defaultAxiosConfig, ...config }; this.backingProxyNetworkProvider = new ProxyNetworkProvider(url, config); + this.setUserAgent(config, clientName); + + } + + private setUserAgent(config: AxiosRequestConfig | undefined, clientName: string | undefined) { + if (!config?.headers) return; + + const headers = AxiosHeaders.from(config.headers as AxiosHeaders).normalize(true); + const resolvedClientName = clientName || 'unknown'; + + const currentUserAgent = headers.hasUserAgent() ? headers.getUserAgent() : ''; + const newUserAgent = `${currentUserAgent} ${this.userAgentPrefix}${resolvedClientName}`.trim(); + + headers.setUserAgent(newUserAgent, true); } async getNetworkConfig(): Promise { diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index a3d8d2d1..68d17459 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -1,4 +1,4 @@ -import axios, { AxiosRequestConfig } from "axios"; +import axios, { AxiosHeaders, AxiosRequestConfig } from "axios"; import { AccountOnNetwork, GuardianData } from "./accounts"; import { defaultAxiosConfig } from "./config"; import { EsdtContractAddress } from "./constants"; @@ -19,10 +19,24 @@ import { TransactionStatus } from "./transactionStatus"; export class ProxyNetworkProvider implements INetworkProvider { private url: string; private config: AxiosRequestConfig; + private userAgentPrefix = 'sdk-network-providers/proxy' - constructor(url: string, config?: AxiosRequestConfig) { + constructor(url: string, config?: AxiosRequestConfig, clientName?: string) { this.url = url; this.config = { ...defaultAxiosConfig, ...config }; + this.setUserAgent(config, clientName); + } + + private setUserAgent(config: AxiosRequestConfig | undefined, clientName: string | undefined) { + if (!config?.headers) return; + + const headers = AxiosHeaders.from(config.headers as AxiosHeaders).normalize(true); + const resolvedClientName = clientName || 'unknown'; + + const currentUserAgent = headers.hasUserAgent() ? headers.getUserAgent() : ''; + const newUserAgent = `${currentUserAgent} ${this.userAgentPrefix}${resolvedClientName}`.trim(); + + headers.setUserAgent(newUserAgent, true); } async getNetworkConfig(): Promise { From a52a34b636ba43f842f732a2965bab780b2165ba Mon Sep 17 00:00:00 2001 From: danielailie Date: Tue, 27 Aug 2024 12:24:44 +0300 Subject: [PATCH 128/133] Extract duplicated code and extend config --- .../NetworkProviderConfig.ts | 5 ++++ src-network-providers/apiNetworkProvider.ts | 23 +++++-------------- src-network-providers/proxyNetworkProvider.ts | 22 +++++------------- src-network-providers/userAgent.ts | 22 ++++++++++++++++++ 4 files changed, 39 insertions(+), 33 deletions(-) create mode 100644 src-network-providers/NetworkProviderConfig.ts create mode 100644 src-network-providers/userAgent.ts diff --git a/src-network-providers/NetworkProviderConfig.ts b/src-network-providers/NetworkProviderConfig.ts new file mode 100644 index 00000000..ea68c235 --- /dev/null +++ b/src-network-providers/NetworkProviderConfig.ts @@ -0,0 +1,5 @@ +import { AxiosRequestConfig } from 'axios'; + +export interface ExtendedAxiosRequestConfig extends AxiosRequestConfig { + clientName?: string; +} diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 42c5a7fc..6bdfb13e 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -1,4 +1,4 @@ -import axios, { AxiosHeaders, AxiosRequestConfig } from "axios"; +import axios from "axios"; import { AccountOnNetwork, GuardianData } from "./accounts"; import { defaultAxiosConfig, defaultPagination } from "./config"; import { ContractQueryRequest } from "./contractQueryRequest"; @@ -16,32 +16,21 @@ import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwor import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork, prepareTransactionForBroadcasting } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; +import { setUserAgent } from "./userAgent"; +import { ExtendedAxiosRequestConfig } from "./NetworkProviderConfig"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ApiNetworkProvider implements INetworkProvider { private url: string; - private config: AxiosRequestConfig; + private config: ExtendedAxiosRequestConfig; private backingProxyNetworkProvider; private userAgentPrefix = 'sdk-network-providers/api' - constructor(url: string, config?: AxiosRequestConfig, clientName?: string) { + constructor(url: string, config?: ExtendedAxiosRequestConfig) { this.url = url; this.config = { ...defaultAxiosConfig, ...config }; this.backingProxyNetworkProvider = new ProxyNetworkProvider(url, config); - this.setUserAgent(config, clientName); - - } - - private setUserAgent(config: AxiosRequestConfig | undefined, clientName: string | undefined) { - if (!config?.headers) return; - - const headers = AxiosHeaders.from(config.headers as AxiosHeaders).normalize(true); - const resolvedClientName = clientName || 'unknown'; - - const currentUserAgent = headers.hasUserAgent() ? headers.getUserAgent() : ''; - const newUserAgent = `${currentUserAgent} ${this.userAgentPrefix}${resolvedClientName}`.trim(); - - headers.setUserAgent(newUserAgent, true); + setUserAgent(this.userAgentPrefix, this.config); } async getNetworkConfig(): Promise { diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 68d17459..3b960f12 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -1,4 +1,4 @@ -import axios, { AxiosHeaders, AxiosRequestConfig } from "axios"; +import axios from "axios"; import { AccountOnNetwork, GuardianData } from "./accounts"; import { defaultAxiosConfig } from "./config"; import { EsdtContractAddress } from "./constants"; @@ -14,29 +14,19 @@ import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwor import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork, prepareTransactionForBroadcasting } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; +import { setUserAgent } from "./userAgent"; +import { ExtendedAxiosRequestConfig } from "./NetworkProviderConfig"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ProxyNetworkProvider implements INetworkProvider { private url: string; - private config: AxiosRequestConfig; + private config: ExtendedAxiosRequestConfig; private userAgentPrefix = 'sdk-network-providers/proxy' - constructor(url: string, config?: AxiosRequestConfig, clientName?: string) { + constructor(url: string, config?: ExtendedAxiosRequestConfig) { this.url = url; this.config = { ...defaultAxiosConfig, ...config }; - this.setUserAgent(config, clientName); - } - - private setUserAgent(config: AxiosRequestConfig | undefined, clientName: string | undefined) { - if (!config?.headers) return; - - const headers = AxiosHeaders.from(config.headers as AxiosHeaders).normalize(true); - const resolvedClientName = clientName || 'unknown'; - - const currentUserAgent = headers.hasUserAgent() ? headers.getUserAgent() : ''; - const newUserAgent = `${currentUserAgent} ${this.userAgentPrefix}${resolvedClientName}`.trim(); - - headers.setUserAgent(newUserAgent, true); + setUserAgent(this.userAgentPrefix, this.config); } async getNetworkConfig(): Promise { diff --git a/src-network-providers/userAgent.ts b/src-network-providers/userAgent.ts new file mode 100644 index 00000000..72722654 --- /dev/null +++ b/src-network-providers/userAgent.ts @@ -0,0 +1,22 @@ +import { AxiosHeaders } from "axios"; +import { ExtendedAxiosRequestConfig } from "./NetworkProviderConfig"; + +export function setUserAgent(userAgentPrefix: string, config: ExtendedAxiosRequestConfig | undefined) { + if (!config) { + config = { headers: new AxiosHeaders({}) } + } + if (!config.headers) { + config.headers = new AxiosHeaders({}) + }; + + const headers = AxiosHeaders.from(config.headers as AxiosHeaders).normalize(true); + if (!config.clientName) { + console.log("Can you please provide the client name of the aplication that uses the sdk?") + } + const resolvedClientName = config.clientName || 'unknown'; + + const currentUserAgent = headers.hasUserAgent() ? headers.getUserAgent() : ''; + const newUserAgent = `${currentUserAgent} ${userAgentPrefix}${resolvedClientName}`.trim(); + + headers.setUserAgent(newUserAgent, true); +} From 1a18343b276ce91f5e9808ff1e716d5c27c4b19a Mon Sep 17 00:00:00 2001 From: danielailie Date: Tue, 27 Aug 2024 14:49:54 +0300 Subject: [PATCH 129/133] refactoring, fix typos, remaning --- src-network-providers/NetworkProviderConfig.ts | 5 ----- src-network-providers/apiNetworkProvider.ts | 13 +++++++------ src-network-providers/constants.ts | 2 ++ src-network-providers/networkProviderConfig.ts | 5 +++++ src-network-providers/proxyNetworkProvider.ts | 14 +++++++------- src-network-providers/userAgent.ts | 18 ++++++++---------- 6 files changed, 29 insertions(+), 28 deletions(-) delete mode 100644 src-network-providers/NetworkProviderConfig.ts create mode 100644 src-network-providers/networkProviderConfig.ts diff --git a/src-network-providers/NetworkProviderConfig.ts b/src-network-providers/NetworkProviderConfig.ts deleted file mode 100644 index ea68c235..00000000 --- a/src-network-providers/NetworkProviderConfig.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { AxiosRequestConfig } from 'axios'; - -export interface ExtendedAxiosRequestConfig extends AxiosRequestConfig { - clientName?: string; -} diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 6bdfb13e..069d576b 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -16,21 +16,22 @@ import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwor import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork, prepareTransactionForBroadcasting } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; -import { setUserAgent } from "./userAgent"; -import { ExtendedAxiosRequestConfig } from "./NetworkProviderConfig"; +import { extendUserAgent } from "./userAgent"; +import { NetworkProviderConfig } from "./networkProviderConfig"; +import { MetricsPrefix } from "./constants"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ApiNetworkProvider implements INetworkProvider { private url: string; - private config: ExtendedAxiosRequestConfig; + private config: NetworkProviderConfig; private backingProxyNetworkProvider; - private userAgentPrefix = 'sdk-network-providers/api' + private userAgentPrefix = `${MetricsPrefix}/api` - constructor(url: string, config?: ExtendedAxiosRequestConfig) { + constructor(url: string, config?: NetworkProviderConfig) { this.url = url; this.config = { ...defaultAxiosConfig, ...config }; this.backingProxyNetworkProvider = new ProxyNetworkProvider(url, config); - setUserAgent(this.userAgentPrefix, this.config); + extendUserAgent(this.userAgentPrefix, this.config); } async getNetworkConfig(): Promise { diff --git a/src-network-providers/constants.ts b/src-network-providers/constants.ts index 932f9595..5218a901 100644 --- a/src-network-providers/constants.ts +++ b/src-network-providers/constants.ts @@ -3,3 +3,5 @@ import { Address } from "./primitives"; export const MaxUint64AsBigNumber = new BigNumber("18446744073709551615"); export const EsdtContractAddress = new Address("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"); +export const MetricsPrefix = "multiversx-sdk" +export const UnknownClientName = "unknown" diff --git a/src-network-providers/networkProviderConfig.ts b/src-network-providers/networkProviderConfig.ts new file mode 100644 index 00000000..b66bffbc --- /dev/null +++ b/src-network-providers/networkProviderConfig.ts @@ -0,0 +1,5 @@ +import { AxiosRequestConfig } from 'axios'; + +export interface NetworkProviderConfig extends AxiosRequestConfig { + clientName?: string; +} diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 3b960f12..6bc2e2b5 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -1,7 +1,7 @@ import axios from "axios"; import { AccountOnNetwork, GuardianData } from "./accounts"; import { defaultAxiosConfig } from "./config"; -import { EsdtContractAddress } from "./constants"; +import { EsdtContractAddress, MetricsPrefix } from "./constants"; import { ContractQueryRequest } from "./contractQueryRequest"; import { ContractQueryResponse } from "./contractQueryResponse"; import { ErrContractQuery, ErrNetworkProvider } from "./errors"; @@ -14,19 +14,19 @@ import { DefinitionOfFungibleTokenOnNetwork, DefinitionOfTokenCollectionOnNetwor import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionOnNetwork, prepareTransactionForBroadcasting } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; -import { setUserAgent } from "./userAgent"; -import { ExtendedAxiosRequestConfig } from "./NetworkProviderConfig"; +import { extendUserAgent } from "./userAgent"; +import { NetworkProviderConfig } from "./networkProviderConfig"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ProxyNetworkProvider implements INetworkProvider { private url: string; - private config: ExtendedAxiosRequestConfig; - private userAgentPrefix = 'sdk-network-providers/proxy' + private config: NetworkProviderConfig; + private userAgentPrefix = `${MetricsPrefix}/proxy` - constructor(url: string, config?: ExtendedAxiosRequestConfig) { + constructor(url: string, config?: NetworkProviderConfig) { this.url = url; this.config = { ...defaultAxiosConfig, ...config }; - setUserAgent(this.userAgentPrefix, this.config); + extendUserAgent(this.userAgentPrefix, this.config); } async getNetworkConfig(): Promise { diff --git a/src-network-providers/userAgent.ts b/src-network-providers/userAgent.ts index 72722654..726ee23e 100644 --- a/src-network-providers/userAgent.ts +++ b/src-network-providers/userAgent.ts @@ -1,22 +1,20 @@ import { AxiosHeaders } from "axios"; -import { ExtendedAxiosRequestConfig } from "./NetworkProviderConfig"; +import { NetworkProviderConfig } from "./networkProviderConfig"; +import { UnknownClientName } from "./constants"; -export function setUserAgent(userAgentPrefix: string, config: ExtendedAxiosRequestConfig | undefined) { - if (!config) { - config = { headers: new AxiosHeaders({}) } - } +export function extendUserAgent(userAgentPrefix: string, config: NetworkProviderConfig) { if (!config.headers) { config.headers = new AxiosHeaders({}) }; - - const headers = AxiosHeaders.from(config.headers as AxiosHeaders).normalize(true); if (!config.clientName) { - console.log("Can you please provide the client name of the aplication that uses the sdk?") + console.log("Can you please provide the client name of the application that uses the SDK? It will be used for metrics.") } - const resolvedClientName = config.clientName || 'unknown'; + + const headers = AxiosHeaders.from(config.headers as AxiosHeaders).normalize(true); + const resolvedClientName = config.clientName || UnknownClientName; const currentUserAgent = headers.hasUserAgent() ? headers.getUserAgent() : ''; - const newUserAgent = `${currentUserAgent} ${userAgentPrefix}${resolvedClientName}`.trim(); + const newUserAgent = `${currentUserAgent} ${userAgentPrefix}/${resolvedClientName}`; headers.setUserAgent(newUserAgent, true); } From 25d250a119635db027c1733ecb3529c1ba2d4850 Mon Sep 17 00:00:00 2001 From: danielailie Date: Tue, 27 Aug 2024 16:08:47 +0300 Subject: [PATCH 130/133] Add tests --- src-network-providers/apiNetworkProvider.ts | 3 +- .../providers.dev.net.spec.ts | 40 +++++++++++++++++-- src-network-providers/userAgent.ts | 3 +- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 069d576b..53ea6b01 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -30,7 +30,8 @@ export class ApiNetworkProvider implements INetworkProvider { constructor(url: string, config?: NetworkProviderConfig) { this.url = url; this.config = { ...defaultAxiosConfig, ...config }; - this.backingProxyNetworkProvider = new ProxyNetworkProvider(url, config); + const proxyConfig = JSON.parse(JSON.stringify(this.config)); + this.backingProxyNetworkProvider = new ProxyNetworkProvider(url, proxyConfig); extendUserAgent(this.userAgentPrefix, this.config); } diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index f4f4399a..890c0e55 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -1,4 +1,4 @@ -import { assert } from "chai"; +import { assert, expect } from "chai"; import { ApiNetworkProvider } from "./apiNetworkProvider"; import { INetworkProvider, ITransactionNext } from "./interface"; import { Address } from "./primitives"; @@ -7,6 +7,7 @@ import { MockQuery } from "./testscommon/dummyQuery"; import { NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionEventData } from "./transactionEvents"; import { TransactionOnNetwork } from "./transactions"; +import { AxiosHeaders } from "axios"; describe("test network providers on devnet: Proxy and API", function () { let alice = new Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); @@ -14,8 +15,8 @@ describe("test network providers on devnet: Proxy and API", function () { let dan = new Address("erd1kyaqzaprcdnv4luvanah0gfxzzsnpaygsy6pytrexll2urtd05ts9vegu7"); const MAX_NUMBER_OF_ITEMS_BY_DEFAULT = 20; - let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.multiversx.com", { timeout: 10000 }); - let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { timeout: 10000 }); + let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.multiversx.com", { timeout: 10000, clientName: 'test' }); + let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { timeout: 10000, clientName: 'test' }); it("should have same response for getNetworkConfig()", async function () { let apiResponse = await apiProvider.getNetworkConfig(); @@ -24,6 +25,39 @@ describe("test network providers on devnet: Proxy and API", function () { assert.deepEqual(apiResponse, proxyResponse); }); + it("should add userAgent unknown for clientName when no clientName passed", async function () { + const expectedApiUserAgent = "multiversx-sdk/api/unknown" + const expectedProxyUserAgent = "multiversx-sdk/proxy/unknown" + + let localApiProvider: any = new ApiNetworkProvider("https://devnet-api.multiversx.com", { timeout: 10000 }); + let localProxyProvider: any = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { timeout: 10000 }); + + assert.equal(localApiProvider.config.headers.getUserAgent(), expectedApiUserAgent); + assert.equal(localProxyProvider.config.headers.getUserAgent(), expectedProxyUserAgent); + }); + + it("should set userAgent with specified clientName ", async function () { + const expectedApiUserAgent = "multiversx-sdk/api/test" + const expectedProxyUserAgent = "multiversx-sdk/proxy/test" + + let localApiProvider: any = new ApiNetworkProvider("https://devnet-api.multiversx.com", { timeout: 10000, clientName: 'test' }); + let localProxyProvider: any = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { timeout: 10000, clientName: 'test' }); + + assert.equal(localApiProvider.config.headers.getUserAgent(), expectedApiUserAgent); + assert.equal(localProxyProvider.config.headers.getUserAgent(), expectedProxyUserAgent); + }); + + it("should keep the set userAgent and add the sdk to it", async function () { + const expectedApiUserAgent = "Client-info multiversx-sdk/api/test" + const expectedProxyUserAgent = "Client-info multiversx-sdk/proxy/test" + + let localApiProvider: any = new ApiNetworkProvider("https://devnet-api.multiversx.com", { timeout: 10000, headers: new AxiosHeaders({ "User-Agent": "Client-info" }), clientName: 'test' }); + let localProxyProvider: any = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { timeout: 10000, headers: new AxiosHeaders({ "User-Agent": "Client-info" }), clientName: 'test' }); + + assert.equal(localApiProvider.config.headers.getUserAgent(), expectedApiUserAgent); + assert.equal(localProxyProvider.config.headers.getUserAgent(), expectedProxyUserAgent); + }); + it("should have same response for getNetworkStatus()", async function () { let apiResponse = await apiProvider.getNetworkStatus(); let proxyResponse = await proxyProvider.getNetworkStatus(); diff --git a/src-network-providers/userAgent.ts b/src-network-providers/userAgent.ts index 726ee23e..e102f114 100644 --- a/src-network-providers/userAgent.ts +++ b/src-network-providers/userAgent.ts @@ -9,12 +9,11 @@ export function extendUserAgent(userAgentPrefix: string, config: NetworkProvider if (!config.clientName) { console.log("Can you please provide the client name of the application that uses the SDK? It will be used for metrics.") } - const headers = AxiosHeaders.from(config.headers as AxiosHeaders).normalize(true); const resolvedClientName = config.clientName || UnknownClientName; const currentUserAgent = headers.hasUserAgent() ? headers.getUserAgent() : ''; - const newUserAgent = `${currentUserAgent} ${userAgentPrefix}/${resolvedClientName}`; + const newUserAgent = currentUserAgent ? `${currentUserAgent} ${userAgentPrefix}/${resolvedClientName}` : `${userAgentPrefix}/${resolvedClientName}`; headers.setUserAgent(newUserAgent, true); } From 8b46cd3e314af36149afb99269365b4c9caf9c78 Mon Sep 17 00:00:00 2001 From: danielailie Date: Tue, 27 Aug 2024 16:36:43 +0300 Subject: [PATCH 131/133] Small renaming --- src-network-providers/apiNetworkProvider.ts | 4 ++-- src-network-providers/constants.ts | 2 +- src-network-providers/proxyNetworkProvider.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 53ea6b01..5a3bb530 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -18,14 +18,14 @@ import { TransactionOnNetwork, prepareTransactionForBroadcasting } from "./trans import { TransactionStatus } from "./transactionStatus"; import { extendUserAgent } from "./userAgent"; import { NetworkProviderConfig } from "./networkProviderConfig"; -import { MetricsPrefix } from "./constants"; +import { BaseUserAgent } from "./constants"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ApiNetworkProvider implements INetworkProvider { private url: string; private config: NetworkProviderConfig; private backingProxyNetworkProvider; - private userAgentPrefix = `${MetricsPrefix}/api` + private userAgentPrefix = `${BaseUserAgent}/api` constructor(url: string, config?: NetworkProviderConfig) { this.url = url; diff --git a/src-network-providers/constants.ts b/src-network-providers/constants.ts index 5218a901..ea134f20 100644 --- a/src-network-providers/constants.ts +++ b/src-network-providers/constants.ts @@ -3,5 +3,5 @@ import { Address } from "./primitives"; export const MaxUint64AsBigNumber = new BigNumber("18446744073709551615"); export const EsdtContractAddress = new Address("erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzllls8a5w6u"); -export const MetricsPrefix = "multiversx-sdk" +export const BaseUserAgent = "multiversx-sdk" export const UnknownClientName = "unknown" diff --git a/src-network-providers/proxyNetworkProvider.ts b/src-network-providers/proxyNetworkProvider.ts index 6bc2e2b5..c58e4bf1 100644 --- a/src-network-providers/proxyNetworkProvider.ts +++ b/src-network-providers/proxyNetworkProvider.ts @@ -1,7 +1,7 @@ import axios from "axios"; import { AccountOnNetwork, GuardianData } from "./accounts"; import { defaultAxiosConfig } from "./config"; -import { EsdtContractAddress, MetricsPrefix } from "./constants"; +import { EsdtContractAddress, BaseUserAgent } from "./constants"; import { ContractQueryRequest } from "./contractQueryRequest"; import { ContractQueryResponse } from "./contractQueryResponse"; import { ErrContractQuery, ErrNetworkProvider } from "./errors"; @@ -21,7 +21,7 @@ import { NetworkProviderConfig } from "./networkProviderConfig"; export class ProxyNetworkProvider implements INetworkProvider { private url: string; private config: NetworkProviderConfig; - private userAgentPrefix = `${MetricsPrefix}/proxy` + private userAgentPrefix = `${BaseUserAgent}/proxy` constructor(url: string, config?: NetworkProviderConfig) { this.url = url; From d4d1385ae7afbffba7c07ff0b81072961e4508a4 Mon Sep 17 00:00:00 2001 From: danielailie Date: Wed, 28 Aug 2024 11:47:19 +0300 Subject: [PATCH 132/133] Fix tests --- src-network-providers/apiNetworkProvider.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 5a3bb530..170b2fb9 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -29,12 +29,18 @@ export class ApiNetworkProvider implements INetworkProvider { constructor(url: string, config?: NetworkProviderConfig) { this.url = url; + let proxyConfig = this.getProxyConfig(config); this.config = { ...defaultAxiosConfig, ...config }; - const proxyConfig = JSON.parse(JSON.stringify(this.config)); this.backingProxyNetworkProvider = new ProxyNetworkProvider(url, proxyConfig); extendUserAgent(this.userAgentPrefix, this.config); } + private getProxyConfig(config: NetworkProviderConfig | undefined) { + let proxyConfig = JSON.parse(JSON.stringify(config)); + proxyConfig = { ...defaultAxiosConfig, ...proxyConfig }; + return proxyConfig; + } + async getNetworkConfig(): Promise { return await this.backingProxyNetworkProvider.getNetworkConfig(); } From a3014a733a0d3b8027031ce4cbbdd8dde1053ee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Fri, 30 Aug 2024 11:47:26 +0300 Subject: [PATCH 133/133] Fix constructor of ApiNetworkProvider, when config is not provided. --- src-network-providers/apiNetworkProvider.ts | 6 +++--- src-network-providers/providers.dev.net.spec.ts | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src-network-providers/apiNetworkProvider.ts b/src-network-providers/apiNetworkProvider.ts index 170b2fb9..3d6bc556 100644 --- a/src-network-providers/apiNetworkProvider.ts +++ b/src-network-providers/apiNetworkProvider.ts @@ -1,12 +1,14 @@ import axios from "axios"; import { AccountOnNetwork, GuardianData } from "./accounts"; import { defaultAxiosConfig, defaultPagination } from "./config"; +import { BaseUserAgent } from "./constants"; import { ContractQueryRequest } from "./contractQueryRequest"; import { ContractQueryResponse } from "./contractQueryResponse"; import { ErrContractQuery, ErrNetworkProvider } from "./errors"; import { IAddress, IContractQuery, INetworkProvider, IPagination, ITransaction, ITransactionNext } from "./interface"; import { NetworkConfig } from "./networkConfig"; import { NetworkGeneralStatistics } from "./networkGeneralStatistics"; +import { NetworkProviderConfig } from "./networkProviderConfig"; import { NetworkStake } from "./networkStake"; import { NetworkStatus } from "./networkStatus"; import { PairOnNetwork } from "./pairs"; @@ -17,8 +19,6 @@ import { FungibleTokenOfAccountOnNetwork, NonFungibleTokenOfAccountOnNetwork } f import { TransactionOnNetwork, prepareTransactionForBroadcasting } from "./transactions"; import { TransactionStatus } from "./transactionStatus"; import { extendUserAgent } from "./userAgent"; -import { NetworkProviderConfig } from "./networkProviderConfig"; -import { BaseUserAgent } from "./constants"; // TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider". export class ApiNetworkProvider implements INetworkProvider { @@ -36,7 +36,7 @@ export class ApiNetworkProvider implements INetworkProvider { } private getProxyConfig(config: NetworkProviderConfig | undefined) { - let proxyConfig = JSON.parse(JSON.stringify(config)); + let proxyConfig = JSON.parse(JSON.stringify(config || {})); proxyConfig = { ...defaultAxiosConfig, ...proxyConfig }; return proxyConfig; } diff --git a/src-network-providers/providers.dev.net.spec.ts b/src-network-providers/providers.dev.net.spec.ts index 890c0e55..8c603c43 100644 --- a/src-network-providers/providers.dev.net.spec.ts +++ b/src-network-providers/providers.dev.net.spec.ts @@ -1,4 +1,5 @@ -import { assert, expect } from "chai"; +import { AxiosHeaders } from "axios"; +import { assert } from "chai"; import { ApiNetworkProvider } from "./apiNetworkProvider"; import { INetworkProvider, ITransactionNext } from "./interface"; import { Address } from "./primitives"; @@ -7,7 +8,6 @@ import { MockQuery } from "./testscommon/dummyQuery"; import { NonFungibleTokenOfAccountOnNetwork } from "./tokens"; import { TransactionEventData } from "./transactionEvents"; import { TransactionOnNetwork } from "./transactions"; -import { AxiosHeaders } from "axios"; describe("test network providers on devnet: Proxy and API", function () { let alice = new Address("erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"); @@ -18,6 +18,17 @@ describe("test network providers on devnet: Proxy and API", function () { let apiProvider: INetworkProvider = new ApiNetworkProvider("https://devnet-api.multiversx.com", { timeout: 10000, clientName: 'test' }); let proxyProvider: INetworkProvider = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com", { timeout: 10000, clientName: 'test' }); + it("should create providers without configuration", async function () { + const apiProviderWithoutConfig = new ApiNetworkProvider("https://devnet-api.multiversx.com"); + const proxyProviderWithoutConfig = new ProxyNetworkProvider("https://devnet-gateway.multiversx.com"); + + const apiResponse = await apiProviderWithoutConfig.getNetworkConfig(); + const proxyResponse = await proxyProviderWithoutConfig.getNetworkConfig(); + + assert.equal(apiResponse.ChainID, "D"); + assert.equal(proxyResponse.ChainID, "D"); + }); + it("should have same response for getNetworkConfig()", async function () { let apiResponse = await apiProvider.getNetworkConfig(); let proxyResponse = await proxyProvider.getNetworkConfig();