This update to the JavaScript SDK brings a lot of significant changes:
- Support for Protocol 20, which introduces the Soroban smart contract platform to the Stellar network.
- Support for Soroban RPC, a new web service unrelated to Horizon built around smart contract interactions.
- A build system overhaul to Webpack 5 and ES6, meaning downstream systems will need to either transpile the library or update their build systems in turn in order to support the new bundles.
- Tons of security fixes and performance optimizations that were enabled by the above, namely through updating all of the dependencies to their latest and greatest versions.
Traditionally, this SDK was a way to do two things:
- Build Stellar transactions, and
- interact with Horizon.
Because there is a new web service to interact with, there has been a significant overhaul in the structure of the modules in the SDK to properly support both Horizon and Soroban RPC. So now, we have:
- In
stellar-sdk's default import, you can build Stellar transactions, and - In
stellar-sdk'sHorizonnamespace (or instellar-sdk/horizon), you can interact with Horizon. - In
stellar-sdk'sSorobanRpcnamespace (or instellar-sdk/soroban), you can interact with Soroban RPC.
There are now three primary namespaces in the SDK, each of which differs in responsibility depending on what you want to achieve:
- If you want to build operations, deal with accounts, or touch the XDR in any way (i.e. the fundamental building blocks of the Stellar protocol), you can use the package directly:
import * as StellarSdk from '@stellar/stellar-sdk';In StellarSdk, you will find the Account and MuxedAccount objects, the TransactionBuilder, the SorobanDataBuilder, and all of the other "shared" concepts that simply define the Stellar protocol.
(If you've ever imported and used stellar-base directly, then this distinction should be clear: anything found in stellar-base lives in the top-level module.)
- If you want to interact with Horizon by querying its endpoints or submitting transactions, you will need to dig deeper into the module:
import { Horizon } from '@stellar/stellar-sdk';In Horizon, you will find Server and all of the related "call builder" objects for its various endpoints. If you are interested in the API definitions themselves, then these will be in Horizon.HorizonApi or Horizon.ServerApi.
- If you want to interact with Soroban RPC, you will also need to dig deeper into the module in a very similar way:
import { SorobanRpc } from '@stellar/stellar-sdk';This contains a different Server object which will let you execute various RPC endpoints. It also contains API schema definitions under the SorobanRpc.Api namespace, and misc. helpers for dealing with transaction simulation (e.g. SorobanRpc.assembleTransaction).
If you are upgrading from the latest stable version of the stellar-sdk package, you'll need to update your imports accordingly:
- The package now lives under the
@stellar/npm namespace. - There is no longer a default export, so if you had
import StellarSdk from 'stellar-sdk';, you will now need to writeimport * as StellarSdk from '@stellar/stellar-sdk';.- However, we highly recommend only importing the specific functionality that you need in order to keep your bundle sizes reasonable, e.g.
import { TransactionBuilder, Account, Horizon } from '@stellar/stellar-sdk';.
- However, we highly recommend only importing the specific functionality that you need in order to keep your bundle sizes reasonable, e.g.
Servernow lives under theHorizonsubmodule, so you can eitherimport { Horizon } from '@stellar/stellar-sdk';orconst { Server } = StellarSdk.Horizon;.- The API definitions are also under the
Horizonsubmodule, so update your references accordingly. - Anything related to SEP-10 that used to live under the
Utilsnamespace now lives under theWebAuthmodule. So if, before, you didStellarSdk.Utils.verifyTxSignedBy(...)you would nowimport { WebAuth } from '@stellar/stellar-sdk';and callWebAuth.verifyTxSignedBy(...). Alternatively, you can grab members from the top-level module, e.g.const { verifyTxSignedBy } = StellarSdk.WebAuth;. - The TOML resolver and federation server have also moved under a separate module:
StellarSdk.StellarTomlcontains aResolverandStellarSdk.Federationcontains aServer, respectively.
Future versions of the SDK are likely to move these latter two bullet points into separate packages to avoid bloating the bundle with features that most people do not need.
Here's an example before-and-after set of scripts:
Details
Before:
import StellarSdk from 'stellar-sdk';
const s = StellarSdk.Server('https://horizon-testnet.stellar.org');
const kp = StellarSdk.Keypair.random();
async function main() {
return s.loadAccount(kp.publicKey()).then(account => {
const tx = new StellarSdk.TransactionBuilder(account, { fee: BASE_FEE })
.addOperation(StellarSdk.Operation.payment({ /* etc. */ }))
.setNetworkPassphrase(StellarSdk.Networks.TESTNET)
.setTimeout(30)
.build();
tx.sign(kp);
return s.submitTransaction(tx);
});
}After:
import {
Keypair,
Networks,
TransactionBuilder,
Operation,
Horizon
} from '@stellar/stellar-sdk';
const s = Horizon.Server('https://horizon-testnet.stellar.org');
const kp = Keypair.random();
async function main() {
return s.loadAccount(kp.publicKey()).then(account => {
const tx = new TransactionBuilder(account, { fee: BASE_FEE })
.addOperation(Operation.payment({ /* etc. */ }))
.setNetworkPassphrase(Networks.TESTNET)
.setTimeout(30)
.build();
tx.sign(kp);
return s.submitTransaction(tx);
});
}If you are coming from soroban-client and want to adapt your codebase to this library (or perhaps you want to leverage Horizon in your app, as well), then you will need to identify where you are interacting with the RPC server vs. just interacting with the Stellar protocol. Namely,
Servernow lives under theSorobanRpcsubmodule- Soroban helpers such as
assembleTransactionalso live under this submodule - The API definitions now live in the
SorobanRpc.Apisubmodule - Helpers that are "shared" and have nothing to do with the RPC (like
TransactionBuilderandContractSpec) are still in the top level
Here's an example before-and-after set of scripts:
Details
Before:
import * as SorobanClient from 'soroban-client';
const s = SorobanClient.Server('https://rpc-testnet.stellar.org');
const kp = SorobanClient.Keypair.random();
const c = new Contract("C...");
async function main() {
return s.getAccount(kp.publicKey()).then(account => {
const tx = new SorobanClient.TransactionBuilder(account, {
fee: BASE_FEE
})
.addOperation(c.call("hello", SorobanClient.scValToNative("world")))
.setNetworkPassphrase(SorobanClient.Networks.FUTURENET)
.setTimeout(30)
.build();
let sim: SorobanClient.SorobanRpc.SimulateTransactionResult;
sim = await s.simulateTransaction(tx);
const readyTx = SorobanClient.assembleTransaction(tx, sim);
readyTx.sign(kp);
return s.submitTransaction(readyTx);
});
}After:
import {
Keypair,
Networks,
TransactionBuilder,
Operation,
scValToNative,
SorobanRpc
} from '@stellar/stellar-sdk';
const { Api, assembleTransaction } = SorobanRpc;
const s = SorobanRpc.Server('https://soroban-testnet.stellar.org');
const kp = Keypair.random();
async function main() {
return s.getAccount(kp.publicKey()).then(account => {
const tx = new TransactionBuilder(account, { fee: BASE_FEE })
.addOperation(c.call("hello", scValToNative("world")))
.setNetworkPassphrase(Networks.TESTNET)
.setTimeout(30)
.build();
let sim: Api.SimulateTransactionResult;
sim = await s.simulateTransaction(tx);
const readyTx = assembleTransaction(tx, sim);
readyTx.sign(kp);
return s.submitTransaction(readyTx);
});
}
Second one should be "you can interact with [SorobanRpc]"