Get Started with xplajs
xplajs seeks to provide a compatible way to work with the XPLA Chain within JavaScript runtimes, such as Node.js and the browser. xplajs enables the following functions:
- Deserializing blockchain data into JavaScript objects with native data types and methods
- Serializing objects back into a blockchain-compatible format
- Providing access to the XPLA Chain RPC from a JavaScript-based interface
- Providing additional utilities, such as hash functions and key-signing algorithms
About This Tutorial
This is an in-depth guide on how to use the xplajs SDK.
In this tutorial, you’ll learn how to:
- Set up your project
- Initialize the RPC
- Create and connect a wallet
- Find a contract address
- Query a contract
- Broadcast the Transaction
By the end of this guide, you’ll be able to execute a token swap from your application using xplajs.
Prerequisites
- yarn and node.js
- XPLA extension vault
1. Set up Your Project
Create a new directory for your project:
mkdir my-xplajs-projectEnter your new project directory:
cd my-xplajs-projectNext, initialize yarn, install the
xplajspackage, and create anindex.jsfile to house the code:corepack enable yarn init -y yarn add @xpla/xplajs @xpla/xpla touch index.tsThe
@xpla/xplajspackage provides the core functionality for interacting with the XPLA Chain, while@xpla/xplacontains the signing and transaction utilities.Note for Yarn Berry users
If you’re using Yarn Berry (Yarn 2+), you need to add
nodeLinker: node-modulesto your.yarnrc.yamlfile. PnP (Plug’n’Play) mode is currently not supported.# .yarnrc.yaml nodeLinker: node-modulesOpen the
package.jsonfile in a code editor and add"type": "module",.{ // ... "type": "module", // ... }
2. Initialize the RPC
XPLA Chain’s RPC allows users to connect to the blockchain, make queries, create wallets, and submit transactions. It’s the main workhorse behind xplajs.
Open your
index.jsfile in a code editor and input the following to initialize the RPC:import { createRPCQueryClient } from "@xpla/xplajs/xpla/rpc.query"; const rpc = await createRPCQueryClient({ rpcEndpoint: "https://cube-rpc.xpla.io" // Use "https://dimension-rpc.xpla.io" for prod });The
createRPCQueryClientfunction establishes a connection to the XPLA Chain RPC endpoint, allowing you to query blockchain data and submit transactions. This replaces the older LCD (Light Client Daemon) approach with a more direct RPC connection.Note
The previous code block shows how to connect to the cube testnet. To connect to the dimension_37-1 mainnet for production, use “
https://dimension-rpc.xpla.io”.
3. Create a Cube Testnet Wallet
You’ll need a wallet to sign and submit transactions. Create a new wallet using the XPLA extension vault. Be sure to save your mnemonic key!
After creating your wallet, you’ll need to set it to use the testnet. Click the gear icon in the extension and change the network from
mainnettotestnet.Add the following code to your
index.tsfile and input your mnemonic key:import { DEFAULT_COSMOS_EVM_SIGNER_CONFIG, EthSecp256k1HDWallet } from "@xpla/xpla" import { HDPath } from "@interchainjs/types" import { createCosmosQueryClient, DirectSigner } from "@interchainjs/cosmos"; const queryClient = await createCosmosQueryClient("https://cube-rpc.xpla.io"); const mnemonic = "-> Input your 24-word mnemonic key here <-"; const wallet = await EthSecp256k1HDWallet.fromMnemonic(mnemonic, {derivations: [{ prefix: "xpla", hdPath: HDPath.eth().toString() }]}); const baseSignConfig = { queryClient: queryClient, chainId: "cube_47-5", addressPrefix: "xpla", } const signerConfig = { ...DEFAULT_COSMOS_EVM_SIGNER_CONFIG, ...baseSignConfig } const signer = new DirectSigner(wallet, signerConfig); const signerAddress = (await signer.getAddresses())[0]This code creates a wallet instance using the new xplajs architecture. The
EthSecp256k1Authhandles authentication using your mnemonic phrase, whileDirectSignerprovides the signing capabilities.Important: The
toEncoders(MsgExecuteContract)function is crucial for transaction signing. It registers theMsgExecuteContractmessage type with the signer, enabling it to properly encode and sign this specific type of transaction. Without this registration, the signer won’t know how to handle the message format, and your transactions will fail. If you need to use other message types (likeMsgSend,MsgDelegate, etc.), you must include them in thetoEncodersfunction as well:toEncoders(MsgExecuteContract, MsgSend, MsgDelegate).The
Network.Testnet.rpcspecifies the testnet configuration for the signer.For AMINO encoding, refer to the XPLA Network Configuration Guide.
Warning
Although this tutorial has you input your mnemonic directly, this practice should be avoided in production. For security reasons, it’s better to store your mnemonic key data in your environment by using
process.env.SECRET_MNEMONICorprocess.env.SECRET_PRIV_KEY. This practice is more secure than a hard-coded string.Request testnet funds for your wallet by navigating to the XPLA faucet and inputting your wallet address. You’ll need these funds to perform swaps and pay for gas fees. Once the funds are in your wallet, you’re ready to move on to the next step.
4. Find a Contract Address
To find the contract address for a specific Dezswap pair Dezswap Pair API
5. Query a Dezswap Contract and Set up the Transaction
Before you can perform a swap, you’ll need a belief price. You can calculate the belief price of one token by querying simulation to the pool. The belief price +/- the max_spread is the range of possible acceptable prices for this swap.
Add the following code to your
index.tsfile. Make sure the contract address is correct.import { Decimal } from 'decimal.js'; const contract = "<POOL_CONTRACT_ADDRESS>"; // A Dezswap pair contract address const offerAmount = "1000000000000000000"; // 5.1 simulate the tx const pairResponse = await rpc.cosmwasm.wasm.v1.smartContractState({ address: contract, queryData: new TextEncoder().encode(`{"pair": {}}`) }); const { asset_decimals: assetDecimals } = JSON.parse(new TextDecoder().decode(pairResponse.data)); const res = await rpc.cosmwasm.wasm.v1.smartContractState({ address: contract, queryData: new TextEncoder().encode(`{ "simulation": { "offer_asset": { "info" : { "native_token": { "denom": "axpla" } }, "amount": "${offerAmount}" } } }`) }); const { return_amount: returnAmount } = JSON.parse(new TextDecoder().decode(res.data)); const Decimal18 = Decimal.set({ precision: 18, rounding: Decimal.ROUND_DOWN }); const beliefPrice = new Decimal18(offerAmount).dividedBy(10 ** assetDecimals[0]).dividedBy(new Decimal18(returnAmount).dividedBy(10 ** assetDecimals[1]));This code performs two key operations: first, it queries the pool contract to get asset decimals information, then it simulates the swap to calculate the expected return amount. The belief price is calculated using precise decimal arithmetic to ensure accurate swap execution. The
Decimal.jslibrary is used for high-precision calculations to avoid floating-point errors.Next, generate a message to broadcast to the network:
import { MessageComposer } from "@xpla/xplajs/cosmwasm/wasm/v1/tx.registry"; import { Coin } from "@xpla/xplajs/cosmos/base/v1beta1/coin"; const executeContractMsg = await MsgExecuteContract.fromPartial({ sender: await signer.getAddress(), contract: contract, msg: new TextEncoder().encode(`{ "swap": { "belief_price": "${beliefPrice.toString()}", "max_spread": "0.005", "offer_asset": { "info": { "native_token": { "denom": "axpla" } }, "amount": "${offerAmount}" } } }`), funds: [Coin.fromPartial({denom: "axpla", amount: offerAmount.toString()})] });This code creates the transaction message for the swap operation. The
MsgExecuteContract.fromPartialmethod constructs the message with the calculated belief price, maximum spread tolerance, and the tokens to be swapped. Themax_spreadparameter (0.5%) ensures the transaction will only execute if the actual price doesn’t deviate too much from the expected price.
6. Broadcast the Transaction
Add the following code to
index.tsto create, sign, and broadcast the transaction:import { TxBody as CosmosTxBody } from "@interchainjs/cosmos-types"; import { MessageComposer } from "@xpla/xplajs/cosmwasm/wasm/v1/tx.registry"; import { encodeCosmosEvmPublicKey } from "@xpla/xpla/signers/config"; const { executeContract } = MessageComposer.encoded; const msg = await executeContract(executeContractMsg); const txBody = CosmosTxBody.fromPartial({ messages: [msg], }) const accounts = await signer.getAccounts() const publicKey = accounts[0].getPublicKey() const publicKeyBytes = encodeCosmosEvmPublicKey(publicKey.value.value) const sequence = await signer.getSequence(signerAddress) const simulateResult = await signer.simulateByTxBody(txBody, [SignerInfo.fromPartial({ publicKey: publicKeyBytes, sequence, modeInfo: ModeInfo.fromPartial({ single: ModeInfo_Single.fromPartial({ mode: SignMode.SIGN_MODE_DIRECT }) }) })]) console.log(simulateResult)This final step completes the transaction process. The
MessageComposer.encoded.executeContractcreates the properly formatted message,simulateByTxBodysimulates the transaction to estimate gas fees, and the transaction can then be signed and broadcast to the network. The transaction will be processed by the XPLA Chain validators and the swap will be executed if all conditions are met.Run the code in your terminal:
node index.js
If successful, you’ll see a log of the successful transaction and some new tokens in your wallet.
And that’s it! You can find other pool addresses here to call other swaps. Be sure to use the correct testnet or mainnet contract address.