0.2.5 • Published 1 year ago

@usesoroban/sdk v0.2.5

Weekly downloads
-
License
Apache-2.0
Repository
github
Last release
1 year ago

Soroban JavaScript SDK

The main aim of this SDK is to provide a great developer experience while integrating and using Soroban contracts and the Stellar blockchain.

Documentation

The SDK exports the following objects. I will describe each separately.

import {
  xdr,
  Network,
  Account,
  Keys,
  Transaction,
  Operation,
  Contract
} from '@usesoroban/sdk';

xdr

This is the product of xdrgen ingesting stellar-xdr. I made the one modification where I import a browser wrapper over Buffer, which is a Node data type. The intention here was to leverage as much of what's provided by the browser as possible.

Every available Stellar xdr definition is accessible under xdr.

xdr.AccountId.publicKeyTypeEd25519(...);
xdr.ScVal.scvU32(42);
// ...

You can explore the Stellar/Soroban XDR type definitions in the source code.

Network

You interact with Soroban by sending requests to compatible RPC servers. To simplify these requests, Network wraps all Soroban RPC methods.

To initialize, provide the network passphrase and the remote RPC URL.

const network = new Network(
  'Test SDF Future Network ; October 2022',
  'https://futurenet.sorobandev.com/soroban/rpc'
);

RPC calls

To interact with the Soroban RPC use these Network methods.

async getHealth();
async getAccount(account: string | Account);
async getLatestLedger();
async getLedgerEntry(key: string | XDR);
async getNetwork();
async requestAirdrop(account: Account);
async getEvents({
  startLedger: string,
  endLedger: string
});
async getTransactionStatus(transactionId: string);
async sendTransaction(transaction: Transaction | PreparedTransaction | string);
async simulateTransaction(transaction: : Transaction | PreparedTransaction | string);

Account

At the moment, this SDK has not integrated any wallet providers so the transaction signing process is done insecurely using a secret key string. However, while Soroban is in development, I felt like it was reasonable to avoid wallet integration to reduce complexity. This will change in the future.

You can initialize instances of Account by using both the address or public key as well as the secret key.

// Initialized using address, account can be used as an argument, but can't sign transactions.
const account = Account.fromKey('GALJMHIIE7LQHDMRKYLBPJ7WNAQP3V3WJUE35J46U62MM5RM7OKXIWWW');
// Initialized using secret key, can be used to sign transactions.
const account = Account.fromKey('SAEWT32IC2A77HNKNI6FJA2YQEJN24SDH6U3QVLFW2QEPQ5JZMENNCCD');

The most important ability instances of Account have is the call method. It allows calling Soroban contract functions in a very simple way.

const result = await account.call(
  contract.toggle({state: true})
);

I'll describe this in more detail later in this document.

Interace

get address(); // Stellar address encoded as string G...
sign(data: Uint8Array);
async call(invocation: {network: Network, operations: Operation[]});

Keys

Every account has associated Keys, you can access it either as account.keys or by initializing Keys directly using the factory function Keys.fromString(key: string) which takes a public or secret key string.

I'm using the TweetNaCl.js npm package to sign bytes encoded as Uint8Array. Normally, there's no need to interact with Keys directly as other objects do so under the hood.

Transaction

This is a wrapper class that allows composing Stellar transactions.

const transaction = new Transaction()
  .sourceAccount(
    Account.fromKey('SAEWT32IC2A77HNKNI6FJA2YQEJN24SDH6U3QVLFW2QEPQ5JZMENNCCD')
  )
  .operations(
    new Operation.CallContract()
      .contractId('d9d5827dc639a3a100fecc1e9ac71e7e7d59867745d5dcc2955049f5ef9c3c06')
      .functionName('on')
  );

You define a Transaction by applying the following methods.

sourceAccount(account: Account);
fee(amount: number);
preconditioncs(preconditions: Precondition[]);
operations(...operations: Operation);
operationFootprints(...footprints: string[]);

Once you're ready to sign and send it.

const preparedTransaction = await transaction.prepareFor(network: Network);
preparedTransaction.signedBy(account);
network.sendTransaction(preparedTransaction.serialized());

Or you can allow Network to take care of this and simply provide the transaction object.

network.sendTransaction(transaction);

Operation

A Transaction instance is a wrapper around Operations. When working with Soroban, you only need three types of Operations.

import {Operation} from '@usesoroban/sdk';

Operation.UploadWasm;
Operation.InstantiateContract;
Operation.CallContract;

You only UploadWasm and InstantiateContract when you're setting up. In your application you're mostly going to be using CallContract, however, there's an even better way of interacting with Soroban contracts - using the Contract class.

Contract

All you need is a contract ID.

const contract = new Contract(
  network,
  'e1ccc55518c3f2461aaa4984173286ff3374adcbbaa942ac8a40b12ec5dbc752'
);
await contract.initialize();

During a single session, instances of Contract only need to be initialized once. After that, you can easily read their contract data on the ledger.

const list = await contract.fetchStorage('LIST');

As well as call their public functions. All arguments maintain the same name as in Rust, for that purpose I'm using an object function argument.

In this case, the add function is defined in Rust.

pub fn add(env: Env, item: Symbol) -> Vec<Symbol>

While on the JavaScript client-side you call the same function using this syntax.

let result = await account.call(
  contract.add({item: 'Hello'})
);
0.2.5

1 year ago

0.2.4

1 year ago

0.2.3

1 year ago

0.2.2

1 year ago

0.2.1

1 year ago

0.2.0

1 year ago

0.1.1

1 year ago

0.1.0

1 year ago