Skip to content

Commit

Permalink
Merge pull request #911 from multiversx/development
Browse files Browse the repository at this point in the history
v2.20.0
  • Loading branch information
CiprianDraghici committed Sep 7, 2023
2 parents ce06ffe + e7c3361 commit 30acba9
Show file tree
Hide file tree
Showing 39 changed files with 1,084 additions and 447 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [[v2.20.0]](https://github.com/multiversx/mx-sdk-dapp/pull/911)] - 2023-09-07

- [Add batch transactions documentation](https://github.com/multiversx/mx-sdk-dapp/pull/909)
- [Batch transactions improvements](https://github.com/multiversx/mx-sdk-dapp/pull/905)

## [[v2.19.9]](https://github.com/multiversx/mx-sdk-dapp/pull/908)] - 2023-09-06

- [Changed `safeRedirect` method to force page reload on logout to ensure fresh states](https://github.com/multiversx/mx-sdk-dapp/pull/907)
Expand Down
198 changes: 195 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -532,9 +532,125 @@ or the `useSignTransactions` hook defined below. If you don't use one of these,

</details>

<details><summary>
<details>
<summary>
Sending sync transactions in batches (batch transactions mechanism)
</summary>

### Sending Transactions

The API for sending sync transactions is a function called **sendBatchTransactions**:

`import { sendBatchTransactions } from "@multiversx/sdk-dapp/services/transactions/sendBatchTransactions";`

It can be used to send a group of transactions (that ca be synchronized) with minimum information:


```typescript
const { sessionId, error } = await sendBatchTransactions({
transactions: [
[
{
value: '1000000000000000000',
data: 'tx1',
receiver: receiverAddress
},
],
[
{
value: '1000000000000000000',
data: 'tx2',
receiver: receiverAddress
},
{
value: '1000000000000000000',
data: 'tx3',
receiver: receiverAddress
},
]
],
/**
* the route to be redirected to after signing. Will not redirect if the user is already on the specified route
* @default window.location.pathname
*/
callbackRoute?: string;
/**
* custom message for toasts texts
* @default null
*/
transactionsDisplayInfo: TransactionsDisplayInfoType;
/**
* Minimum amount of gas in order to process the transaction.
* @default 50_000
*/
minGasLimit?: number (optional, defaults to 50_000);
/**
* Contains extra sessionInformation that will be passed back via getSignedTransactions hook
*/
sessionInformation?: any (optional, defaults to null)
/**
* The transactions will be signed without being sent to the blockchain
*/
signWithoutSending?: boolean;
/**
* Delay the transaction status from going into "successful" state
*/
completedTransactionsDelay?: number;
/**
* If true, redirects to the provided callbackRoute
*/
redirectAfterSigning?: boolean;
});
```

It returns a Promise that will be fulfilled with `{error?: string; sessionId: string | null;}`

- `sessionId` is the transactions' session id used to compose the `batchId` which will be used to send the batch to the batch service and to track the transactions status and react to it.
- `error` is the error that can appear during the signing/sending process.

### How to synchronize transactions ?
`sendBatchTransactions` accepts an argument `transactions` which is an array of transactions arrays.
Each transaction array will be sent to the blockchain in the order they are provided.
Having the example above, the transactions will be sent in the following order:
- `tx1`
- `tx2, tx3`

`tx1` will be sent first, waits until is completed, then `tx2` and `tx3` will be sent in parallel. This means that the groups are sent synchronously, but the transactions inside a group are sent in parallel.

** Important! This function will send the transactions automatically in batches, based on the provided transactions array, immediately after signing.
If you do not want them to be sent automatically, but on demand, then you should use send callback exposed by the `useSendBatchTransactions` hook.
Be sure to save the `sessionId` passed to the batch. We recommend to generate a new sessionId like this: `Date.now().toString();` **

```typescript
import { sendBatchTransactions } from '@multiversx/sdk-dapp/services/transactions/sendBatchTransactions';
import { useSendBatchTransactions } from '@multiversx/sdk-dapp/hooks/transactions/batch/useSendBatchTransactions';


const { send: sendBatchToBlockchain } = useSendBatchTransactions();

// Use signWithoutSending: true to sign the transactions without sending them to the blockchain
sendBatchTransactions({
transactions,
signWithoutSending: true,
callbackRoute: window.location.pathname,
customTransactionInformation: { redirectAfterSign: true }
});

const { error, batchId, data } = await sendBatchToBlockchain({
transactions,
sessionId
});
```

**Important! For the transaction to be signed, you will have to use either `SignTransactionsModals` defined above, in the `Prerequisites` section,
or the `useSignTransactions` hook defined below. If you don't use one of these, the transactions won't be signed**

</details>

<details>
<summary>
Transaction Signing Flow
</summary>
</summary>

### Transaction Signing Flow

Expand Down Expand Up @@ -619,7 +735,83 @@ Tracking a transaction

### Tracking a transaction

The library exposes a hook called useTrackTransactionStatus;
The library has a built-in implementation for tracking the transactions sent normally of synchronously via batch transactions.
Also, exposes a hook called `useTrackTransactionStatus`;

### 1. Built-in tracking

There is a `TransactionTracker` component that is used to track transactions. It is used by default in the `DappProvider` component.
This component is using the `useTransactionsTracker` and `useBatchTransactionsTracker` hooks to track the transactions.

`useTransactionsTracker` - track transactions sent normally
`useBatchTransactionsTracker` track batch transactions

The developers are be able to create their own implementation for the transaction tracking component (using these hooks or creating their own logic) and pass it to the `DappProvider` component through `customComponents` field.

```jsx
import { TransactionsTracker } from "your/module";
<DappProvider
environment={environment}
customNetworkConfig={{
name: 'customConfig',
apiTimeout,
walletConnectV2ProjectId
}}
customComponents={{
transactionTracker: {
component: TransactionsTracker,
props: {
onSuccess: (sessionId) => {
console.log(`Session ${sessionId} successfully completed`);
},
onFail: (sessionId, errorMessage) => {
if (errorMessage) {
console.log(`Session ${sessionId} failed, ${errorMessage}`);
return;
}

console.log(`Session ${sessionId} failed`);
}
}
}
}}
>
````
The props passed to the `TransactionsTracker` component are:
```typescript
export interface TransactionsTrackerType {
getTransactionsByHash?: GetTransactionsByHashesType;
onSuccess?: (sessionId: string | null) => void;
onFail?: (sessionId: string | null, errorMessage?: string) => void;
}
```
Also, the same props can be passed to the `useTransactionsTracker` and `useBatchTransactionsTracker` hooks.

```typescript
import { useBatchTransactionsTracker } from 'hooks/transactions/batch/tracker/useBatchTransactionsTracker';
import { useTransactionsTracker } from 'hooks/transactions/useTransactionsTracker';
const props = {
onSuccess: (sessionId) => {
console.log(`Session ${sessionId} successfully completed`);
},
onFail: (sessionId, errorMessage) => {
if (errorMessage) {
console.log(`Session ${sessionId} failed, ${errorMessage}`);
return;
}
console.log(`Session ${sessionId} failed`);
}
};
useTransactionsTracker(props);
useBatchTransactionsTracker(props);
```

The transactions trackers will automatically update the transactions statuses in the store. This functionality is used by the `TransactionToastList` component to display the transactions statuses.

### 2. Tracking transaction status

```typescript
import {useTrackTransactionStatus} from @multiversx/sdk-dapp/hooks;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@multiversx/sdk-dapp",
"version": "2.19.9",
"version": "2.20.0",
"description": "A library to hold the main logic for a dapp on the MultiversX blockchain",
"author": "MultiversX",
"license": "GPL-3.0-or-later",
Expand Down
1 change: 1 addition & 0 deletions src/apiCalls/transactions/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './sendSignedTransactions';
export * from './sendSignedBatchTransactions';
export * from './getTransactionsByHashes';
export * from './getTransactions';
export * from './getTransactionsCount';
Expand Down
68 changes: 68 additions & 0 deletions src/apiCalls/transactions/sendSignedBatchTransactions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import axios from 'axios';
import { TIMEOUT } from 'constants/network';
import { buildBatchId } from 'hooks/transactions/helpers/buildBatchId';
import { addressSelector, networkSelector } from 'reduxStore/selectors';
import { store } from 'reduxStore/store';
import {
BatchTransactionsRequestType,
BatchTransactionsResponseType,
CustomTransactionInformation,
SignedTransactionType
} from 'types';
import { TRANSACTIONS_BATCH } from '../endpoints';

export interface SendBatchTransactionsPropsType {
transactions: SignedTransactionType[][];
sessionId: string;
customTransactionInformationOverrides?: Partial<CustomTransactionInformation>;
}

export type SendSignedBatchTransactionsReturnType = {
error?: string | null;
batchId?: string | null;
data?: BatchTransactionsResponseType;
};

export async function sendSignedBatchTransactions({
transactions,
sessionId
}: SendBatchTransactionsPropsType) {
const address = addressSelector(store.getState());
const { apiAddress, apiTimeout } = networkSelector(store.getState());

if (!address) {
return {
error:
'Invalid address provided. You need to be logged in to send transactions',
batchId: null
};
}

try {
const batchId = buildBatchId({
sessionId,
address
});

const payload: BatchTransactionsRequestType = {
transactions,
id: batchId
};

const response = await axios.post<BatchTransactionsResponseType>(
`${apiAddress}/${TRANSACTIONS_BATCH}`,
payload,
{
timeout: Number(apiTimeout ?? TIMEOUT)
}
);

return { batchId, data: response.data };
} catch (err) {
console.error('error sending batch transactions', err);
return {
error: (err as any)?.message ?? 'error sending batch transactions',
batchId: null
};
}
}
Loading

0 comments on commit 30acba9

Please sign in to comment.