Skip to content

Commit

Permalink
Merge pull request #180 from ElrondNetwork/tx-on-network
Browse files Browse the repository at this point in the history
Breaking change: unifying provider interfaces, preparing network providers for extraction - step 1
  • Loading branch information
andreibancioiu authored Apr 6, 2022
2 parents be7ba70 + dd13690 commit 12231f0
Show file tree
Hide file tree
Showing 16 changed files with 631 additions and 223 deletions.
38 changes: 18 additions & 20 deletions src-network-providers/networkProvider/apiNetworkProvider.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
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, INetworkProvider, INonFungibleTokenOfAccountOnNetwork, ITransactionOnNetwork, 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 { Nonce } from "../nonce";
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";
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 {
Expand All @@ -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);
}

Expand All @@ -50,13 +48,13 @@ export class ApiNetworkProvider implements INetworkProvider {
return stats;
}

async getAccount(address: Address): Promise<AccountOnNetwork> {
async getAccount(address: IAddress): Promise<AccountOnNetwork> {
let response = await this.doGetGeneric(`accounts/${address.bech32()}`);
let account = AccountOnNetwork.fromHttpResponse(response);
return account;
}

async getFungibleTokensOfAccount(address: Address, pagination?: Pagination): Promise<IFungibleTokenOfAccountOnNetwork[]> {
async getFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise<IFungibleTokenOfAccountOnNetwork[]> {
pagination = pagination || Pagination.default();

let url = `accounts/${address.bech32()}/tokens?${this.buildPaginationParams(pagination)}`;
Expand All @@ -68,7 +66,7 @@ export class ApiNetworkProvider implements INetworkProvider {
return tokens;
}

async getNonFungibleTokensOfAccount(address: Address, pagination?: Pagination): Promise<INonFungibleTokenOfAccountOnNetwork[]> {
async getNonFungibleTokensOfAccount(address: IAddress, pagination?: Pagination): Promise<INonFungibleTokenOfAccountOnNetwork[]> {
pagination = pagination || Pagination.default();

let url = `accounts/${address.bech32()}/nfts?${this.buildPaginationParams(pagination)}`;
Expand All @@ -80,37 +78,37 @@ export class ApiNetworkProvider implements INetworkProvider {
return tokens;
}

async getFungibleTokenOfAccount(address: Address, tokenIdentifier: string): Promise<IFungibleTokenOfAccountOnNetwork> {
async getFungibleTokenOfAccount(address: IAddress, tokenIdentifier: string): Promise<IFungibleTokenOfAccountOnNetwork> {
let response = await this.doGetGeneric(`accounts/${address.bech32()}/tokens/${tokenIdentifier}`);
let tokenData = FungibleTokenOfAccountOnNetwork.fromHttpResponse(response);
return tokenData;
}

async getNonFungibleTokenOfAccount(address: Address, collection: string, nonce: Nonce): Promise<INonFungibleTokenOfAccountOnNetwork> {
async getNonFungibleTokenOfAccount(address: IAddress, collection: string, nonce: INonce): Promise<INonFungibleTokenOfAccountOnNetwork> {
let response = await this.doGetGeneric(`accounts/${address.bech32()}/nfts/${collection}-${nonce.hex()}`);
let tokenData = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response);
return tokenData;
}

async getTransaction(txHash: TransactionHash): Promise<ITransactionOnNetwork> {
async getTransaction(txHash: IHash): Promise<TransactionOnNetwork> {
let response = await this.doGetGeneric(`transactions/${txHash.toString()}`);
let transaction = TransactionOnNetwork.fromApiHttpResponse(txHash, response);
return transaction;
}

async getTransactionStatus(txHash: TransactionHash): Promise<TransactionStatus> {
async getTransactionStatus(txHash: IHash): Promise<TransactionStatus> {
let response = await this.doGetGeneric(`transactions/${txHash.toString()}?fields=status`);
let status = new TransactionStatus(response.status);
return status;
}

async sendTransaction(tx: Transaction): Promise<TransactionHash> {
async sendTransaction(tx: ITransaction): Promise<IHash> {
let response = await this.doPostGeneric("transactions", tx.toSendable());
let hash = new TransactionHash(response.txHash);
let hash = new Hash(response.txHash);
return hash;
}

async simulateTransaction(tx: Transaction): Promise<any> {
async simulateTransaction(tx: ITransaction): Promise<any> {
return await this.backingProxyNetworkProvider.simulateTransaction(tx);
}

Expand All @@ -133,7 +131,7 @@ export class ApiNetworkProvider implements INetworkProvider {
return definition;
}

async getNonFungibleToken(collection: string, nonce: Nonce): Promise<INonFungibleTokenOfAccountOnNetwork> {
async getNonFungibleToken(collection: string, nonce: INonce): Promise<INonFungibleTokenOfAccountOnNetwork> {
let response = await this.doGetGeneric(`nfts/${collection}-${nonce.hex()}`);
let token = NonFungibleTokenOfAccountOnNetwork.fromApiHttpResponse(response);
return token;
Expand Down Expand Up @@ -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);
}

Expand Down
11 changes: 11 additions & 0 deletions src-network-providers/networkProvider/config.ts
Original file line number Diff line number Diff line change
@@ -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);
}
]
};
71 changes: 37 additions & 34 deletions src-network-providers/networkProvider/contractResults.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import { BigNumber } from "bignumber.js";
import { Address } from "../address";
import { Balance } from "../balance";
import { Hash } from "../hash";
import { IContractQueryResponse, IContractResultItem, IContractResults } from "./interface";
import { GasLimit, GasPrice } from "../networkParams";
import { Nonce } from "../nonce";
import { MaxUint64, ReturnCode } from "../smartcontracts";
import { TransactionHash } from "../transaction";

export class ContractResults implements IContractResults {
readonly items: IContractResultItem[];

constructor(items: IContractResultItem[]) {
import { IAddress, IContractQueryResponse, IContractReturnCode, IGasLimit, IGasPrice, IHash, INonce } from "./interface";
import { TransactionLogs } from "./transactionLogs";
import { MaxUint64 } from "../smartcontracts/query";
import { Address, ContractReturnCode, Hash, Nonce, TransactionValue } from "./primitives";

export class ContractResults {
readonly items: ContractResultItem[];

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();
});
}
Expand All @@ -34,19 +30,24 @@ export class ContractResults implements IContractResults {
}
}

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();
export class ContractResultItem {
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();

constructor(init?: Partial<ContractResultItem>) {
Object.assign(this, init);
}

static fromProxyHttpResponse(response: any): ContractResultItem {
let item = ContractResultItem.fromHttpResponse(response);
Expand All @@ -65,37 +66,39 @@ export class ContractResultItem implements IContractResultItem {
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 || 0).toString());
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 = Number(response.gasLimit || 0);
item.gasPrice = Number(response.gasPrice || 0);
item.data = response.data || "";
item.callType = response.callType;
item.returnMessage = response.returnMessage;

item.logs = TransactionLogs.fromHttpResponse(response.logs || {});

return item;
}
}

export class ContractQueryResponse implements IContractQueryResponse {
returnData: string[] = [];
returnCode: ReturnCode = ReturnCode.None;
returnCode: IContractReturnCode = new ContractReturnCode("");
returnMessage: string = "";
gasUsed: GasLimit = new GasLimit(0);
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 = payload["returnCode"] || "";
response.returnCode = new ContractReturnCode(payload["returnCode"] || "");
response.returnMessage = payload["returnMessage"] || "";
response.gasUsed = new GasLimit(MaxUint64.minus(gasRemaining).toNumber());
response.gasUsed = MaxUint64.minus(gasRemaining).toNumber();

return response;
}
Expand Down
30 changes: 30 additions & 0 deletions src-network-providers/networkProvider/errors.ts
Original file line number Diff line number Diff line change
@@ -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);
}
}
Loading

0 comments on commit 12231f0

Please sign in to comment.