/multiversx-spring-boot-starter-reactive

Spring Boot Starter Reactive for Elrond Network integration

Primary LanguageJavaMIT LicenseMIT

MultiversX Spring Boot Starter Reactive

This is a Spring Boot Starter project for integrating with the MultiversX Network, with the goal of achieving an effortless autoconfigured integration with the network.
The client is implemented using project Reactor as the Reactive Streams' specification implementation, allowing fully non-blocking operations and providing efficient demand management when interacting with the network, ideal for building scalable reactive microservices.

Build Status

java spring reactor

Author

@carlo-stanciu

Features

  • Auto synchronise network configurations from the MultiversX Network at startup based on the configured gateway
  • Non-blocking network requests with the reactive MultiversX client
  • Easy to use Interactors for executing various blockchain operations
  • A lot of abstracted complexity in creating addresses, wallets, transactions

Usage

To use the starter, add the following dependency to the dependencies section of your build descriptor:

  • Maven (in your pom.xml)
<dependency>
  <groupId>software.crldev</groupId>
  <artifactId>multiversx-spring-boot-starter-reactive</artifactId>
  <version>1.2.0</version>
</dependency>
  • Gradle (in your build.gradle file)
dependencies {
  implementation(group: 'software.crldev', name: 'multiversx-spring-boot-starter-reactive', version: '1.2.0')
}
  • And some other required dependencies for cryptographic functions:
implementation group: 'org.bouncycastle', name: 'bcmail-jdk15on', version: '1.70'
implementation group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version: '1.70'
implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.70'
implementation group: 'org.bouncycastle', name: 'bcprov-ext-jdk15on', version: '1.70'
implementation group: 'org.bitcoinj', name: 'bitcoinj-core', version: '0.16.2'

Documentation

First part of integration is setting up application.yaml. If nothing is set, defaults will be used.

spring:
  multiversx:
    client:
      (optional) gateway: devnet (default) (mainnet | testnet | devnet)
      (optional) customProxyUrl: https://custom-proxy.com
      readTimeoutMillis: 10000 (default)
      writeTimeoutMillis: 10000 (default)

The project uses object notations from the blockchain terminology like Address, Wallet, Transaction, Nonce, Gas, Signature etc ... so it's required to be familiar with them.

An Address can be instantiated in two ways:

- fromHex (public key in HEX String)
- fromBech32 (address in Bech32 String)

A Wallet is used for signing transactions. It can be instantiated in multiple ways:

- fromPrivateKeyBuffer (private key in byte[] format)
- fromPrivateKeyHex (private key in HEX String)
- fromPemFile (using a PEM file as an input) (both File & reactive FilePart supported)
- fromMnemonic (using a mnemonic phrase)
- fromKeyStore (not yet implemented)

We can generate a mnemonic phrase by using MnemonicsUtils .

The interaction with the MultiversX Network is done with the help of a set components called ** Interactors**, which provide all the required functionalities based on segregated parts of the network:

Account Interactor

- getAccountInfo
- getBalance
- getNonce
- getTransactions
- getStorageValue
- getStorage

Block Interactor

- queryHyperblockByNonce
- queryHyperblockByHash
- queryShardBlockByNonceFromShard
- queryShardBlockByHashFromShard

Network Interactor

- getNetworkConfig
- getShardStatus
- getNodeHeartbeatStatus

Transaction Interactor

- sendTransaction
- sendBatchOfTransactions
- simulateTransaction
- estimateTransactionCost
- queryTransactionInfo
- queryTransactionStatus

The Transaction Interactor has methods used for a more granular approach to transaction operations.
In order to create a sendable transaction, we must first create an instance of a transaction using Transaction domain object (setting nonce, gasLimit, version etc), then sign it using a wallet and transform it to a payload for the Transaction Interactor (using toSendable() method).

For a more simple way of doing transaction operations, the interactor also has overloaded methods for sending, simulating and estimating. The methods are abstracting the complexity of transaction creation: automatically assigns proper nonce value, computes fee based on data input and applies the signature before execution. The required inputs are a Wallet and the following payload with minimum necessary data:

TransactionRequest

 - receiver address
 - value
 - data
 - gas limit (optional)

