Skip to content

Commit

Permalink
Merge pull request #55 from multiversx/add-support-for-tx-next
Browse files Browse the repository at this point in the history
Add suport for TransactionNext
  • Loading branch information
popenta authored Feb 20, 2024
2 parents 302dae1 + ab6f64a commit 9ccbae5
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 20 deletions.
13 changes: 7 additions & 6 deletions src-network-providers/apiNetworkProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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, prepareTransactionForBroadcasting } from "./transactions";
import { TransactionStatus } from "./transactionStatus";

// TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider".
Expand Down Expand Up @@ -119,16 +119,17 @@ export class ApiNetworkProvider implements INetworkProvider {
return status;
}

async sendTransaction(tx: ITransaction): Promise<string> {
let response = await this.doPostGeneric("transactions", tx.toSendable());
async sendTransaction(tx: ITransaction | ITransactionNext): Promise<string> {
const transaction = prepareTransactionForBroadcasting(tx);
const response = await this.doPostGeneric("transactions", transaction);
return response.txHash;
}

async sendTransactions(txs: ITransaction[]): Promise<string[]> {
async sendTransactions(txs: (ITransaction | ITransactionNext)[]): Promise<string[]> {
return await this.backingProxyNetworkProvider.sendTransactions(txs);
}

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

Expand Down
1 change: 0 additions & 1 deletion src-network-providers/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ export class ErrNetworkProvider extends Err {
}
}


/**
* Signals a generic error in the context of querying Smart Contracts.
*/
Expand Down
22 changes: 20 additions & 2 deletions src-network-providers/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ export interface INetworkProvider {
/**
* Broadcasts an already-signed transaction.
*/
sendTransaction(tx: ITransaction): Promise<string>;
sendTransaction(tx: ITransaction | ITransactionNext): Promise<string>;

/**
* Broadcasts a list of already-signed transactions.
*/
sendTransactions(txs: ITransaction[]): Promise<string[]>;
sendTransactions(txs: (ITransaction | ITransactionNext)[]): Promise<string[]>;

/**
* Simulates the processing of an already-signed transaction.
Expand Down Expand Up @@ -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;
}
50 changes: 48 additions & 2 deletions src-network-providers/providers.dev.net.spec.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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("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: 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 proxyProvider.sendTransaction(transaction);
const proxyTxNextHash = await proxyProvider.sendTransaction(transactionNext);

assert.equal(apiLegacyTxHash, proxyLegacyTxHash);
assert.equal(apiTxNextHash, proxyTxNextHash);
});
});
19 changes: 11 additions & 8 deletions src-network-providers/proxyNetworkProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, prepareTransactionForBroadcasting } from "./transactions";
import { TransactionStatus } from "./transactionStatus";

// TODO: Find & remove duplicate code between "ProxyNetworkProvider" and "ApiNetworkProvider".
Expand Down Expand Up @@ -122,13 +122,15 @@ export class ProxyNetworkProvider implements INetworkProvider {
return status;
}

async sendTransaction(tx: ITransaction): Promise<string> {
let response = await this.doPostGeneric("transaction/send", tx.toSendable());
async sendTransaction(tx: ITransaction | ITransactionNext): Promise<string> {
const transaction = prepareTransactionForBroadcasting(tx);
const response = await this.doPostGeneric("transaction/send", transaction);
return response.txHash;
}

async sendTransactions(txs: ITransaction[]): Promise<string[]> {
const data: any = txs.map(tx => tx.toSendable());
async sendTransactions(txs: (ITransaction | ITransactionNext)[]): Promise<string[]> {
const data = (txs).map((tx) => prepareTransactionForBroadcasting(tx));

const response = await this.doPostGeneric("transaction/send-multiple", data);
const hashes = Array(txs.length).fill(null);

Expand All @@ -139,8 +141,9 @@ export class ProxyNetworkProvider implements INetworkProvider {
return hashes;
}

async simulateTransaction(tx: ITransaction): Promise<any> {
let response = await this.doPostGeneric("transaction/simulate", tx.toSendable());
async simulateTransaction(tx: ITransaction | ITransactionNext): Promise<any> {
const transaction = prepareTransactionForBroadcasting(tx);
const response = await this.doPostGeneric("transaction/simulate", transaction);
return response;
}

Expand Down
26 changes: 25 additions & 1 deletion src-network-providers/transactions.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
import { TransactionStatus } from "./transactionStatus";
import { ContractResults } from "./contractResults";
import { Address } from "./primitives";
import { IAddress } from "./interface";
import { IAddress, ITransaction, ITransactionNext } from "./interface";
import { TransactionLogs } from "./transactionLogs";
import { TransactionReceipt } from "./transactionReceipt";

export function prepareTransactionForBroadcasting(transaction: ITransaction | ITransactionNext): any {
if ("toSendable" in transaction){
return transaction.toSendable();
}

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 = "";
Expand Down

0 comments on commit 9ccbae5

Please sign in to comment.