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!

footer-logo-dark

© Akash Network 2025 The Akash Network Authors Documentation Distributed under CC BY 4.0

Open-source Apache 2.0 Licensed.

GitHub v0.38.2

Privacy