AuthZ & Fee Grants SDK

Programmatically grant permissions and manage fee allowances using the Akash SDK.

This guide covers how to use the Akash SDK (Go and JavaScript/TypeScript) to implement AuthZ and Fee Grants in your applications.


Overview

The Akash SDK provides full support for:

  • AuthZ (Authorization) - Grant deployment permissions programmatically
  • Fee Grants - Pay transaction fees for other accounts via code

For CLI usage and concepts, see: AuthZ & Fee Grants Guide


Installation

Before using AuthZ and Fee Grants, install the Akash SDK:

SDK Installation Guide


AuthZ SDK Integration

Granting Permissions

Grant deployment permissions to another account:

import (
  "pkg.akt.dev/go/node/authz/v1beta1"
  "time"
)

// Grant permission to create deployments
grantMsg := &authz.MsgGrant{
  Granter: granterAddress,
  Grantee: granteeAddress,
  Grant: authz.Grant{
      Authorization: &authz.GenericAuthorization{
          Msg: "/akash.deployment.v1beta3.MsgCreateDeployment",
      },
      Expiration: &time.Time{}, // Optional expiration
  },
}

// Broadcast the grant transaction
resp, err := client.BroadcastTx(ctx, grantMsg)
if err != nil {
  log.Fatal(err)
}

Grant with Expiration and Limits

import (
  "pkg.akt.dev/go/node/authz/v1beta1"
  sdk "github.com/cosmos/cosmos-sdk/types"
  "time"
)

// Set expiration to 30 days from now
expiration := time.Now().Add(30 * 24 * time.Hour)

// Grant with spending limit
grantMsg := &authz.MsgGrant{
  Granter: granterAddress,
  Grantee: granteeAddress,
  Grant: authz.Grant{
      Authorization: &authz.GenericAuthorization{
          Msg: "/akash.deployment.v1beta3.MsgCreateDeployment",
      },
      Expiration: &expiration,
  },
}

// Note: Spending limits are set via fee grants (see below)
resp, err := client.BroadcastTx(ctx, grantMsg)

Execute with Granted Permission

Use granted permissions to deploy on behalf of another account:

import (
  "pkg.akt.dev/go/node/authz/v1beta1"
  "pkg.akt.dev/go/node/deployment/v1beta3"
  "github.com/cosmos/cosmos-sdk/codec/types"
)

// Create the deployment message
deploymentMsg := &deployment.MsgCreateDeployment{
  ID: deployment.DeploymentID{
      Owner: granterAddress, // Important: use granter's address
      DSeq:  dseq,
  },
  Groups: groups,
  Version: version,
  Deposit: deposit,
}

// Wrap in authz exec message
execMsg := &authz.MsgExec{
  Grantee: granteeAddress, // Your address
  Msgs: []*types.Any{
      types.MustPackAny(deploymentMsg),
  },
}

// Broadcast from grantee account
resp, err := client.BroadcastTx(ctx, execMsg)
if err != nil {
  log.Fatal(err)
}

fmt.Printf("Deployment created: %d\n", dseq)

Query Grants

Check existing grants between accounts:

import (
  "pkg.akt.dev/go/node/authz/v1beta1"
)

// Query grants by granter and grantee
grantsResp, err := client.AuthzClient.Grants(ctx, &authz.QueryGrantsRequest{
  Granter: granterAddress,
  Grantee: granteeAddress,
  MsgTypeUrl: "/akash.deployment.v1beta3.MsgCreateDeployment",
})
if err != nil {
  log.Fatal(err)
}

for _, grant := range grantsResp.Grants {
  fmt.Printf("Grant: %+v\n", grant)
  fmt.Printf("Expiration: %s\n", grant.Expiration)
}

// Query all grants by granter
allGrantsResp, err := client.AuthzClient.GranterGrants(ctx, &authz.QueryGranterGrantsRequest{
  Granter: granterAddress,
})

Revoke Permissions

Remove granted permissions:

import (
  "pkg.akt.dev/go/node/authz/v1beta1"
)

