Skip to content

Commit e99777d

Browse files
authored
Merge pull request #4 from hyperweb-io/feat/interchainjs-tools
feat: interchainjs mcp tools
2 parents f939cf2 + c9c77fb commit e99777d

File tree

11 files changed

+838
-11
lines changed

11 files changed

+838
-11
lines changed

package.json

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"main": "build/index.js",
66
"scripts": {
77
"build": "tsc && npm run copy-prompts && chmod 755 build/index.js",
8-
"copy-prompts": "mkdir -p build/starship && cp -r src/starship/prompts build/starship/",
8+
"copy-prompts": "./scripts/copy-prompts.sh",
99
"clean": "rimraf build",
1010
"test": "vitest",
1111
"test:watch": "vitest --watch",
@@ -30,19 +30,14 @@
3030
"typescript": "^5.8.2",
3131
"vitest": "^3.1.1"
3232
},
33-
"files": [
34-
"build"
35-
],
33+
"files": ["build"],
3634
"pnpm": {
37-
"onlyBuiltDependencies": [
38-
"@biomejs/biome",
39-
"esbuild"
40-
]
35+
"onlyBuiltDependencies": ["@biomejs/biome", "esbuild"]
4136
},
4237
"dependencies": {
4338
"@modelcontextprotocol/sdk": "^1.7.0",
4439
"dotenv": "^16.4.7",
4540
"js-yaml": "^4.1.0",
4641
"zod": "^3.24.2"
4742
}
48-
}
43+
}

scripts/copy-prompts.sh

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/bin/bash
2+
3+
# Ensure the script fails on any error
4+
set -e
5+
6+
# Find all prompts directories under src
7+
PROMPTS_DIRS=$(find src -type d -name prompts)
8+
9+
# Process each prompts directory
10+
for PROMPT_DIR in $PROMPTS_DIRS; do
11+
# Get the relative path without 'src/'
12+
REL_PATH=$(dirname "$PROMPT_DIR" | sed 's|^src/||')
13+
14+
# Create the target directory
15+
mkdir -p "build/$REL_PATH"
16+
17+
# Copy the prompts
18+
cp -r "$PROMPT_DIR" "build/$REL_PATH/"
19+
done
20+
21+
# Copy migration-examples directory
22+
if [ -d "src/interchainjs/migration-examples" ]; then
23+
mkdir -p "build/interchainjs"
24+
cp -r "src/interchainjs/migration-examples" "build/interchainjs/"
25+
fi

src/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { fileURLToPath } from "node:url";
66

77
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
88
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
9+
import { registerMigrateToInterchainjsTool } from "./interchainjs/tools/migrate-to-interchainjs.js";
910
import { registerStarshipConfigGenTool } from "./starship/tools/starship-config-gen.js";
1011
import { registerStarshipSetupTool } from "./starship/tools/starship-setup.js";
1112

@@ -25,8 +26,12 @@ async function main() {
2526
version: VERSION,
2627
});
2728

28-
registerStarshipConfigGenTool(server);
29+
// Starship
2930
registerStarshipSetupTool(server);
31+
registerStarshipConfigGenTool(server);
32+
33+
// InterchainJS
34+
registerMigrateToInterchainjsTool(server);
3035

