本页面的翻译由 LLM 生成。如果你发现翻译有误,请在 GitHub 上提交 issue 告诉我们。
Sai WASM 集成指南
使用 NibiruTxClient 从 Cosmos、WASM 侧与 Sai 交互的完整指南。
0. 开始使用
Section titled “0. 开始使用”- Node.js ≥ 18。
- pnpm、npm 或 yarn。
mkdir sai-wasm && cd sai-wasmpnpm init -ypnpm add @nibiruchain/nibijs @cosmjs/cosmwasm-stargate @cosmjs/stargate cosmjs-types bignumber.jspnpm add -D typescript ts-node @types/node dotenvnpx tsc --init --target ES2022 --module NodeNext --moduleResolution NodeNext创建包含配置的 .env。
# Testnet-2NIBI_RPC=https://rpc.testnet-2.nibiru.fi/
# Or Mainnet# NIBI_RPC=https://rpc.nibiru.fi/
MNEMONIC="word1 word2 ... word12" # Your wallet mnemonic (keep this secret!)初始化客户端
Section titled “初始化客户端”import "dotenv/config"import { NibiruTxClient } from "@nibiruchain/nibijs"
export async function makeNibiruTxClient() { const rpc = process.env.NIBI_RPC! const mnemonic = process.env.MNEMONIC! const client = await NibiruTxClient.connectWithSignerFromMnemonic(rpc, mnemonic) const account = (await client.signer.getAccounts())[0] return { client, bech32: account.address }}1. 抵押资产与支付代币
Section titled “1. 抵押资产与支付代币”BANK 默认 6 位小数,显示金额须乘 10^6 转换。
Testnet-2
Section titled “Testnet-2”| 代币 | Bank Denom |
|---|---|
| USDC | tf/nibi1pc2mmwcqhvzn9vsm0umpu40yzl6gfy6nucwn7g/usdc |
| stNIBI | tf/nibi1pc2mmwcqhvzn9vsm0umpu40yzl6gfy6nucwn7g/stnibi |
| 代币 | Bank Denom |
|---|---|
| USDC | erc20/0x0829F361A05D993d5CEb035cA6DF3446b060970b |
| stNIBI | tf/nibi1udqqx30cw8nwjxtl4l28ym9hhrp933zlq8dqxfjzcdhvl8y24zcqpzmh8m/ampNIBI |
将显示金额转换为 BANK 单位
Section titled “将显示金额转换为 BANK 单位”import BigNumber from "bignumber.js"
const displayAmount = new BigNumber("100") // 100 USDCconst bankAmount = displayAmount.times(1e6).integerValue().toString()// Result: "100000000" (100 * 10^6)2. 永续合约开仓
Section titled “2. 永续合约开仓”{ "open_trade": { "market_index": "MarketIndex(N)", "leverage": "string (e.g., '5')", "long": true, "collateral_index": "TokenIndex(N)", "trade_type": "trade|limit|stop", "open_price": "<market or limit price>", "slippage_p": "0.01", "tp": "optional take-profit", "sl": "optional stop-loss", "is_evm_origin": false }}slippage_p 是 CosmWasm Decimal 比例,"0.01" 表示 1%。
- 市价交易的
open_price设为当前市场价。 - 限价、止损入场的
open_price设为触发价。
import BigNumber from "bignumber.js"import { Coin } from "cosmjs-types/cosmos/base/v1beta1/coin"import { makeNibiruTxClient } from "./wasmClient"
async function openTrade() { const { client, bech32 } = await makeNibiruTxClient()
// Contract addresses (from chain config) const saiPerp = "<saiContracts.perp>" // bech32 address const bankDenom = "tf/nibi1pc2mmwcqhvzn9vsm0umpu40yzl6gfy6nucwn7g/usdc" // Testnet-2 USDC
// Convert 100 USDC to BANK units const display = new BigNumber("100") const amount = display.times(1e6).integerValue().toString() // "100000000"
const msg = { open_trade: { market_index: "MarketIndex(0)", leverage: "5", long: true, collateral_index: "TokenIndex(0)", trade_type: "trade", open_price: "70000", slippage_p: "0.01", is_evm_origin: false, }, }
const res = await client.wasmClient.execute( bech32, saiPerp, msg, "auto", undefined, [Coin.fromPartial({ denom: bankDenom, amount })] )
console.log("Transaction hash:", res.transactionHash) console.log("Gas used:", res.gasUsed)}3. 永续合约平仓
Section titled “3. 永续合约平仓”关闭未平仓仓位。
import { makeNibiruTxClient } from "./wasmClient"
async function closeTrade() { const { client, bech32 } = await makeNibiruTxClient() const saiPerp = "<saiContracts.perp>"
const res = await client.wasmClient.execute( bech32, saiPerp, { close_trade: { trade_index: "UserTradeIndex(0)", }, }, "auto" )
console.log("Trade closed in tx:", res.transactionHash)}4. 创建和使用推荐码
Section titled “4. 创建和使用推荐码”async function createReferralCode() { const { client, bech32 } = await makeNibiruTxClient() const saiPerp = "<saiContracts.perp>"
const res = await client.wasmClient.execute( bech32, saiPerp, { create_referrer_code: { code: "MYCODE", }, }, "auto" )
console.log("Referral code created in tx:", res.transactionHash)}async function redeemReferralCode() { const { client, bech32 } = await makeNibiruTxClient() const saiPerp = "<saiContracts.perp>"
const res = await client.wasmClient.execute( bech32, saiPerp, { redeem_referrer_code: { code: "PARTNER", }, }, "auto" )
console.log("Referral code redeemed in tx:", res.transactionHash)}5. 金库充值
Section titled “5. 金库充值”向金库存入抵押资产。
import BigNumber from "bignumber.js"import { Coin } from "cosmjs-types/cosmos/base/v1beta1/coin"import { makeNibiruTxClient } from "./wasmClient"
async function depositToVault() { const { client, bech32 } = await makeNibiruTxClient()
const vaultAddr = "<vault bech32 address>" const bankDenom = "tf/nibi1pc2mmwcqhvzn9vsm0umpu40yzl6gfy6nucwn7g/usdc" // Testnet-2 USDC
// Convert 250 USDC to BANK units const amount = new BigNumber("250") .times(1e6) .integerValue() .toString()
const res = await client.wasmClient.execute( bech32, vaultAddr, { deposit: {} }, "auto", undefined, [Coin.fromPartial({ denom: bankDenom, amount })] )
console.log("Deposited to vault in tx:", res.transactionHash)}6. 金库提现申请
Section titled “6. 金库提现申请”申请从金库提现。
import { Coin } from "cosmjs-types/cosmos/base/v1beta1/coin"import { makeNibiruTxClient } from "./wasmClient"
async function makeWithdrawRequest() { const { client, bech32 } = await makeNibiruTxClient()
const vaultAddr = "<vault bech32 address>"
// First, query the vault to get the share denom const shareDenom = await client.wasmClient.queryContractSmart(vaultAddr, { get_vault_share_denom: {}, })
console.log("Share denom:", shareDenom)
// Request to withdraw 1.0 share (1,000,000 in BANK units) const res = await client.wasmClient.execute( bech32, vaultAddr, { make_withdraw_request: {} }, "auto", undefined, [Coin.fromPartial({ denom: shareDenom, amount: "1000000" })] )
console.log("Withdraw request created in tx:", res.transactionHash)}7. 金库赎回
Section titled “7. 金库赎回”赎回金库份额。
import { makeNibiruTxClient } from "./wasmClient"
async function redeemVaultShares() { const { client, bech32 } = await makeNibiruTxClient()
const vaultAddr = "<vault bech32 address>"
// Redeem 0.5 shares (500,000 in BANK units) const res = await client.wasmClient.execute( bech32, vaultAddr, { redeem: { shares: "500000", }, }, "auto" )
console.log("Shares redeemed in tx:", res.transactionHash)}8. 取消提现申请
Section titled “8. 取消提现申请”取消待处理提现申请。
import { makeNibiruTxClient } from "./wasmClient"
async function cancelWithdrawRequest() { const { client, bech32 } = await makeNibiruTxClient()
const vaultAddr = "<vault bech32 address>"
const res = await client.wasmClient.execute( bech32, vaultAddr, { cancel_withdraw_request: { unlock_epoch: 123, // Replace with actual unlock epoch }, }, "auto" )
console.log("Withdraw request cancelled in tx:", res.transactionHash)}查询份额 denom
Section titled “查询份额 denom”async function getVaultShareDenom() { const { client } = await makeNibiruTxClient() const vaultAddr = "<vault bech32 address>"
const shareDenom = await client.wasmClient.queryContractSmart(vaultAddr, { get_vault_share_denom: {}, })
console.log("Share denom:", shareDenom) return shareDenom}查询用户交易
Section titled “查询用户交易”async function getUserTrades() { const { client, bech32 } = await makeNibiruTxClient() const saiPerp = "<saiContracts.perp>"
const trades = await client.wasmClient.queryContractSmart(saiPerp, { get_user_trades: { user: bech32, }, })
console.log("User trades:", trades) return trades}查询金库信息
Section titled “查询金库信息”async function getVaultInfo() { const { client } = await makeNibiruTxClient() const vaultAddr = "<vault bech32 address>"
const info = await client.wasmClient.queryContractSmart(vaultAddr, { get_info: {}, })
console.log("Vault info:", info) return info}错误处理与排查
Section titled “错误处理与排查”| 问题 | 解决方法 |
|---|---|
| ”No account found” | 检查助记词和 NibiruTxClient 初始化 |
| ”Insufficient funds” | 确认钱包有足够 BANK 单位余额 |
| ”Invalid denom” | 检查 bankDenom 对应网络 |
| ”Contract not found” | 检查网络合约地址 |
| 小数转换错误 | 传给 WASM 前乘 10^6 |
| 交易超时 | 增加超时或检查 RPC 连接 |
- 执行前确认
NibiruTxClient已连接。 - 验证数量是 BANK 单位的非负整数。
- 无特殊 Gas 要求时使用
"auto"。 - 安全保存助记词,不得提交到版本控制。
- 对参数作假设前先查询状态。
- 主网上线前先在 Testnet-2 测试。
- 用
client.getTx(transactionHash)检查详情。 - 查看结果中的详细错误。
- 用
console.log()追踪流程。 - 检查响应中的 Gas 使用和费用。