kmcpg / multiversx-sdk-laravel
Laravel SDK for interacting with the MultiversX blockchain.
Requires
- php: ^8.1
- bitwasp/bech32: ^0.0.1
- illuminate/http: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
- kornrunner/keccak: ^1.1
- simplito/elliptic-php: ^1.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0
- phpunit/phpunit: ^10.0|^11.0
README
A Laravel SDK for interacting with the MultiversX blockchain (formerly Elrond). PS :Initially made for intern usage it still in alpha use with cautions.
Installation
composer require kmcpg/multiversx-sdk-laravel
The service provider and facade are auto-discovered.
Configuration
Publish the configuration file:
php artisan vendor:publish --tag=multiversx-config
This will create a config/multiversx.php
file. You can customize the network, API URL, and default transaction parameters:
// config/multiversx.php return [ // 'mainnet', 'testnet', or 'devnet' 'network' => env('MULTIVERSX_NETWORK', 'devnet'), // Public API URL 'api_url' => env('MULTIVERSX_API_URL', 'https://devnet-api.multiversx.com'), // Default gas price for transactions 'default_gas_price' => env('MULTIVERSX_DEFAULT_GAS_PRICE', 1000000000), // Default transaction version 'default_tx_version' => env('MULTIVERSX_DEFAULT_TX_VERSION', 1), ];
Set your environment variables in .env
if needed:
MULTIVERSX_NETWORK=devnet MULTIVERSX_API_URL=https://devnet-api.multiversx.com # MULTIVERSX_DEFAULT_GAS_PRICE=1000000000 # MULTIVERSX_DEFAULT_TX_VERSION=1
Usage
You can use the Multiversx
facade or inject the specific services you need.
Utility Class (Converter
)
The SDK provides a KmcpG\MultiversxSdkLaravel\Utils\Converter
class with static methods for common tasks:
use KmcpG\MultiversxSdkLaravel\Utils\Converter; // Convert EGLD to atomic units (string) $atomicValue = Converter::egldToAtomic('1.5'); // "1500000000000000000" // Convert ESDT amount to atomic units (string) // Requires knowing the token decimals (fetch via TokenService) $atomicEsdt = Converter::esdtToAtomic('123.45', 6); // Assuming 6 decimals: "123450000" // Encode arguments for a Smart Contract call (array of hex strings) $rawArgs = [ gmp_init(1000), 'erd1...', // Bech32 address true, 'hello' ]; $encodedArgs = Converter::encodeSmartContractArgs($rawArgs); // Result: ['03e8', 'publicKeyHex...', '01', '68656c6c6f'] // Build the data field for a Smart Contract call (string) $dataField = Converter::buildContractDataField('myFunction', $encodedArgs); // Result: "myFunction@03e8@publicKeyHex...@01@68656c6c6f"
Wallet Operations (via Facade or WalletService
)
use KmcpG\MultiversxSdkLaravel\Facades\Multiversx; // or inject KmcpG\MultiversxSdkLaravel\Services\WalletService // Get account details (Nonce, Balance, etc.) $account = Multiversx::getAccount('erd1...'); // $nonce = $account['nonce']; // $balance = $account['balance']; // Create a new wallet (generates private/public keys and address) $wallet = Multiversx::createWallet(); // $privateKey = $wallet->privateKey; // $publicKey = $wallet->publicKey; // $address = $wallet->address; // Validate an address $isValid = Multiversx::isValidAddress('erd1...'); // Returns true or false // Convert Bech32 address to Public Key Hex (Static Utility) use KmcpG\MultiversxSdkLaravel\Services\WalletService; $publicKeyHex = WalletService::bech32ToPublicKeyHex('erd1...');
Transaction Operations (via TransactionService
)
Inject KmcpG\MultiversxSdkLaravel\Services\TransactionService
.
use KmcpG\MultiversxSdkLaravel\Services\TransactionService; use KmcpG\MultiversxSdkLaravel\Services\WalletService; use KmcpG\MultiversxSdkLaravel\Utils\Converter; // Import Converter class MyController { protected TransactionService $txService; protected WalletService $walletService; public function __construct(TransactionService $txService, WalletService $walletService) { $this->txService = $txService; $this->walletService = $walletService; // Typically, you'd retrieve the private key securely } // Helper to get address (implementation specific) private function getAddressFromPrivateKey(string $privateKeyHex): string { // You might implement this using WalletService or keep it separate // Requires mdanter/ecc currently $adapter = \Mdanter\Ecc\EccFactory::getAdapter(); $generator = \Mdanter\Ecc\EccFactory::getSecgCurves()->generator256k1(); $key = $generator->getPrivateKeyFrom(gmp_init($privateKeyHex, 16)); $point = $key->getPublicKey()->getPoint(); $pkBin = substr((new \Mdanter\Ecc\Serializer\Point\UncompressedPointSerializer($adapter))->serialize($point), 1, 32); $data = array_values(unpack('C*', $pkBin)); $convertedData = \BitWasp\Bech32\convertBits($data, count($data), 8, 5, true); return \BitWasp\Bech32\encode('erd', $convertedData); } public function sendEgldExample(string $senderPrivateKeyHex, string $receiverAddress, string $amountEgld, int $nonce) { // 1. Prepare basic EGLD transfer $params = [ 'sender' => $this->getAddressFromPrivateKey($senderPrivateKeyHex), 'contractAddress' => $receiverAddress, 'functionName' => '', // Empty function name for EGLD transfer 'arguments' => [], // No arguments for EGLD transfer 'value' => Converter::egldToAtomic($amountEgld), // Use Converter 'nonce' => $nonce, 'gasLimit' => 50000, ]; // Note: Sending EGLD uses prepareSmartContractCall structure $preparedTx = $this->txService->prepareSmartContractCall($params); // 2. Sign $signedTx = $this->txService->signTransaction($preparedTx, $senderPrivateKeyHex); // 3. Send $result = $this->txService->sendTransaction($signedTx); return $result; } public function sendEsdtExample(string $senderPrivateKeyHex, string $receiverAddress, string $token, string $amount, int $decimals, int $nonce) { // 1. Prepare ESDT transfer $params = [ 'sender' => $this->getAddressFromPrivateKey($senderPrivateKeyHex), 'receiver' => $receiverAddress, 'tokenIdentifier' => $token, // Use GMP and Converter::esdtToAtomic or just pass GMP amount 'amount' => gmp_init(Converter::esdtToAtomic($amount, $decimals)), 'nonce' => $nonce, 'gasLimit' => 600000, ]; $preparedTx = $this->txService->prepareEsdtTransfer($params); // 2. Sign & 3. Send (same as above) $signedTx = $this->txService->signTransaction($preparedTx, $senderPrivateKeyHex); $result = $this->txService->sendTransaction($signedTx); return $result; } public function sendNftExample(string $senderPrivateKeyHex, string $receiverAddress, string $collection, int $nftNonce, int $txNonce) { // 1. Prepare NFT transfer $params = [ 'sender' => $this->getAddressFromPrivateKey($senderPrivateKeyHex), 'receiver' => $receiverAddress, 'collection' => $collection, 'nonce' => $nftNonce, // The nonce of the specific NFT 'quantity' => gmp_init(1), // Quantity is 1 for NFTs 'txNonce' => $txNonce, 'gasLimit' => 1000000, ]; $preparedTx = $this->txService->prepareNftTransfer($params); // 2. Sign & 3. Send (same as above) $signedTx = $this->txService->signTransaction($preparedTx, $senderPrivateKeyHex); $result = $this->txService->sendTransaction($signedTx); return $result; } public function callContractExample(string $senderPrivateKeyHex, string $contractAddress, string $function, array $rawArgs, string $valueEgld, int $nonce) { // 1. Prepare SC call $params = [ 'sender' => $this->getAddressFromPrivateKey($senderPrivateKeyHex), 'contractAddress' => $contractAddress, 'functionName' => $function, 'arguments' => $rawArgs, // Pass raw arguments here 'value' => Converter::egldToAtomic($valueEgld), // Use Converter 'nonce' => $nonce, 'gasLimit' => 5000000, ]; // prepareSmartContractCall now handles encoding via Converter internally $preparedTx = $this->txService->prepareSmartContractCall($params); // 2. Sign & 3. Send (same as above) $signedTx = $this->txService->signTransaction($preparedTx, $senderPrivateKeyHex); $result = $this->txService->sendTransaction($signedTx); return $result; } public function checkStatusExample(string $txHash) { $status = $this->txService->getTransactionStatus($txHash); // e.g., $status['status'] can be 'pending', 'success', 'fail' return $status; } }
Token Operations (via TokenService
)
Inject KmcpG\MultiversxSdkLaravel\Services\TokenService
.
use KmcpG\MultiversxSdkLaravel\Services\TokenService; // Get properties of a token (ESDT/NFT/SFT) $properties = $tokenService->getTokenProperties('WEGLD-bd4d79'); // $name = $properties['name']; // $decimals = $properties['decimals']; // Get the balance of a specific token for an address $balanceInfo = $tokenService->getTokenBalance('erd1...', 'WEGLD-bd4d79'); // $balanceAtomic = $balanceInfo['balance']; // Balance in atomic units (string)
Testing
This SDK includes both unit and integration tests using PHPUnit.
Run all tests:
composer test
Run only unit tests:
vendor/bin/phpunit --testsuite=Unit
Run only integration tests:
vendor/bin/phpunit --testsuite=Integration
Integration Test Requirements
The integration tests (tests/Integration
) interact with the MultiversX Devnet. To run them successfully, you need valid Devnet credentials set as environment variables in your .env
file or your system environment:
# .env for integration tests MULTIVERSX_TEST_SENDER_PK="YOUR_64_CHAR_HEX_PRIVATE_KEY" MULTIVERSX_TEST_SENDER_ADDRESS="erd1..." MULTIVERSX_TEST_RECEIVER_ADDRESS="erd1..."
MULTIVERSX_TEST_SENDER_PK
: Required. The 64-character hexadecimal private key of a Devnet wallet holding some test xEGLD. This must be the raw hex key, NOT a path to a PEM file or its content.MULTIVERSX_TEST_SENDER_ADDRESS
: Required. The correspondingerd1...
address for the sender private key.MULTIVERSX_TEST_RECEIVER_ADDRESS
: Required. Another validerd1...
Devnet address to receive test xEGLD.
If these variables are not set, the integration tests that require sending a transaction will be skipped. You can obtain Devnet credentials and test xEGLD from the MultiversX Devnet Faucet.
Contributing
Contributions are welcome! Please feel free to submit issues or pull requests.
License
MIT