PaxiHub Documentation
Docs Menu
2. DApp Guide
Guide for DApp developers to connect to the PaxiHub app: if window.paxihub isn’t injected on mobile, it will deep-link to the PaxiHub Explorer; if not installed, it redirects to the appropriate app store for download.
// Check if PaxiHub is injected
if (typeof window.paxihub !== 'undefined') {
// Initialize your dApp connection...
const hub = window.paxihub;
// ...
} else if (/Mobi/.test(navigator.userAgent)) {
// Deep‑link into PaxiHub Explorer
window.location.href = `paxi://hub/explorer?url=${encodeURIComponent(window.location.href)}`;
// If not installed, go to store after 1s
setTimeout(() => {
window.location.href = 'https://paxinet.io/paxi_docs/paxihub#paxihub-application';
}, 1000);
}
3. DApp Demo
Demonstrates common operations: signing text messages, building and broadcasting transactions, transferring PAXI, PRC20 tokens, and NFTs.
3.1 Include Paxi Library
<script src="https://mainnet-api.paxinet.io/resources/js/paxi-cosmjs.umd.js"></script>
3.2 Global Variables & Helpers
// RPC / LCD endpoints
const rpc = 'https://mainnet-rpc.paxinet.io';
const lcd = 'https://mainnet-lcd.paxinet.io';
const denom = 'upaxi';
// base64 helper
const toBase64 = bytes => btoa(String.fromCharCode(...bytes));
// fetch accountNumber & sequence
async function buildCommon(chainId, address) {
const res = await fetch(`${lcd}/cosmos/auth/v1beta1/accounts/${address}`);
const { account } = await res.json();
// some endpoints nest under base_account
const ba = account.base_account || account;
return {
accountNumber: Number(ba.account_number),
sequence: Number(ba.sequence)
};
}
3.3 Sign Text Message
async function buildAndSignMessage() {
const result = await window.paxihub.paxi.signMessage(
"Sign this message to continue"
);
return result;
}
3.4 Build Transaction
async function buildAndSendTx(messages, memo = "") {
// fetch chainId from RPC
const chainId = await fetch(`${rpc}/status`)
.then(r => r.json())
.then(d => d.result.node_info.network);
// get sender info
const sender = await window.paxihub.paxi.getAddress();
const { accountNumber, sequence } = await buildCommon(chainId, sender.address);
// TxBody
const txBody = PaxiCosmJS.TxBody.fromPartial({ messages, memo });
// Fee
const fee = {
amount: [ PaxiCosmJS.coins("30000", denom)[0] ],
gasLimit: 600_000
};
// PubKey Any
const pubkeyBytes = new Uint8Array(sender.public_key);
const pubkeyAny = {
typeUrl: "/cosmos.crypto.secp256k1.PubKey",
value: PaxiCosmJS.PubKey.encode({ key: pubkeyBytes }).finish()
};
// AuthInfo
const authInfo = PaxiCosmJS.AuthInfo.fromPartial({
signerInfos: [{
publicKey: pubkeyAny,
modeInfo: { single: { mode: 1 } },
sequence: BigInt(sequence)
}],
fee
});
// SignDoc
const signDoc = PaxiCosmJS.SignDoc.fromPartial({
bodyBytes: PaxiCosmJS.TxBody.encode(txBody).finish(),
authInfoBytes: PaxiCosmJS.AuthInfo.encode(authInfo).finish(),
chainId,
accountNumber: BigInt(accountNumber)
});
// ask wallet to sign & send
const txObj = {
bodyBytes: btoa(String.fromCharCode(...signDoc.bodyBytes)),
authInfoBytes: btoa(String.fromCharCode(...signDoc.authInfoBytes)),
chainId,
accountNumber: signDoc.accountNumber.toString()
};
const result = await window.paxihub.paxi.signAndSendTransaction(txObj);
const sigBytes = Uint8Array.from(atob(result.success), c => c.charCodeAt(0));
// assemble TxRaw
const txRaw = PaxiCosmJS.TxRaw.fromPartial({
bodyBytes: signDoc.bodyBytes,
authInfoBytes: signDoc.authInfoBytes,
signatures: [ sigBytes ]
});
const txBytes = PaxiCosmJS.TxRaw.encode(txRaw).finish();
const base64Tx = toBase64(txBytes);
// broadcast
const broadcastResult = await fetch(`${lcd}/cosmos/tx/v1beta1/txs`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ tx_bytes: base64Tx, mode: "BROADCAST_MODE_SYNC" })
}).then(r => r.json());
document.getElementById("output").textContent =
JSON.stringify(broadcastResult, null, 2);
}
3.5 Transfer PAXI
async function buildAndSendMsgSend() {
const sender = await window.paxihub.paxi.getAddress();
const to = sender.address; // self-send for demo
const msg = PaxiCosmJS.MsgSend.fromPartial({
fromAddress: sender.address,
toAddress: to,
amount: [PaxiCosmJS.coins("1234567", denom)[0]]
});
const anyMsg = PaxiCosmJS.Any.fromPartial({
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
value: PaxiCosmJS.MsgSend.encode(msg).finish()
});
await buildAndSendTx([ anyMsg ], "MsgSend Test");
}
3.6 Transfer PRC-20 Token
async function buildAndSendMsgExecutePRC20() {
const sender = await window.paxihub.paxi.getAddress();
const contract = "<YOUR_PRC20_CONTRACT_ADDR>";
const msgObj = { transfer: { recipient: sender.address, amount: "<AMOUNT>" } };
const msg = PaxiCosmJS.MsgExecuteContract.fromPartial({
sender, contract,
msg: new TextEncoder().encode(JSON.stringify(msgObj))
});
const anyMsg = PaxiCosmJS.Any.fromPartial({
typeUrl: "/cosmwasm.wasm.v1.MsgExecuteContract",
value: PaxiCosmJS.MsgExecuteContract.encode(msg).finish()
});
await buildAndSendTx([ anyMsg ], "Execute PRC-20 Transfer");
}
3.7 Transfer NFT
async function buildAndSendMsgExecuteNFT() {
const sender = await window.paxihub.paxi.getAddress();
const nftContract = "<YOUR_NFT_CONTRACT_ADDR>";
const msgObj = { transfer_nft: { recipient: sender.address, token_id: "<TOKEN_ID>" } };
const msg = PaxiCosmJS.MsgExecuteContract.fromPartial({
sender, contract: nftContract,
msg: new TextEncoder().encode(JSON.stringify(msgObj))
});
const anyMsg = PaxiCosmJS.Any.fromPartial({
typeUrl: "/cosmwasm.wasm.v1.MsgExecuteContract",
value: PaxiCosmJS.MsgExecuteContract.encode(msg).finish()
});
await buildAndSendTx([ anyMsg ], "Execute NFT Transfer");
}
3.8 Swap PRC-20 to PAXI
async function fetchPool(contractAddress) {
try {
const url = `${lcd}/paxi/swap/pool/${contractAddress}`;
const res = await fetch(url);
if (!res.ok) throw new Error('Fetch pool failed');
return res.json();
} catch (e) {
console.error('[fetchPool]', e);
return null;
}
}
async function buildAndSendSwapMsg() {
const prc20 = "<YOUR_PRC20_CONTRACT_ADDR>";
const swapModuleAddress = "paxi1mfru9azs5nua2wxcd4sq64g5nt7nn4n80r745t";
const offerDenom = prc20;
const offerAmount = "<AMOUNT>";
const senderInfo = await window.paxihub.paxi.getAddress();
const sender = senderInfo.address;
// fecth pool inforamtion and calculate expected receive
const pool = await fetchPool(prc20);
const reservePaxi = parseFloat(pool['reserve_paxi']);
const reservePrc20 = parseFloat(pool['reserve_prc20']);
// max slippage is 50%
const minReceive = Math.floor(offerAmount * (reservePaxi / reservePrc20) * 0.5);
// optionally increase PRC20 allowance if PRC20==native denom
const msgs = [];
if (prc20 === offerDenom) {
const allowanceMsg = {
increase_allowance: {
spender: swapModuleAddress, // Address of Swap Module Address
amount: String(offerAmount)
}
};
const exec1 = PaxiCosmJS.MsgExecuteContract.fromPartial({
sender: sender,
contract: prc20,
msg: new TextEncoder().encode(JSON.stringify(allowanceMsg)),
});
msgs.push(PaxiCosmJS.Any.fromPartial({
typeUrl: "/cosmwasm.wasm.v1.MsgExecuteContract",
value: PaxiCosmJS.MsgExecuteContract.encode(exec1).finish()
}));
}
// create the actual swap message
const swapMsg = {
creator: sender,
prc20: prc20,
offerDenom: offerDenom,
offerAmount:String(offerAmount),
minReceive: String(minReceive)
};
// Note: adjust typeUrl if your protobuf path differs
const swapExec = PaxiCosmJS.MsgSwap.fromPartial(swapMsg);
msgs.push(PaxiCosmJS.Any.fromPartial({
typeUrl: "/x.swap.types.MsgSwap",
value: PaxiCosmJS.MsgSwap.encode(swapExec).finish()
}));
// broadcast
await buildAndSendTx(msgs, `Swap ${offerAmount} ${offerDenom}`);
}