Documentation Index
Fetch the complete documentation index at: https://docs.getpara.com/llms.txt
Use this file to discover all available pages before exploring further.
Learn how to set up with Para SDK to interact with Cosmos-based blockchains.
Prerequisites
Proto Signer
Amino Signer
Use the Proto signer for transaction operations like sending tokens, staking, and IBC transfers.Install
npm install @getpara/react-native-wallet @getpara/cosmjs-v0-integration @cosmjs/stargate
@getpara/cosmjs-v0-integration is a separate package — install it alongside @getpara/react-native-wallet.
Usage
Hook (React)
Direct (Non-React)
Use the hook to create a CosmJS OfflineDirectSigner for your user’s Para embedded wallet or external wallet. The hook wraps signAndBroadcast in a React Query mutation.import { useParaCosmjsProtoSigner, useParaCosmjsSignAndBroadcast } from "@getpara/react-native-wallet/cosmos";
import { SigningStargateClient, coins } from "@cosmjs/stargate";
import { useState, useEffect } from "react";
import { Text, TouchableOpacity } from "react-native";
const RPC_URL = "https://rpc.cosmos.directory/cosmoshub";
function SendTokens() {
const { protoSigner, isLoading } = useParaCosmjsProtoSigner();
const [client, setClient] = useState<SigningStargateClient>();
useEffect(() => {
if (protoSigner) {
SigningStargateClient.connectWithSigner(RPC_URL, protoSigner).then(setClient);
}
}, [protoSigner]);
const { signAndBroadcastAsync, isPending } = useParaCosmjsSignAndBroadcast(protoSigner, client);
const handleSend = async () => {
const result = await signAndBroadcastAsync({
messages: [{ typeUrl: "/cosmos.bank.v1beta1.MsgSend", value: {
fromAddress: protoSigner!.address,
toAddress: "cosmos1...",
amount: coins(1000000, "uatom"),
}}],
fee: { amount: coins(5000, "uatom"), gas: "200000" },
});
console.log("Tx hash:", result.transactionHash);
};
if (isLoading) return <Text>Loading...</Text>;
return (
<TouchableOpacity onPress={handleSend} disabled={isPending}>
<Text>{isPending ? "Broadcasting..." : "Send 1 ATOM"}</Text>
</TouchableOpacity>
);
}
Wallet Resolution
When no address or walletId is passed, the hook resolves the wallet in this order:
- Selected wallet — if the user selected a Cosmos wallet in the UI. If there is only one Cosmos wallet in the session, it is already selected by default
- First Cosmos wallet — the first available Cosmos wallet on the account
To target a specific wallet:const { protoSigner } = useParaCosmjsProtoSigner({
address: "cosmos1...", // or walletId: "uuid-..."
prefix: "osmo", // optional chain prefix, defaults to "cosmos"
});
Use createParaProtoSigner to create a signer directly.import { createParaProtoSigner } from "@getpara/cosmjs-v0-integration";
import { SigningStargateClient } from "@cosmjs/stargate";
import Para from "@getpara/core-sdk";
const para = new Para("YOUR_API_KEY");
// Authenticate first...
const signer = createParaProtoSigner({ para, prefix: "cosmos" });
const client = await SigningStargateClient.connectWithSigner(rpcUrl, signer);
Wallet Resolution
When no address or walletId is passed, the factory picks the first available Cosmos wallet. To target a specific wallet:const signer = createParaProtoSigner({ para, prefix: "cosmos", address: "cosmos1..." });
Use the Amino signer for message signing (ADR-036) and authentication flows.Install
npm install @getpara/react-native-wallet @getpara/cosmjs-v0-integration @cosmjs/amino
Usage
Hook (React)
Direct (Non-React)
Use the hook to create a CosmJS OfflineAminoSigner for message signing (ADR-036) and authentication flows. The mutation hook also accepts an amino signer.import { useParaCosmjsAminoSigner } from "@getpara/react-native-wallet/cosmos";
import { makeSignDoc } from "@cosmjs/amino";
import { Text, Button } from "react-native";
function SignMessage() {
const { aminoSigner, isLoading } = useParaCosmjsAminoSigner();
const address = aminoSigner?.address;
const handleSign = async () => {
if (!aminoSigner || !address) return;
const signDoc = makeSignDoc(
[{ type: "sign/MsgSignData", value: { signer: address, data: btoa("Hello!") } }],
{ amount: [], gas: "0" }, "cosmoshub-4", "", 0, 0,
);
const { signature } = await aminoSigner.signAmino(address, signDoc);
console.log("Signature:", signature.signature);
};
if (isLoading) return <Text>Loading...</Text>;
return <Button title="Sign Message" onPress={handleSign} />;
}
Wallet resolution works the same as the Proto signer hook. import { createParaAminoSigner } from "@getpara/cosmjs-v0-integration";
const signer = createParaAminoSigner({ para, prefix: "cosmos" });
Metro Configuration
@cosmjs/crypto depends on libsodium-wrappers-sumo, a WASM-based cryptography library that is incompatible with React Native. Since Para handles signing server-side via MPC, this library is not needed at runtime. However, Metro will still bundle it and crash when the WASM module loads.
To fix this, stub out the module in your metro.config.js using a custom resolveRequest:
const { getDefaultConfig } = require('expo/metro-config');
const config = getDefaultConfig(__dirname);
const emptyModule = require.resolve('./lib/empty-module.js');
// libsodium-wrappers-sumo uses WASM which doesn't work in React Native.
// Since Para signs via MPC, this module is not needed.
// We must use resolveRequest (not extraNodeModules) because the package
// is installed in node_modules and extraNodeModules only acts as a fallback.
const stubbedModules = new Set(['libsodium-wrappers-sumo']);
const originalResolveRequest = config.resolver.resolveRequest;
config.resolver.resolveRequest = (context, moduleName, platform) => {
if (stubbedModules.has(moduleName)) {
return { type: 'sourceFile', filePath: emptyModule };
}
if (originalResolveRequest) {
return originalResolveRequest(context, moduleName, platform);
}
return context.resolveRequest(context, moduleName, platform);
};
module.exports = config;
Create the empty module stub:
Using extraNodeModules will not work for this case. Metro’s extraNodeModules only acts as a
fallback when a module can’t be found. Since libsodium-wrappers-sumo is installed as a transitive
dependency of @cosmjs/crypto, Metro resolves it from node_modules before checking
extraNodeModules. The resolveRequest override intercepts resolution before that happens.
Next Steps