3136
const transport = new StdioServerTransport();
3237
await server.connect(transport);
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
2+
import {
3+
GasPrice,
4+
SigningStargateClient,
5+
calculateFee,
6+
} from "@cosmjs/stargate";
7+
import type { MsgSend } from "cosmjs-types/cosmos/bank/v1beta1/tx";
8+
9+
// --- Configuration & Setup ---
10+
11+
const rpcEndpoint = "rpc.cosmos.network:26657"; // Replace with your RPC endpoint
12+
const senderMnemonic = "..."; // Replace with a valid mnemonic (for testing only!)
13+
const recipientAddress = "cosmos1..."; // Replace with a recipient address
14+
const amountToSend = {
15+
denom: "uatom",
16+
amount: "1000",
17+
};
18+
const gasPrice = GasPrice.fromString("0.025uatom");
19+
const gasLimit = 200000;
20+
const fee = calculateFee(gasLimit, gasPrice);
21+
const memo = "Sent via CosmJS";
22+
23+
// Type registry setup (only needed for custom message types, MsgSend is built-in)
24+
// const registry = new Registry();
25+
// const typeUrl = "/cosmos.bank.v1beta1.MsgSend"; // Example type URL
26+
// registry.register(typeUrl, MsgSend);
27+
28+
// --- Main Signing Logic (Conceptual Example) ---
29+
30+
async function signAndBroadcast() {
31+
// 1. Get a signer (e.g., from a mnemonic or browser extension like Keplr)
32+
// Using mnemonic here for a self-contained example (DO NOT use mainnet mnemonics in code)
33+
const signer = await DirectSecp256k1HdWallet.fromMnemonic(senderMnemonic, {
34+
prefix: "cosmos",
35+
});
36+
const [firstAccount] = await signer.getAccounts();
37+
const senderAddress = firstAccount.address;
38+
39+
console.log(`Sender address: ${senderAddress}`);
40+
41+
// 2. Create the signing client
42+
const signingClient = await SigningStargateClient.connectWithSigner(
43+
rpcEndpoint,
44+
signer,
45+
// Optional: Provide registry if using custom types
46+
// { registry: registry }
47+
);
48+
49+
// 3. Create the message
50+
const message: MsgSend = {
51+
fromAddress: senderAddress,
52+
toAddress: recipientAddress,
53+
amount: [amountToSend],
54+
};
55+
56+
// The type URL is crucial for Stargate messages
57+
const msgAny = {
58+
typeUrl: "/cosmos.bank.v1beta1.MsgSend",
59+
value: message,
60+
};
61+
62+
// 4. Sign and broadcast the transaction
63+
try {
64+
console.log("Signing and broadcasting transaction...");
65+
const result = await signingClient.signAndBroadcast(
66+
senderAddress,
67+
[msgAny], // Array of messages
68+
fee,
69+
memo,
70+
);
71+
console.log("Transaction successful:", result.transactionHash);
72+
console.log("Result details:", result);
73+
} catch (error) {
74+
console.error("Transaction failed:", error);
75+
}
76+
}
77+
78+
// --- Execute the function ---
79+
// signAndBroadcast(); // Uncomment to run, requires valid RPC and mnemonic
80+
81+
console.log("Example signing code structure loaded.");
82+
console.log("Ensure RPC endpoint and mnemonic are configured before running.");
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { fromBech32, toBech32 } from "@cosmjs/encoding";
2+
import { Decimal, Uint53 } from "@cosmjs/math";
3+
import { parseCoins } from "@cosmjs/stargate";
4+
5+
// Example 1: Bech32 encoding and decoding
6+
const decodedAddress = fromBech32(
7+
"cosmos1zmj0fpkm9px3f7klg7hzycu6z6k76jskvnsc0n",
8+
);
9+
console.log("Decoded Address Prefix:", decodedAddress.prefix);
10+
console.log("Decoded Address Data Length:", decodedAddress.data.length);
11+
12+
const reEncodedAddress = toBech32("cosmos", decodedAddress.data);
13+
console.log("Re-encoded Address:", reEncodedAddress);
14+
15+
// Example 2: Parsing coin strings
16+
const coinsString = "1000000uatom,500000stake";
17+
const parsedCoins = parseCoins(coinsString);
18+
console.log("Parsed Coins:", parsedCoins);
19+
20+
const singleCoinString = "12345uosmo";
21+
const parsedCoin = parseCoins(singleCoinString)[0];
22+
console.log("Parsed Single Coin:", parsedCoin);
23+
24+
// Example 3: Using Decimal for calculations
25+
const amount1 = Decimal.fromUserInput("123.456", 6); // Represents 123.456000
26+
const amount2 = Decimal.fromUserInput("0.001", 6); // Represents 0.001000
27+
28+
const sum = amount1.plus(amount2);
29+
console.log(
30+
`Sum: ${sum.toString()} (fractional digits: ${sum.fractionalDigits})`,
31+
);
32+
33+
const product = amount1.multiply(new Uint53(2)); // Multiply by 2
34+
console.log(
35+
`Product: ${product.toString()} (fractional digits: ${product.fractionalDigits})`,
36+
);
37+
38+
const division = amount1.toFloatApproximation() / 10;
39+
console.log(`Division (approx float): ${division}`);
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { SigningClient } from "@interchainjs/cosmos/signing-client";
2+
import { DirectGenericOfflineSigner } from "@interchainjs/cosmos/types/wallet";
3+
import { assertIsDeliverTxSuccess } from "@interchainjs/cosmos/utils";
4+
import { Secp256k1HDWallet } from "@interchainjs/cosmos/wallets/secp256k1hd";
5+
import { HDPath } from "@interchainjs/types";
6+
import type { MsgSend } from "interchainjs/cosmos/bank/v1beta1/tx";
7+
import { send } from "interchainjs/cosmos/bank/v1beta1/tx.rpc.func";
8+
9+
// --- Configuration & Setup ---
10+
11+
const rpcEndpoint = "rpc.cosmos.network:26657"; // Replace with your RPC endpoint
12+
const senderMnemonic = "..."; // Replace with a valid mnemonic (for testing only!)
13+
const recipientAddress = "cosmos1..."; // Replace with a recipient address
14+
const amountToSend = {
15+
denom: "uatom",
16+
amount: "1000",
17+
};
18+
const chainPrefix = "cosmos"; // Prefix for Cosmos Hub
19+
20+
// Fee object (adjust gas limit and amount as needed)
21+
const fee = {
22+
amount: [
23+
{
24+
denom: amountToSend.denom, // Match the send denom
25+
amount: "5000", // Example fee amount
26+
},
27+
],
28+
gas: "200000", // Example gas limit
29+
};
30+
const memo = "Sent via InterchainJS";
31+
32+
// --- Main Signing Logic (Conceptual Example) ---
33+
34+
async function signAndBroadcast() {
35+
// 1. Initialize wallet and get signer
36+
const wallet = Secp256k1HDWallet.fromMnemonic(senderMnemonic, [
37+
{
38+
prefix: chainPrefix,
39+
hdPath: HDPath.cosmos(0, 0, 0).toString(), // Standard Cosmos path
40+
},
41+
]);
42+
const offlineSigner = wallet.toOfflineDirectSigner();
43+
const [firstAccount] = await offlineSigner.getAccounts();
44+
const senderAddress = firstAccount.address;
45+
46+
console.log(`Sender address: ${senderAddress}`);
47+
48+
// 2. Wrap signer and create the signing client
49+
const genericSigner = new DirectGenericOfflineSigner(offlineSigner);
50+
const signingClient = await SigningClient.connectWithSigner(
51+
rpcEndpoint,
52+
genericSigner,
53+
{
54+
// Optional: Configure broadcast options if needed
55+
broadcast: {
56+
checkTx: true,
57+
deliverTx: true,
58+
},
59+
},
60+
);
61+
62+
// 3. Prepare the message payload for the 'send' function
63+
// Note: The 'send' function takes the message fields directly
64+
const msgPayload: MsgSend = {
65+
fromAddress: senderAddress,
66+
toAddress: recipientAddress,
67+
amount: [amountToSend],
68+
};
69+
70+
// 4. Call the specific 'send' function
71+
try {
72+
const result = await send(
73+
signingClient,
74+
senderAddress, // Sender address
75+
msgPayload, // The message payload
76+
fee, // The fee object
77+
memo, // The memo string
78+
);
79+
console.log(result);
80+
81+
// Optional: Check for success (interchainjs might throw on error depending on setup)
82+
assertIsDeliverTxSuccess(result);
83+
} catch (error) {
84+
console.error("Transaction failed:", error);
85+
}
86+
}
87+
88+
// --- Execute the function ---
89+
// signAndBroadcast(); // Uncomment to run, requires valid RPC and mnemonic
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { parseCoins } from "@interchainjs/amino";
2+
import { fromBech32, toBech32 } from "@interchainjs/encoding";
3+
import { Decimal, Uint53 } from "@interchainjs/math";
4+
5+
// Example 1: Bech32 encoding and decoding
6+
const decodedAddress = fromBech32(
7+
"cosmos1zmj0fpkm9px3f7klg7hzycu6z6k76jskvnsc0n",
8+
);
9+
console.log("Decoded Address Prefix:", decodedAddress.prefix);
10+
console.log("Decoded Address Data Length:", decodedAddress.data.length);
11+
12+
const reEncodedAddress = toBech32("cosmos", decodedAddress.data);
13+
console.log("Re-encoded Address:", reEncodedAddress);
14+
15+
// Example 2: Parsing coin strings
16+
const coinsString = "1000000uatom,500000stake";
17+
const parsedCoins = parseCoins(coinsString);
18+
console.log("Parsed Coins:", parsedCoins);
19+
20+
const singleCoinString = "12345uosmo";
21+
const parsedCoin = parseCoins(singleCoinString)[0];
22+
console.log("Parsed Single Coin:", parsedCoin);
23+
24+
// Example 3: Using Decimal for calculations
25+
const amount1 = Decimal.fromUserInput("123.456", 6); // Represents 123.456000
26+
const amount2 = Decimal.fromUserInput("0.001", 6); // Represents 0.001000
27+
28+
const sum = amount1.plus(amount2);
29+
console.log(
30+
`Sum: ${sum.toString()} (fractional digits: ${sum.fractionalDigits})`,
31+
);
32+
33+
const product = amount1.multiply(new Uint53(2)); // Multiply by 2
34+
console.log(
35+
`Product: ${product.toString()} (fractional digits: ${product.fractionalDigits})`,
36+
);
37+
38+
const division = amount1.toFloatApproximation() / 10;
39+
console.log(`Division (approx float): ${division}`);

0 commit comments

Comments
 (0)