// Revoke permission
revokeMsg := &authz.MsgRevoke{
  Granter: granterAddress,
  Grantee: granteeAddress,
  MsgTypeUrl: "/akash.deployment.v1beta3.MsgCreateDeployment",
}

// Broadcast the revoke transaction
resp, err := client.BroadcastTx(ctx, revokeMsg)
if err != nil {
  log.Fatal(err)
}

fmt.Println("Permission revoked successfully")

Fee Grant SDK Integration

Grant Basic Fee Allowance

Allow another account to use your AKT for transaction fees:

import (
  "pkg.akt.dev/go/node/feegrant/v1beta1"
  sdk "github.com/cosmos/cosmos-sdk/types"
  "github.com/cosmos/cosmos-sdk/codec/types"
)

// Grant basic fee allowance (unlimited)
basicAllowance := &feegrant.BasicAllowance{}

allowanceAny, err := types.NewAnyWithValue(basicAllowance)
if err != nil {
  log.Fatal(err)
}

grantMsg := &feegrant.MsgGrantAllowance{
  Granter:   granterAddress,
  Grantee:   granteeAddress,
  Allowance: allowanceAny,
}

// Broadcast the grant
resp, err := client.BroadcastTx(ctx, grantMsg)

Grant Fee Allowance with Spending Limit

import (
  "pkg.akt.dev/go/node/feegrant/v1beta1"
  sdk "github.com/cosmos/cosmos-sdk/types"
  "github.com/cosmos/cosmos-sdk/codec/types"
)

// Grant with spending limit (1 AKT = 1,000,000 uAKT)
limitAllowance := &feegrant.BasicAllowance{
  SpendLimit: sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(1000000))),
}

allowanceAny, err := types.NewAnyWithValue(limitAllowance)
if err != nil {
  log.Fatal(err)
}

grantMsg := &feegrant.MsgGrantAllowance{
  Granter:   granterAddress,
  Grantee:   granteeAddress,
  Allowance: allowanceAny,
}

resp, err := client.BroadcastTx(ctx, grantMsg)

Grant Periodic Fee Allowance

Allow a specific amount per time period (e.g., daily limit):

import (
  "pkg.akt.dev/go/node/feegrant/v1beta1"
  sdk "github.com/cosmos/cosmos-sdk/types"
  "github.com/cosmos/cosmos-sdk/codec/types"
  "time"
)

// Grant 0.1 AKT per day
period := time.Hour * 24
periodLimit := sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(100000)))

periodicAllowance := &feegrant.PeriodicAllowance{
  Basic: feegrant.BasicAllowance{
      SpendLimit: sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10000000))), // Total limit
  },
  Period:       period,
  PeriodLimit:  periodLimit,
}

allowanceAny, err := types.NewAnyWithValue(periodicAllowance)
grantMsg := &feegrant.MsgGrantAllowance{
  Granter:   granterAddress,
  Grantee:   granteeAddress,
  Allowance: allowanceAny,
}

resp, err := client.BroadcastTx(ctx, grantMsg)

Query Fee Grants

import (
  "pkg.akt.dev/go/node/feegrant/v1beta1"
)

// Query specific fee grant
grantResp, err := client.FeegrantClient.Allowance(ctx, &feegrant.QueryAllowanceRequest{
  Granter: granterAddress,
  Grantee: granteeAddress,
})
if err != nil {
  log.Fatal(err)
}

fmt.Printf("Allowance: %+v\n", grantResp.Allowance)

// Query all fee grants by granter
granterResp, err := client.FeegrantClient.AllowancesByGranter(ctx, &feegrant.QueryAllowancesByGranterRequest{
  Granter: granterAddress,
})

for _, allowance := range granterResp.Allowances {
  fmt.Printf("Grantee: %s\n", allowance.Grantee)
}

Revoke Fee Grant

import (
  "pkg.akt.dev/go/node/feegrant/v1beta1"
)

// Revoke fee grant
revokeMsg := &feegrant.MsgRevokeAllowance{
  Granter: granterAddress,
  Grantee: granteeAddress,
}

