A minimalist Typescript library for interacting with the Open Libra blockchain.
npm install open-libra-sdkA minimalist Typescript library for interacting with the Open Libra blockchain.
``bash`
npm install open-libra-sdk
https://www.npmjs.com/package/open-libra-sdk
typescript
// 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
`typescript
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:
`typescript
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
`typescript
// 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.
`typescript
// ... 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.`typescript
// ... 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
`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(
// alice
"0x87515d94a244235a1433d7117bc0cb154c613c2f4b1e67ca8d98a542ee3f59f5",
"0x1::coin::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:
`typescript
// 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.`bash
with npm/yarn/bun:
bun run testnet
bun run testnet-downcall docker directly with:
cd tests/support/container
docker compose up --detach --timeout 600
docker compose down
`
Maintainers
$3
bun is the default Node/JS/TS runtime for OL development.https://bun.sh/docs/installation
$3
`bash
bun install
`$3
`bash
bun test
`End to end tests will start a local testnet before each test, and requires
docker be installed.$3
The examples references in README.md must all be tested at: ./tests/e2e_tests/docs.tests.tsUpdating 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.
$3
1. Ensure your Move source files are up to date.
- The script expects a directory containing your
.move files (e.g., ./my-move-modules).2. Run the codegen script:
`sh
bun ./scripts/viewCodeGen.ts
`
- Replace with the path to your Move modules directory.
- Example:
`sh
bun ./scripts/viewCodeGen.ts ./my-move-modules
`3. Check the output:
- The generated file will be at
./src/views/viewFunctionsSugar.ts.
- Review the file for correctness if needed.4. Commit the updated file:
- Add and commit
src/views/viewFunctionsSugar.ts to your release branch.$3
- 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.