Package Exports
- open-libra-sdk
Readme
open-libra-sdk
A minimalist Typescript library for interacting with the Open Libra blockchain.
npm install open-libra-sdkhttps://www.npmjs.com/package/open-libra-sdk
Quick Start
// Uses LibraWallet for common account operations
import { LibraWallet, Network, addressFromString } from 'open-libra-sdk'
const TESTNET_URL = "https://testnet.openlibra.io/v1";
const MNEM = "your mnemonic..."
// For mainnet, just initialize with your mnemonic
const wallet_mainnet = LibraWallet.fromMnemonic(MNEM);
// optionally, connect to a local testnet, by adding vars
const wallet = LibraWallet.fromMnemonic(MNEM, Network.TESTNET, TESTNET_URL);
// check your connection to the fullnode
const ledgerInfo = await wallet.client?.getLedgerInfo();
console.log("block height:", ledgerInfo?.block_height);
// get the account's state from chain
await wallet.syncOnchain();
// parse an address which you'd like to send a tx to
const addressObj = addressFromString(
"0xDECAFC0FFEE",
);
// use the transfer helper function
const tx = await wallet.buildTransferTx(addressObj, 100);
// wait for the result
const res = await wallet.signSubmitWait(tx);
if (res.success == false) {
throw "Tx fails"
}Common Operations
Create a client
You may not need to instantiate a wallet to check the chain status. Below you can check you can connect to a fullnode, and get the API index with latest block info
import { LibraClient, Network } from 'open-libra-sdk'
const TESTNET_URL = "https://testnet.openlibra.io/v1";
// for mainnet
const client_mainnet = new LibraClient();
// local testnet
const client_testnet = new LibraClient(Network.TESTNET, TESTNET_URL);
const ledgerInfo = await client_testnet.getLedgerInfo();
console.log("block height:", ledgerInfo.block_height);
expect(Number(ledgerInfo.block_height)).toBeGreaterThan(0);
// Advanced:
// You can reuse this client instance to create a LibraWallet instance for a user.
// First get the Ed25519Account type, in this case generated:
const edAccount = Ed25519Account.generate()
// then init a wallet
const wallet = LibraWallet.fromPrivateKey(edAccount.accountAddress, edAccount.privateKey, client_testnet);
// now you can use the wallet to interact with the chain
const id = await wallet.client?.general.getChainId();
console.log("chain id:", id);Querying Latest Blocks and Transaction Versions
You can easily query the latest blocks and transaction versions using the SDK helpers:
import { LibraClient, Network, getLatestBlocks, getLatestTxVersions } from "open-libra-sdk";
// Create a client for MAINNET (or TESTNET, as needed)
const client = new LibraClient(Network.MAINNET);
// Query the latest 5 blocks
const latestBlocks = await getLatestBlocks(client, 5);
console.log("Latest 5 blocks:\n", JSON.stringify(latestBlocks, null, 2));
// Query the latest 5 transaction versions (all types)
const latestVersions = await getLatestTxVersions(client, 5, false);
console.log("Latest 5 transaction versions (all types):\n", JSON.stringify(latestVersions, null, 2));
// Query the latest 5 user transactions only
const latestUserTxs = await getLatestTxVersions(client, 5, true);
console.log("Latest 5 user transactions only:\n", JSON.stringify(latestUserTxs, null, 2));Initialize a wallet
// You can construct the wallet object for offline (cold wallet)
// cases as well as online wallets to update state and submit transactions
// COLD WALLETS
// simple case: cold wallet, where no key rotation happened
const coldWalletFromMnem = LibraWallet.fromMnemonic(MNEM);
console.log("address:", coldWalletFromMnem.getAddress().toStringLong());
// set specific private key and address: in case of key rotation
const addressObj = addressFromString("0xDECAFC0FFEE");
const pkey = new Ed25519PrivateKey("0x74f18da2b80b1820b58116197b1c41f8a36e1b37a15c7fb434bb42dd7bdaa66b");
const coldWalletWithKey = LibraWallet.fromPrivateKey(
addressObj,
pkey,
);
console.log(
"other address:",
coldWalletWithKey.getAddress().toStringLong(),
);
// ONLINE WALLETS
const mainnetHotWallet = LibraWallet.fromMnemonic(
MNEM,
Network.MAINNET,
MAINNET_URL,
);
console.log("fullnode url:", mainnetHotWallet.client?.config.fullnode);
// Online wallet, using testnet
const testnetHotWallet = LibraWallet.fromMnemonic(
MNEM,
Network.TESTNET,
TESTNET_URL,
);
// Get the latest account state.
// Checks if key is rotated and update the LibraWallet.onchainAddress
// will also update to the most recent sequence number found on chain
// plus if the authentication key was changed
await testnetHotWallet.syncOnchain().then(() => {
console.log(
"sequence number:",
testnetHotWallet.txOptions.accountSequenceNumber,
);
});Build transactions for Entry Functions
Using the same wallet function above you can build arbitrary "entry functions" which call onchain smart contracts.
// ... continued from above
const tx = await testnetHotWallet.buildTransaction(
"0x1::ol_account::transfer",
[
// address string (here's a good practice to check address parsing)
addressFromString("0x1234").toStringLong(),
// number of coins
100,
],
);
const res = await testnetHotWallet.signSubmitWait(tx);
if (res.success == false) {
throw "Tx failed";
}
Or use the transfer helper for simple account transfers.
// ... continued from above
// remember to update the account sequence number like so:
await testnetHotWallet.syncOnchain();
// send another transaction
const tx2 = await testnetHotWallet.buildTransferTx(
addressFromString("0xabcde"),
100,
);
const res2 = await testnetHotWallet.signSubmitWait(tx2);
if (res2.success == false) {
throw "Tx failed";
}Fetch Arbitrary Data
You can define a Typescript type, and the Libra.getResource will coerce the type in typescript
import { LibraClient, Network } from 'open-libra-sdk'
const TESTNET_URL = "https://testnet.openlibra.io/v1";
const libra = new LibraClient(Network.TESTNET, TESTNET_URL);
interface Coin {
coin: {
value: number;
};
}
const res = await libra.getResource<Coin>(
// alice
"0x87515d94a244235a1433d7117bc0cb154c613c2f4b1e67ca8d98a542ee3f59f5",
"0x1:🪙:CoinStore<0x1::libra_coin::LibraCoin>",
);
if (res.coin.value == 0) {
throw "no coin found"
}Troubleshooting
There's a known issue when executing using bun. Calling a fullnode with an https url API will fail. Since http/2 is not fully developed in bun as of 1.2.2.
NodeJS (with npm, yarn, pnpm) does not appear to produce this error. Deno is untested.
Flavors
Look in the ./examples folder for commonjs, Node, and typescript imports of the module.
In a common JS file you can import the sdk to manage wallets and query the chain. See the minimal example:
// Example for how common js would import the sdk
const libraSDK = require('open-libra-sdk');
const main = async () => {
const mnem = libraSDK.generateMnemonic();
console.log("Generate a mnemonic:\n");
console.log(mnem, "\n");
let coldWallet = libraSDK.LibraWallet.fromMnemonic(mnem);
console.log(coldWallet.getAddress().toStringLong())
let client = new libraSDK.LibraClient(libraSDK.Network.MAINNET);
console.log(`Client created for: ${client.config.network}`);
// call a view function with a helper object that contains the
// payload for querying the current validators
// let vals = await client.general.viewJson(libraSDK.currentValidatorsPayload);
// console.log(vals);
}
main()
Testnet in a bottle
Start a containerized testnet with docker etc.
This repo contains a tests/support/container/compose.yml which will create a three node testnet with production binaries.
# with npm/yarn/bun:
bun run testnet
bun run testnet-down
## call docker directly with:
cd tests/support/container
docker compose up --detach --timeout 600
docker compose downMaintainers
Bun
bun is the default Node/JS/TS runtime for OL development.
https://bun.sh/docs/installation
To install dependencies:
bun installTo run tests:
bun testEnd to end tests will start a local testnet before each test, and requires docker be installed.
Documentation
The examples references in README.md must all be tested at: ./tests/e2e_tests/docs.tests.ts
Updating the View Function Sugar File (For Core Maintainers)
Before each release, you should regenerate the TypeScript view function sugar file to ensure it reflects the latest Move modules and view functions.
Steps:
Ensure your Move source files are up to date.
- The script expects a directory containing your
.movefiles (e.g.,./my-move-modules).
- The script expects a directory containing your
Run the codegen script:
bun ./scripts/viewCodeGen.ts <PATH_TO_MOVE_DIR>
- Replace
<PATH_TO_MOVE_DIR>with the path to your Move modules directory. - Example:
bun ./scripts/viewCodeGen.ts ./my-move-modules
- Replace
Check the output:
- The generated file will be at
./src/views/viewFunctionsSugar.ts. - Review the file for correctness if needed.
- The generated file will be at
Commit the updated file:
- Add and commit
src/views/viewFunctionsSugar.tsto your release branch.
- Add and commit
Notes
- The script will overwrite the existing sugar file.
- If you add, remove, or change any
#[view]functions in your Move code, you must regenerate this file before release. - The generated file uses local imports for development and will work out of the box with the rest of the TypeScript SDK.