multiversx / mx-sdk-js-core

MultiversX SDK for interacting with the MultiversX blockchain (in general) and Smart Contracts (in particular).
https://multiversx.github.io/mx-sdk-js-core/
Other
59 stars 37 forks source link

Migration support: "v12" to "v13" (April 2024) #392

Open andreibancioiu opened 7 months ago

andreibancioiu commented 7 months ago

Here, we describe the main steps for migrating from sdk-core v12 to sdk-core v13.

:bulb: For any questions about the migration, feel free to leave a comment :pray: :bulb:

When transitioning from v12 to v13, you should encounter little to no breaking changes.

However, we've introduced new approaches of creating transactions (transfers, smart contract transactions, token management operations, delegation operations), performing contract queries, and parsing transaction outcome. These new approaches are (mostly) in line with our newest SDK specs, and we recommend you to use them whenever possible.

Legacy methods are still available - though, at some point into the future, they will be marked as deprecated.

References:

andreibancioiu commented 7 months ago

1 / Non-breaking change: new TransactionFactories vs. legacy factories and builders

In v13, we have new ways of constructing transactions. The existing (legacy) approaches (v12) are still available.

Transfer (EGLD, ESDT) transactions

Smart Contract transactions

Relayed transactions

Token management transactions

References

andreibancioiu commented 7 months ago

2 / Non-breaking change: new way of performing contract queries

The existing (legacy) approaches are still working.

Before:

query = contract.createQuery({
    func: "getUltimateAnswer"
});

rawResponse = await networkProvider.queryContract(query);

Or using the interaction API:

query = contract.methods.getUltimateAnswer().buildQuery();
rawResponse = await networkProvider.queryContract(query);

Now:

adapter = new QueryRunnerAdapter({ networkProvider });
controller = new SmartContractQueriesController({ abi, queryRunner: adapter });
nicelyParsedResponse = await controller.runQuery({ function: "getUltimateAnswer" });

References

andreibancioiu commented 7 months ago

3 / Non-breaking change: new way of parsing outcome of transactions

The existing (legacy) approaches are still available.

Smart Contract transactions

Token management transactions

References

For the rest of outcome parsers & more details, check out:

andreibancioiu commented 7 months ago

4 / Non-breaking change: constructor and properties of Transaction

Since v13, the Transaction class exhibits its state as public read-write properties. For example, you can access and set the nonce property, instead of using getNonce and setNonce.

Additionally, the constructor has been adjusted in a non-breaking manner to accept initialization parameters as improved, simplified types.

E.g. transaction data can now be passed both as a simple, standard Uint8Array (new approach) and as a legacy TransactionPayload object. Value can now be passed both as a simple, standard bigint (new approach) and as a BigNumber (legacy). For the rest, see the cookbook and the auto-generated API docs.

Cookbook

andreibancioiu commented 7 months ago

5 / Small breaking change on Transaction: adjusted type for version and options

In v12, these fields were marked as deprecated:

class Transaction {
    // @deprecated
    version: TransactionVersion;
    // @deprecated
    options: TransactionOptions;

Now, in v13, we've un-deprecated them, but we've also altered their types:

class Transaction {
    ...
    version: number;
    options: number;
    ...
}

References

andreibancioiu commented 6 months ago

6 / Non-breaking (in practice) change: default transaction version is now 2, instead of 1

That is, when you create a Transaction object and do not specify an explicit version for the transaction, the new default is 2. Previously, it was 1.

Generally speaking, this should not be a breaking change within client code.

Overriding the transaction version is possible.

References

andreibancioiu commented 6 months ago

7 / Non-breaking change: pass a transaction hash to TransactionWatcher.await*

This is a non-breaking change. The old way of using TransactionWatcher is still available. However, we recommend the new approach.

Before:

async awaitCompleted(transaction: ITransaction): Promise<ITransactionOnNetwork> {...}
async awaitAnyEvent(transaction: ITransaction): Promise<ITransactionOnNetwork> {...}
...

Now:

async awaitCompleted(txHash: string): Promise<ITransactionOnNetwork> {...}
async awaitAnyEvent(txHash: string): Promise<ITransactionOnNetwork> {...}
...

References

andreibancioiu commented 6 months ago

8 / Non-breaking change: BigInt vs. BigNumber

We now favor the use of bigint primitive, instead of number or BigNumber of bignumber.js (library) - where applicable: for nonces, gas limit, gas price, amounts etc.

Classes / functions continue to accept BigNumber of bignumber.js library, just as before v13.

References

andreibancioiu commented 6 months ago

9 / Non-breaking change: serializing objects for signing

The legacy method serializeForSigning() is still available on Transaction and Message. However, we recommend using the new TransactionComputer and MessageComputer to convert these objects to raw bytes - in order to sign them:

const transactionComputer = new TransactionComputer();
const transactionBytes = transactionComputer.computeBytesForSigning(transaction);

const messageComputer = new MessageComputer();
const messageBytes = messageComputer.computeBytesForSigning(message);

Furthermore, the class SignableMessage is not deprecated - use Message, instead. Additionally, if your application is concerned with passing signed message over the Internet (e.g. towards a service, an API) and verifying them, you might be interested into: packing and unpacking a message.

References

andreibancioiu commented 6 months ago

10 / Formatting and parsing amounts

For formatting or parsing token amounts as numbers (with fixed number of decimals), do not rely on sdk-core. Instead, use sdk-dapp (higher level) or bignumber.js (lower level).

References

andreibancioiu commented 6 months ago

11 / Breaking change (trivial): Interaction.withSingleESDTNFTTransfer() and Interaction.withMultiESDTNFTTransfer() - dropped sender parameter

We've removed the (long deprecated) sender parameter from the methods: Interaction.withSingleESDTNFTTransfer() and Interaction.withMultiESDTNFTTransfer().

When using the (now legacy) interaction facility to build smart contract calls, make sure to use withSender() instead.

However, now, since v13, the recommended way to build smart contract calls is by means of the new transactions factories. See SmartContractTransactionsFactory.

Cookbook

andreibancioiu commented 6 months ago

12 / Small (trivial) breaking change: Address constructor cannot be called without parameters anymore

The Address constructor cannot be called without parameters anymore. Replacement: Address.empty().

However, generally speaking, new Address(/no params/) should have never been used within client code. Just the same, Address.empty() should not be used by client code, generally speaking (internal use only).

References

andreibancioiu commented 6 months ago

13 / Breaking (fixing) change: TokenOperationsFactory - removed canMint, canBurn

On TokenOperationsFactory (legacy, somehow unknown component), some unused and already deprecated input parameters (flags) have been removed: canMint, canBurn.

However, now, since v13, the recommended way to build smart contract calls is by means of the new transactions factories. Note: TokenOperationsFactory is not part of the new set of factories - it's an old one. The corresponding new one is called TokenManagementTransactionsFactory.

Cookbook

Additional references

andreibancioiu commented 5 months ago

14 / Breaking change when passing variadic values to SmartContract.call()

Please follow this: