Tài liệu PaxiHub

1. Ứng dụng PaxiHub 2.1.0

Liên kết Tải xuống
Download the APK File

2. Hướng dẫn DApp

Hướng dẫn cho nhà phát triển DApp kết nối với ứng dụng PaxiHub: nếu window.paxihub không được inject trên di động, nó sẽ liên kết sâu đến PaxiHub Explorer; nếu chưa cài đặt, nó sẽ chuyển hướng đến cửa hàng ứng dụng phù hợp để tải xuống.

// 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. Demo DApp

Trình diễn các thao tác phổ biến: ký tin nhắn văn bản, xây dựng và phát giao dịch, chuyển PAXI, token PRC20 và NFTs.

3.1 Bao gồm Thư viện Paxi
<script src="https://mainnet-api.paxinet.io/resources/js/paxi-cosmjs.umd.js"></script>
3.2 Biến Toàn cục & Trợ giúp
// 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 Ký Tin nhắn Văn bản
async function buildAndSignMessage() {
  const result = await window.paxihub.paxi.signMessage(
    "Sign this message to continue"
  );
  return result;
}
3.4 Xây dựng Giao dịch
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 Chuyển 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 Chuyển Token PRC‑20
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 Chuyển 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 Hoán đổi PRC‑20 sang 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}`);
}
3.9 Mã Demo Đầy đủ
https://mainnet-api.paxinet.io/dapp/test