Example usage:

@Autowired MxTransactionInteractor interactor;

    Mono<TransactionHash> sendTransaction(File pemFile){
    var wallet=WalletCreator.fromPemFile(pemFile);

    var tRequest=TransactionRequest.builder()
    .receiverAddress(Address.fromBech32("erd1gklqdvxxxxxxxxxxxxxxxxxxxxx"))
    .value(Balance.fromEgld(3.5))
    .data(PayloadData.fromString("hello MultiversX"))
    .build();

    return interactor.sendTransaction(wallet,tRequest);
    }

Smart Contract Interactor

- callFunction
- query
- queryHex
- queryString
- queryInt

This component has methods which interact with the smart contracts on the network (obviously).

In order to call a smart contract function, we need to pass an instance of ContractFunction:

ContractFunction

 - smart contract address
 - function name
 - array of arguments
 - value
 - gas limit (optional)

Example usage:

@Autowired MxSmartContractInteractor interactor;

    Mono<TransactionHash> callFunction(File pemFile){
    var wallet=WalletCreator.fromPemFile(pemFile);

    var function=ContractFunction.builder()
    .smartContractAddress(Address.fromBech32("erd1xxxxxxxxxxxxxxxxxxxx8llllsh6u4jp"))
    .functionName(FunctionName.fromString("addName"))
    .args(List.of(FunctionArg.fromString("MultiversX"))
    .value(Balance.zero())
    .build();

    return interactor.callFunction(wallet,function);
    }

The ContractFunction generates a payload based on function name and args (HEX encoded), creates, assigns nonce, gas (if not specified, default is used), signs and executes a transaction.

Also, for querying we can use the following object:

ContractQuery

 - smart contract address
 - function name
 - array of arguments
 - value
 - caller address (optional)

ESDT Interactor

- processEsdtTransaction
- getTokensForAccount
- getTokenRolesForAccount
- getAllTokens
- getTokenProperties
- getTokenSpecialRoles
- getNftDataForAccount
- getNftSftForAccount
- getTokensWithRole

This component has methods which cover all the ESDT related transaction and queries on the network.

processEsdtTransaction takes an ESDTTransaction arg, which has multiple implementations:

Example on how to issue a fungible ESDT:

@Autowired MxESDTInteractor interactor;

    Mono<TransactionHash> issueEsdt(File pemFile){
    var wallet=WalletCreator.fromPemFile(pemFile);

    var transaction=ESDTIssuance.builder()
    .type(Type.FUNGIBLE)
    .tokenName(TokenName.fromString("Fung Token"))
    .tokenTicker(TokenTicker.fromString("FNGTNK"))
    .initialSupply(TokenInitialSupply.fromNumber(BigInteger.TEN))
    .decimals(TokenDecimals.fromNumber(2))
    .properties(Set.of(
    new TokenProperty(TokenPropertyName.CAN_FREEZE,true),
    new TokenProperty(TokenPropertyName.CAN_CHANGE_OWNER,true),
    new TokenProperty(TokenPropertyName.CAN_ADD_SPECIAL_ROLES,true)));

    return interactor.processEsdtTransaction(wallet,transaction);
    }

For all transaction, the gas limit is already configured, but you can always set a custom value.

The rest of the ESDT operations are done in a similar fashion. NFT, SFT and META creation are also made super easy. You can follow the MultiversX ESDT documentation where you have the steps for all operations regarding ESDT, which are all covered by this framework.


For more details regarding the implementation, please consult the project's official Javadoc documentation .

Demo

You can find an example of a spring-boot service using this framework HERE.

Next features

In the next releases the following features have been planned:

  • Account storage API
  • Wallet Connect integration
  • Wallet Creator - method to instantiate wallet from password-protected JSON keystore file
  • Other enhancements

Changelog

All notable features and changes to this project will be documented in CANGELOG.md file

Contributing

Contributions are always welcome!

You can get in touch with me using the links below and figure out together how to make the project better.

Also, if you appreciate my effort and want to help me develop & maintain the MultiversX Spring Boot Framework, you can buy me some coffee via xPortal.

🔗 Links

portfolio linkedin twitter