Skip to main content
Glama
oraichainSubmitTx.ts6.49 kB
import { createWasmAminoConverters, SigningCosmWasmClient, wasmTypes, } from "@cosmjs/cosmwasm-stargate"; import { DirectSecp256k1HdWallet, Registry } from "@cosmjs/proto-signing"; import { AminoTypes, Coin, createDefaultAminoConverters, defaultRegistryTypes, GasPrice, } from "@cosmjs/stargate"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; import { ORAI } from "@oraichain/common"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { toBase64, toHex } from "@cosmjs/encoding"; import { setTimeout } from "timers/promises"; import assert from "assert"; import { makeSignDoc, Secp256k1HdWallet } from "@cosmjs/amino"; import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx"; import { sha256 } from "@cosmjs/crypto"; (async () => { // setup SSE Server for testing const transport = new SSEClientTransport( new URL("http://localhost:8080/sse"), ); const sseClient = new Client({ name: "test-client", version: "0.0.1" }); await sseClient.connect(transport); await testSignAndBroadcastDirectTx(sseClient); await testSignAndBroadcastAminoTx(sseClient); await testSignAndBroadcastTxBytes(sseClient); // close transport & connection await sseClient.close(); })(); async function testSignAndBroadcastDirectTx(sseClient: Client) { // setup wallet to sign const wallet = await DirectSecp256k1HdWallet.fromMnemonic( process.env.MNEMONIC!, { prefix: "orai" }, ); const accounts = await wallet.getAccounts(); const client = await SigningCosmWasmClient.connectWithSigner( process.env.RPC_URL!, wallet, { gasPrice: GasPrice.fromString("0.0001orai"), registry: new Registry([...defaultRegistryTypes, ...wasmTypes]), }, ); const transferMessageResult = await sseClient.callTool({ name: "TOKEN_TRANSFER_ACTION", arguments: { senderAddress: accounts[0].address, recipient: accounts[0].address, amount: { amount: "1", denom: ORAI } as Coin, }, }); const message = JSON.parse( (transferMessageResult.content as any)[0].text, ).data; const txRaw = await client.sign( accounts[0].address, [message], { amount: [{ amount: "0", denom: ORAI }], gas: "20000000" }, "", ); const txHashData = await sseClient.callTool({ name: "BROADCAST_SIGNED_TX_FROM_SIGNED_BYTES_AND_SIGNATURE_ACTION", arguments: { signedBodyBytes: toBase64(txRaw.bodyBytes), signedAuthBytes: toBase64(txRaw.authInfoBytes), signatures: txRaw.signatures.map((sig) => toBase64(sig)), }, }); const txHash = JSON.parse((txHashData.content as any)[0].text).data.txHash; await setTimeout(2000); const txHashInfo = await client.getTx(txHash); assert(txHashInfo !== null); assert(txHashInfo.code === 0); assert(txHashInfo.hash === txHash); } async function testSignAndBroadcastAminoTx(sseClient: Client) { // sign amino tx const legacyWallet = await Secp256k1HdWallet.fromMnemonic( process.env.MNEMONIC!, { prefix: "orai" }, ); const accounts = await legacyWallet.getAccounts(); const client = await SigningCosmWasmClient.connectWithSigner( process.env.RPC_URL!, legacyWallet, { gasPrice: GasPrice.fromString("0.0001orai"), registry: new Registry([...defaultRegistryTypes, ...wasmTypes]), }, ); const signer = accounts[0]; // get transfer message const transferMessageResult = await sseClient.callTool({ name: "TOKEN_TRANSFER_ACTION", arguments: { senderAddress: accounts[0].address, recipient: accounts[0].address, amount: { amount: "1", denom: ORAI } as Coin, }, }); const message = JSON.parse( (transferMessageResult.content as any)[0].text, ).data; // prep signing data for amino signing const { accountNumber, sequence } = await client.getSequence(signer.address); const chainId = await client.getChainId(); const signerData = { accountNumber: accountNumber, sequence: sequence, chainId: chainId, }; const aminoTypes = new AminoTypes({ ...createDefaultAminoConverters(), ...createWasmAminoConverters(), }); const aminoMsg = aminoTypes.toAmino(message); const signedDoc = await legacyWallet.signAmino( signer.address, makeSignDoc( [aminoMsg], { amount: [{ amount: "0", denom: ORAI }], gas: "20000000" }, chainId, "", accountNumber, sequence, ), ); // broadcast amino tx // get transfer message const txHashData = await sseClient.callTool({ name: "BROADCAST_SIGNED_TX_FROM_STD_SIGNDOC_AND_SIGNATURE_ACTION", arguments: { signedDoc: signedDoc.signed, signature: signedDoc.signature, }, }); const txHash = JSON.parse((txHashData.content as any)[0].text).data.txHash; await setTimeout(2000); const txHashInfo = await client.getTx(txHash); assert(txHashInfo !== null); assert(txHashInfo.code === 0); assert(txHashInfo.hash === txHash); } async function testSignAndBroadcastTxBytes(sseClient: Client) { // setup wallet to sign const wallet = await DirectSecp256k1HdWallet.fromMnemonic( process.env.MNEMONIC!, { prefix: "orai" }, ); const accounts = await wallet.getAccounts(); const client = await SigningCosmWasmClient.connectWithSigner( process.env.RPC_URL!, wallet, { gasPrice: GasPrice.fromString("0.0001orai"), registry: new Registry([...defaultRegistryTypes, ...wasmTypes]), }, ); const transferMessageResult = await sseClient.callTool({ name: "TOKEN_TRANSFER_ACTION", arguments: { senderAddress: accounts[0].address, recipient: accounts[0].address, amount: { amount: "1", denom: ORAI } as Coin, }, }); const message = JSON.parse( (transferMessageResult.content as any)[0].text, ).data; const txRaw = await client.sign( accounts[0].address, [message], { amount: [{ amount: "0", denom: ORAI }], gas: "20000000" }, "", ); const txBytes = TxRaw.encode(txRaw).finish(); const txHashData = await sseClient.callTool({ name: "BROADCAST_SIGNED_TX_ACTION", arguments: { signedTx: toBase64(txBytes), }, }); const txHash = JSON.parse((txHashData.content as any)[0].text).data.txHash; await setTimeout(2000); const txHashInfo = await client.getTx(txHash); assert(txHashInfo !== null); assert(txHashInfo.code === 0); assert(txHashInfo.hash === txHash); assert(txHashInfo.hash.toLowerCase() === toHex(sha256(txBytes))); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/oraichain/orai-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server