Injective Frontend Wallet
Use this skill before shipping any Injective browser transaction flow. Injective
looks Cosmos-shaped at the transaction layer, but its accounts and public keys
are Ethereum-style. Generic Cosmos frontend code often reaches the quote screen
and then fails at signing or CheckTx.
First Decision
Choose the signing stack deliberately:
- Prefer
@injectivelabs/sdk-ts / Injective broadcaster utilities when the app
already uses the Injective SDK and the transaction type is covered.
- Use CosmJS for CosmWasm frontends only if you explicitly handle Injective
account and pubkey compatibility.
- Do not assume a Keplr/Leap
inj1... address means generic
/cosmos.crypto.secp256k1.PubKey signing will validate on-chain.
Required Checks
Before calling the work complete, verify these on the actual signing path:
- Query account metadata from LCD:
GET /cosmos/auth/v1beta1/accounts/{injAddress}.
- If the account
@type is /injective.types.v1beta1.EthAccount, parse
base_account.account_number and base_account.sequence; do not rely on
CosmJS' default accountFromAny.
- Ensure transaction
AuthInfo.signer_infos[0].public_key.type_url is
/injective.crypto.v1beta1.ethsecp256k1.PubKey.
- Ensure the public key bytes are encoded as protobuf field 1
(
0a <len> <compressed-pubkey>), same field shape as the standard secp256k1
key but with the Injective type URL.
- For direct signing, sign the
SignDoc that contains that Injective pubkey in
authInfoBytes; otherwise the wallet signs bytes that differ from the
broadcast transaction.
- Use the wallet address returned for chain
injective-1; do not derive or
substitute addresses from another chain account without conversion checks.
Browser Trading Flow Checks
Browser trading apps need UI-level guards in addition to correct signing bytes:
- Keep a single per-wallet in-flight lock around transaction-producing actions.
Disable open, close, cash-out, and bulk action buttons until the prior tx is
confirmed or has failed.
- Do not rely on per-card loading state to prevent duplicate broadcasts; two
buttons can still race the same account sequence.
- Revalidate any local session, grantee, or autosign token against the currently
connected
inj1 address after wallet connect, account swap, and page reload.
- Treat
account sequence mismatch, expected X, got Y as a likely concurrency
bug first. Audit parallel clicks, multiple tabs, stale cached sequence, and
background retries before changing chain parameters.
- Keep raw CheckTx details in logs. User-facing errors should explain the
action, such as
Order failed, please try again., not expose transaction
hashes, RFQ IDs, account sequences, or signer internals.
Common Failures
If the error is:
Unsupported type: '/injective.types.v1beta1.EthAccount': the client is
using a generic Cosmos account parser for sequence/account number. Patch
getSequence() or use Injective SDK account querying.
pubKey does not match signer address ... invalid pubkey: AuthInfo likely
contains /cosmos.crypto.secp256k1.PubKey; use
/injective.crypto.v1beta1.ethsecp256k1.PubKey.
account does not exist on chain: the wallet has never transacted or is
unfunded. Fund it with INJ and retry after the account exists.
signature verification failed: inspect sign mode, signed authInfoBytes,
account number, sequence, and chain ID before changing business logic.
CosmJS Compatibility Pattern
When using SigningCosmWasmClient against Injective:
- Connect with the wallet signer.
- Patch or wrap
getSequence(address) so it reads account number and sequence
from Injective LCD for EthAccount.
- Patch direct signing so
AuthInfo uses the Injective ethsecp pubkey type
URL.
- Keep the actual business message unchanged, such as
MsgExecuteContract for
a swap contract.
- Add unit tests for the account payload and pubkey encoding helpers.
Minimal helper expectations:
const INJECTIVE_PUBKEY_TYPE = "/injective.crypto.v1beta1.ethsecp256k1.PubKey";
const INJECTIVE_ACCOUNT_TYPE = "/injective.types.v1beta1.EthAccount";
Swap Contract Frontends
For Injective swap-contract UIs:
- Query the contract for routes and quotes; do not inspect orderbooks in the
browser unless the task explicitly requires independent analytics.
- Execute the swap contract message (
swap_min_output or swap_exact_output)
with exactly one input coin in funds.
- Keep RFQ and direct exchange-module order placement out of scope unless the
user asks for those venues.
- Apply slippage to the contract quote's raw output quantity, not the formatted
decimal string.
- Test a live quote and a dry signing-path construction before asking the user
to sign real funds.
Regression Checklist
Add at least these tests or harness checks:
- Parse an Injective
EthAccount LCD fixture into
{ accountNumber, sequence }.
- Encode an Injective ethsecp pubkey and assert the type URL exactly.
- Build a tx or signing harness and assert
authInfoBytes contains the
Injective pubkey type before broadcast.
- Run
typecheck, unit tests, and a production build for browser apps.
Do Not Ship Until
- The account type and pubkey type checks above have been run.
- The transaction path has been tested with the same wallet family the user will
use, typically Keplr or Leap for
inj1.
- Any fallback to generic CosmJS behavior is documented as unsafe for Injective
unless proven with the checks above.
1---2name: injective-frontend-wallet3description: Build, review, or debug browser frontends that sign and broadcast Injective transactions with Keplr, Leap, MetaMask, CosmJS, @injectivelabs/sdk-ts, or CosmWasm execute messages. Use this whenever implementing Injective React/Vite/Next apps, wallet connect flows, swap-contract UIs, MsgExecuteContract, MsgBroadcaster, or when errors mention EthAccount, ethsecp256k1, invalid pubkey, account sequence, signer address, Keplr, Leap, or browser wallet signing.4license: MIT5---67# Injective Frontend Wallet89Use this skill before shipping any Injective browser transaction flow. Injective10looks Cosmos-shaped at the transaction layer, but its accounts and public keys11are Ethereum-style. Generic Cosmos frontend code often reaches the quote screen12and then fails at signing or CheckTx.1314## First Decision1516Choose the signing stack deliberately:17181. Prefer `@injectivelabs/sdk-ts` / Injective broadcaster utilities when the app19 already uses the Injective SDK and the transaction type is covered.202. Use CosmJS for CosmWasm frontends only if you explicitly handle Injective21 account and pubkey compatibility.223. Do not assume a Keplr/Leap `inj1...` address means generic23 `/cosmos.crypto.secp256k1.PubKey` signing will validate on-chain.2425## Required Checks2627Before calling the work complete, verify these on the actual signing path:2829- Query account metadata from LCD: `GET /cosmos/auth/v1beta1/accounts/{injAddress}`.30- If the account `@type` is `/injective.types.v1beta1.EthAccount`, parse31 `base_account.account_number` and `base_account.sequence`; do not rely on32 CosmJS' default `accountFromAny`.33- Ensure transaction `AuthInfo.signer_infos[0].public_key.type_url` is34 `/injective.crypto.v1beta1.ethsecp256k1.PubKey`.35- Ensure the public key bytes are encoded as protobuf field 136 (`0a <len> <compressed-pubkey>`), same field shape as the standard secp256k137 key but with the Injective type URL.38- For direct signing, sign the `SignDoc` that contains that Injective pubkey in39 `authInfoBytes`; otherwise the wallet signs bytes that differ from the40 broadcast transaction.41- Use the wallet address returned for chain `injective-1`; do not derive or42 substitute addresses from another chain account without conversion checks.4344## Browser Trading Flow Checks4546Browser trading apps need UI-level guards in addition to correct signing bytes:4748- Keep a single per-wallet in-flight lock around transaction-producing actions.49 Disable open, close, cash-out, and bulk action buttons until the prior tx is50 confirmed or has failed.51- Do not rely on per-card loading state to prevent duplicate broadcasts; two52 buttons can still race the same account sequence.53- Revalidate any local session, grantee, or autosign token against the currently54 connected `inj1` address after wallet connect, account swap, and page reload.55- Treat `account sequence mismatch, expected X, got Y` as a likely concurrency56 bug first. Audit parallel clicks, multiple tabs, stale cached sequence, and57 background retries before changing chain parameters.58- Keep raw CheckTx details in logs. User-facing errors should explain the59 action, such as `Order failed, please try again.`, not expose transaction60 hashes, RFQ IDs, account sequences, or signer internals.6162## Common Failures6364If the error is:6566- `Unsupported type: '/injective.types.v1beta1.EthAccount'`: the client is67 using a generic Cosmos account parser for sequence/account number. Patch68 `getSequence()` or use Injective SDK account querying.69- `pubKey does not match signer address ... invalid pubkey`: `AuthInfo` likely70 contains `/cosmos.crypto.secp256k1.PubKey`; use71 `/injective.crypto.v1beta1.ethsecp256k1.PubKey`.72- `account does not exist on chain`: the wallet has never transacted or is73 unfunded. Fund it with INJ and retry after the account exists.74- `signature verification failed`: inspect sign mode, signed `authInfoBytes`,75 account number, sequence, and chain ID before changing business logic.7677## CosmJS Compatibility Pattern7879When using `SigningCosmWasmClient` against Injective:80811. Connect with the wallet signer.822. Patch or wrap `getSequence(address)` so it reads account number and sequence83 from Injective LCD for `EthAccount`.843. Patch direct signing so `AuthInfo` uses the Injective ethsecp pubkey type85 URL.864. Keep the actual business message unchanged, such as `MsgExecuteContract` for87 a swap contract.885. Add unit tests for the account payload and pubkey encoding helpers.8990Minimal helper expectations:9192```ts93const INJECTIVE_PUBKEY_TYPE = "/injective.crypto.v1beta1.ethsecp256k1.PubKey";94const INJECTIVE_ACCOUNT_TYPE = "/injective.types.v1beta1.EthAccount";95```9697## Swap Contract Frontends9899For Injective swap-contract UIs:100101- Query the contract for routes and quotes; do not inspect orderbooks in the102 browser unless the task explicitly requires independent analytics.103- Execute the swap contract message (`swap_min_output` or `swap_exact_output`)104 with exactly one input coin in funds.105- Keep RFQ and direct exchange-module order placement out of scope unless the106 user asks for those venues.107- Apply slippage to the contract quote's raw output quantity, not the formatted108 decimal string.109- Test a live quote and a dry signing-path construction before asking the user110 to sign real funds.111112## Regression Checklist113114Add at least these tests or harness checks:115116- Parse an Injective `EthAccount` LCD fixture into117 `{ accountNumber, sequence }`.118- Encode an Injective ethsecp pubkey and assert the type URL exactly.119- Build a tx or signing harness and assert `authInfoBytes` contains the120 Injective pubkey type before broadcast.121- Run `typecheck`, unit tests, and a production build for browser apps.122123## Do Not Ship Until124125- The account type and pubkey type checks above have been run.126- The transaction path has been tested with the same wallet family the user will127 use, typically Keplr or Leap for `inj1`.128- Any fallback to generic CosmJS behavior is documented as unsafe for Injective129 unless proven with the checks above.