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:
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
- Always set spending limits - Never grant unlimited fee allowances
- Use expiration dates - Time-limit permissions when possible
- Monitor grants - Regularly query and audit active grants
- Revoke promptly - Remove grants when no longer needed
- 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)
}Related Resources
- AuthZ & Fee Grants Guide - CLI usage and concepts
- SDK Installation - Get started with the SDK
- SDK Quick Start - Deploy your first app programmatically
- SDK Examples - More SDK code examples
Additional Resources
- Cosmos SDK AuthZ: docs.cosmos.network/main/modules/authz
- Cosmos SDK FeeGrant: docs.cosmos.network/main/modules/feegrant
- Discord: discord.akash.network - #developers channel
Questions? Join Discord #developers channel!