Skip to main content
Authorization (x/authz) lets one account grant another the right to broadcast specific message types on its behalf, scoped by amount, time, or message URL. x/feegrant lets one account pay another’s transaction fees. Both are standard Cosmos SDK modules — IXO uses the upstream message types directly.

Before you start

You need:
  • An IXO account with uixo for fees on the network you target — see Networks and endpoints.
  • An offline signer — see the SDK README.
  • The granter and grantee bech32 addresses.
npm install @ixo/impactxclient-sdk
import { cosmos, createSigningClient } from "@ixo/impactxclient-sdk";

const signingClient = await createSigningClient(RPC_ENDPOINT, offlineSigner);

Grant a send authorization

SendAuthorization lets the grantee call cosmos.bank.v1beta1.MsgSend from the granter, capped at spend_limit.
const sendAuth = cosmos.bank.v1beta1.SendAuthorization.fromPartial({
  spendLimit: [{ denom: "uixo", amount: "1000000" }],
});

const grantMsg = {
  typeUrl: "/cosmos.authz.v1beta1.MsgGrant",
  value: cosmos.authz.v1beta1.MsgGrant.fromPartial({
    granter: granterAddress,
    grantee: granteeAddress,
    grant: cosmos.authz.v1beta1.Grant.fromPartial({
      authorization: {
        typeUrl: "/cosmos.bank.v1beta1.SendAuthorization",
        value: cosmos.bank.v1beta1.SendAuthorization.encode(sendAuth).finish(),
      },
    }),
  }),
};

await signingClient.signAndBroadcast(granterAddress, [grantMsg], "auto");
For broader grants (e.g. authorize any IBC transfer message URL), use cosmos.authz.v1beta1.GenericAuthorization with the target msg type URL.

Execute a granted message

The grantee wraps the message they were authorized to send inside cosmos.authz.v1beta1.MsgExec.
const innerSend = cosmos.bank.v1beta1.MsgSend.fromPartial({
  fromAddress: granterAddress,
  toAddress: recipientAddress,
  amount: [{ denom: "uixo", amount: "100000" }],
});

const execMsg = {
  typeUrl: "/cosmos.authz.v1beta1.MsgExec",
  value: cosmos.authz.v1beta1.MsgExec.fromPartial({
    grantee: granteeAddress,
    msgs: [
      {
        typeUrl: "/cosmos.bank.v1beta1.MsgSend",
        value: cosmos.bank.v1beta1.MsgSend.encode(innerSend).finish(),
      },
    ],
  }),
};

await signingClient.signAndBroadcast(granteeAddress, [execMsg], "auto");
For an IBC transfer, replace the inner message with ibc.applications.transfer.v1.MsgTransfer.

Revoke an authorization

const revokeMsg = {
  typeUrl: "/cosmos.authz.v1beta1.MsgRevoke",
  value: cosmos.authz.v1beta1.MsgRevoke.fromPartial({
    granter: granterAddress,
    grantee: granteeAddress,
    msgTypeUrl: "/cosmos.bank.v1beta1.MsgSend",
  }),
};

Grant a fee allowance

const basicAllowance = cosmos.feegrant.v1beta1.BasicAllowance.fromPartial({
  spendLimit: [{ denom: "uixo", amount: "500000" }],
});

const grantAllowanceMsg = {
  typeUrl: "/cosmos.feegrant.v1beta1.MsgGrantAllowance",
  value: cosmos.feegrant.v1beta1.MsgGrantAllowance.fromPartial({
    granter: granterAddress,
    grantee: granteeAddress,
    allowance: {
      typeUrl: "/cosmos.feegrant.v1beta1.BasicAllowance",
      value: cosmos.feegrant.v1beta1.BasicAllowance.encode(basicAllowance).finish(),
    },
  }),
};

Revoke a fee allowance

const revokeAllowanceMsg = {
  typeUrl: "/cosmos.feegrant.v1beta1.MsgRevokeAllowance",
  value: cosmos.feegrant.v1beta1.MsgRevokeAllowance.fromPartial({
    granter: granterAddress,
    grantee: granteeAddress,
  }),
};
The grantee then sets the granter’s address as the feePayer in the transaction’s fee object — the granter is debited instead of the grantee.

Verify the result

Query active grants through the gRPC gateway API:
  • cosmos.authz.v1beta1.Query/Grants — grants between a granter and grantee
  • cosmos.authz.v1beta1.Query/GranterGrants — all grants issued by a granter
  • cosmos.authz.v1beta1.Query/GranteeGrants — all grants received by a grantee
  • cosmos.feegrant.v1beta1.Query/Allowance — fee allowance status

Troubleshooting

Confirm bech32 addresses are valid for the chain prefix (ixo), the denom is supported, and the amount is within spend_limit.
Confirm the grant has not expired, the grantee’s transaction message URL exactly matches the authorization’s allowed type, and the spend limit has not been exhausted.
Ensure the granter has sufficient balance for the allowance, the allowance type matches the use case (BasicAllowance vs PeriodicAllowance vs AllowedMsgAllowance), and the transaction’s feePayer is set to the granter.
Use AllowedMsgAllowance to combine fee payment with a strict whitelist of message URLs the grantee may submit at the granter’s expense.

Next steps

Custom authorizations

Use IXO-specific authz types for entities, claims, and tokens.

Smart accounts

Add programmable authenticators on top of authz.

Cosmos authz module

Full reference for x/authz.

Cosmos feegrant module

Full reference for x/feegrant.