resp, err := client.BroadcastTx(ctx, revokeMsg)
if err != nil {
  log.Fatal(err)
}

fmt.Println("Fee grant revoked")

Combined AuthZ + Fee Grant

The most powerful pattern: grant both permissions AND fee allowance so the grantee can deploy without any AKT:

import (
  "pkg.akt.dev/go/node/authz/v1beta1"
  "pkg.akt.dev/go/node/feegrant/v1beta1"
  sdk "github.com/cosmos/cosmos-sdk/types"
  "github.com/cosmos/cosmos-sdk/codec/types"
  "time"
)

// Step 1: Grant fee allowance
limitAllowance := &feegrant.BasicAllowance{
  SpendLimit: sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(10000000))), // 10 AKT for fees
}
allowanceAny, _ := types.NewAnyWithValue(limitAllowance)
feeGrantMsg := &feegrant.MsgGrantAllowance{
  Granter:   granterAddress,
  Grantee:   granteeAddress,
  Allowance: allowanceAny,
}

// Step 2: Grant deployment permission
expiration := time.Now().Add(30 * 24 * time.Hour)
authzGrantMsg := &authz.MsgGrant{
  Granter: granterAddress,
  Grantee: granteeAddress,
  Grant: authz.Grant{
      Authorization: &authz.GenericAuthorization{
          Msg: "/akash.deployment.v1beta3.MsgCreateDeployment",
      },
      Expiration: &expiration,
  },
}

// Broadcast both in a single transaction
resp, err := client.BroadcastTx(ctx, feeGrantMsg, authzGrantMsg)
if err != nil {
  log.Fatal(err)
}

fmt.Println("Grantee can now deploy on your behalf with no AKT needed!")

Use Cases

CI/CD Pipeline Automation

Grant your CI/CD bot permissions and fees for automated deployments:

// Setup CI/CD bot with daily fee limit and deployment permissions
func setupCICDBot(client *AkashClient, botAddress string) error {
  // Daily fee limit: 0.5 AKT per day
  period := time.Hour * 24
  periodicAllowance := &feegrant.PeriodicAllowance{
      Basic: feegrant.BasicAllowance{
          SpendLimit: sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(50000000))),
      },
      Period:      period,
      PeriodLimit: sdk.NewCoins(sdk.NewCoin("uakt", sdk.NewInt(500000))),
  }
  
  // Grant full deployment permissions
  authzGrant := &authz.MsgGrant{
      Granter: myAddress,
      Grantee: botAddress,
      Grant: authz.Grant{
          Authorization: &authz.GenericAuthorization{
              Msg: "/akash.deployment.v1beta3.MsgCreateDeployment",
          },
      },
  }
  
  // Broadcast both
  return client.BroadcastTx(ctx, periodicAllowance, authzGrant)
}

Best Practices

Security

  1. Always set spending limits - Never grant unlimited fee allowances
  2. Use expiration dates - Time-limit permissions when possible
  3. Monitor grants - Regularly query and audit active grants
  4. Revoke promptly - Remove grants when no longer needed
  5. Separate accounts - Use dedicated accounts for different purposes

Error Handling

// Check if grant exists before executing
func checkAndExecute(client *AkashClient, granterAddr, granteeAddr string) error {
  // Query grant
  grantResp, err := client.AuthzClient.Grants(ctx, &authz.QueryGrantsRequest{
      Granter:    granterAddr,
      Grantee:    granteeAddr,
      MsgTypeUrl: "/akash.deployment.v1beta3.MsgCreateDeployment",
  })
  
  if err != nil {
      return fmt.Errorf("failed to query grant: %w", err)
  }
  
  if len(grantResp.Grants) == 0 {
      return fmt.Errorf("no grant found")
  }
  
  // Check expiration
  grant := grantResp.Grants[0]
  if grant.Expiration != nil && grant.Expiration.Before(time.Now()) {
      return fmt.Errorf("grant has expired")
  }
  
  // Execute deployment
  return executeDeployment(client, granterAddr)
}


Additional Resources


Questions? Join Discord #developers channel!