The IXO smartaccount module replaces the default Cosmos SDK signature ante handler with an opt-in pluggable system. Each account can register one or more authenticators — signature verifiers, message filters, spend-limit contracts, or composite logic — that execute on every transaction the account opts in to. If no authenticators are selected, transactions fall back to the standard Cosmos SDK signature flow.
Before you start
You need:
- An IXO account with
uixofor fees on the network you target — see Networks and endpoints. - An offline signer — see the SDK README.
- An authenticator type and config payload to register. The supported types are defined in the smartaccount types proto.
npm install @ixo/impactxclient-sdkimport { ixo, createSigningClient } from "@ixo/impactxclient-sdk";
const signingClient = await createSigningClient(RPC_ENDPOINT, offlineSigner);Add an authenticator
const addAuthenticatorMsg = {
typeUrl: "/ixo.smartaccount.v1beta1.MsgAddAuthenticator",
value: ixo.smartaccount.v1beta1.MsgAddAuthenticator.fromPartial({
sender: signerAddress,
authenticatorType: "SignatureVerification",
data: new TextEncoder().encode(JSON.stringify({ pubkey: pubkeyHex })),
}),
};
await signingClient.signAndBroadcast(signerAddress, [addAuthenticatorMsg], "auto");The chain assigns an id to each authenticator on success. Read it from transaction events to reference the authenticator in subsequent transactions.
Remove an authenticator
const removeAuthenticatorMsg = {
typeUrl: "/ixo.smartaccount.v1beta1.MsgRemoveAuthenticator",
value: ixo.smartaccount.v1beta1.MsgRemoveAuthenticator.fromPartial({
sender: signerAddress,
id: 1n,
}),
};Pause the module (governance)
MsgSetActiveState is the circuit breaker — only the module's gov authority can broadcast it.
const setActiveMsg = ixo.smartaccount.v1beta1.MsgSetActiveState.fromPartial({
authority: govAuthority,
active: false,
});When active is false, the smart-account ante handler is skipped and all transactions use the default Cosmos SDK signature path.
Use authenticators on a transaction
A transaction opts in to specific authenticators via the AuthenticatorTxExtension TX extension. The full pattern depends on your signing flow — see the smartaccount module README and the README for the IXO MultiClient SDK for current helpers. The extension carries the list of authenticator IDs to use for each signer.
Composite authenticators
Composite authenticators combine sub-authenticators using boolean logic.
AllOf
Approves only when every sub-authenticator approves: auth(a) && auth(b) && ....
AnyOf
Approves when at least one sub-authenticator approves: auth(a) || auth(b) || ....
PartitionedAllOf
Multi-signature where signatures are split across sub-authenticators (one signer per sub-authenticator).
Example shapes:
// One-click trading: hot key restricted to swap messages with on-chain spend-limit guard
AllOf(
SignatureVerification(usersPubKey),
AnyOf(
MessageFilter(SwapMsg1),
MessageFilter(SwapMsg2)
),
CosmwasmAuthenticator(spendLimitContract, params)
)
// Multisig (2-of-3): each signer satisfies one branch
PartitionedAllOf(pubkey1, pubkey2, pubkey3)
// Cosigner protection: cosigner approves alongside a user-selected set
AllOf(
SignatureVerification(cosignerPubKey),
AnyOf(...userAuthenticators)
)Authentication phases
Each authenticator runs through a three-phase lifecycle on every transaction:
- Authenticate — verify the transaction is authorized.
- Track — record any state changes the authenticator needs (committed regardless of transaction outcome).
- Confirm execution — validate the post-execution effects.
Verify the result
Query an account's authenticators through the ixo.smartaccount.v1beta1.Query/AccountAuthenticators endpoint on the gRPC gateway API. Module params (including is_smart_account_active) are read from Query/Params.
Troubleshooting
unknown authenticator type
authenticatorType must match one of the registered types in the chain's smartaccount module. Check Query/Params.maximum_unauthenticated_gas and the module's registered types.
authenticator id not found
MsgRemoveAuthenticator fails when id does not exist for sender. Query AccountAuthenticators to confirm the id.
module inactive
When is_smart_account_active is false, MsgAddAuthenticator and MsgRemoveAuthenticator are rejected. The module is gated by gov via MsgSetActiveState.
signature verification failed
Ensure the TX extension lists the correct authenticator IDs in the order matching the signer set, and that the data payload registered with MsgAddAuthenticator is the canonical encoding for that authenticator type.