このページの翻訳は LLM によって生成されています。誤りに気づいた場合は GitHub で issue を開いてお知らせください。
Sai WASM連携ガイド
NibiruTxClient でCosmos、WASM側からSaiを操作する一連の手順です。
0. はじめに
Section titled “0. はじめに”- Node.js ≥ 18。
- pnpm、npm、yarnのいずれか。
新しいプロジェクト
Section titled “新しいプロジェクト”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. 担保・支払いトークン”小数桁の処理
Section titled “小数桁の処理”BANKは既定で小数6桁です。表示額に10^6を掛けて変換してください。
Testnet-2
Section titled “Testnet-2”| トークン | Bankデノム |
|---|---|
| USDC | tf/nibi1pc2mmwcqhvzn9vsm0umpu40yzl6gfy6nucwn7g/usdc |
| stNIBI | tf/nibi1pc2mmwcqhvzn9vsm0umpu40yzl6gfy6nucwn7g/stnibi |
メインネット
Section titled “メインネット”| トークン | Bankデノム |
|---|---|
| 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. 無期限先物の新規注文”メッセージ構造
Section titled “メッセージ構造”{ "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に現在の市場価格を設定します。 - 指値・逆指値ではトリガー価格を設定します。
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. 紹介コードの作成・適用”紹介コードの作成
Section titled “紹介コードの作成”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)}紹介コードの適用
Section titled “紹介コードの適用”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)}持分デノムの取得
Section titled “持分デノムの取得”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 “エラー処理と問題の解決”よくある問題
Section titled “よくある問題”| 問題 | 解決方法 |
|---|---|
| ”No account found” | ニーモニックと NibiruTxClient 初期化を確認 |
| ”Insufficient funds” | BANK単位の残高を確認 |
| ”Invalid denom” | bankDenom がネットワークに合うか確認 |
| ”Contract not found” | ネットワークのコントラクトアドレスを確認 |
| 小数桁の変換 | WASMに渡す前に10^6倍 |
| タイムアウト | 待機時間を増やすかRPC接続を確認 |
- 実行前に
NibiruTxClientの接続を確認します。 - 数量がBANK単位の非負整数か検証します。
- 特別な要件がなければガス推定に
"auto"を使います。 - ニーモニックを安全に保ち、Gitにコミットしてはいけません。
- パラメーターを推測せず、状態を取得してください。
- メインネットの前にTestnet-2で試してください。
デバッグのヒント
Section titled “デバッグのヒント”client.getTx(transactionHash)で詳細を確認。- 結果の詳しいエラー原因を確認。
console.log()で処理を追跡。- 応答のガス使用量・手数料を確認。