Manage authorization

Grant, revoke, and execute Cosmos authz and feegrant messages on the IXO Protocol.

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

invalid authorization parameters

Confirm bech32 addresses are valid for the chain prefix (ixo), the denom is supported, and the amount is within spend_limit.

execution failures

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.

fee allowance issues

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.

Next steps