- Docs
- Developers
- Utilizing grant allowances
Using grant allowances to execute transactions
As one of the primary use case of the Fee Grant module is to help with onboarding new users, this section of the guide will show how to allow users to execute transactions using the allowance granted to them.
Query a grant allowance
Now that an allowance has been assigned to an account address, you should be able to verify the details of that grant. The returned information will include the granter's address, the allowance amount, and any other conditions set by the granter, such as the expiration date of the allowance.
The following command using archwayd will give the details of a grant allowance:
archwayd query feegrant grant "${granter_address}" "${grantee_address}" --chain-id constantine-3 --node https://rpc.constantine.archway.io:443
Results:
allowance:
'@type': /cosmos.feegrant.v1beta1.BasicAllowance
expiration: null
spend_limit:
- amount: "4806067100000000000"
denom: aconst
grantee: archway1vve3d5u89h966t8kcvemwu88rnzzgcqxvkuj4s
granter: archway1u0p8vfpf5gjwje84073x0d6w40vm2s25603359
This can also be achieved via the following API endpoint where api_endpoint is an API endpoint connected to one of the Archway networks (Testnet or Mainnet). granter is the address that granted the allowance and grantee is the address that received the allowance:
{api_endpoint}/cosmos/feegrant/v1beta1/allowance/{granter}/{grantee}
Results:
{
"allowance": {
"granter": "archway1u0p8vfpf5gjwje84073x0d6w40vm2s25603359",
"grantee": "archway1vve3d5u89h966t8kcvemwu88rnzzgcqxvkuj4s",
"allowance": {
"@type": "/cosmos.feegrant.v1beta1.BasicAllowance",
"spend_limit": [
{
"denom": "aconst",
"amount": "4806067100000000000"
}
],
"expiration": null
}
}
}
Creating a Transaction
Just like any other transaction on Archway, a transaction that will use a granted allowance for fees must include certain information, such as the type of transaction (i.e., the message). Instead of the normal fee object, the transaction should include the granter's account which will pay the transaction fee. This is accomplished by doing the following:
const fee = await signingClient.calculateFee(signerAddress, messages, '', 1.5, feeGranterAddress); const broadcastResult = await signingClient.signAndBroadcast(signerAddress, messages, fee);
The signAndBroadcast method does not allow for setting the feeGranterAddress address to stipulate that this account should cover the fees and therefore a custom fee object should be generated which is made available within arch3.js via the calculateFee method as shown here. This fee is then plugged into the signAndBroadcast method and if there is an allowance from the feeGranterAddress for the signerAddress then the amount will be deducted from the feeGranterAddress. If not, the fee will be deducted from the signerAddress.
This is main difference in executing a transaction with fees paid for by the signer as opposed to the fees paid for by a fee grant allwoance.
Basic keplr example
The following example will allow a user to increment the counter is our basic increment contract which you can create easily from a template within Archway CLI. The following setup guide will help to create and deploy such a contract on Archway.
Info
This tutorial needs to be embedded in a web page for it to function. For a full working example, see dapp examples.
Prerequisites
Before moving forward, ensure that you have completed the following prerequisites:
Create config
Create a new config file in your project. You can name the file triomphe.config.js if using mainnet, or constantine.config.js if using testnet. The file should contain the following content:
mainnet
testnet
const currency = { coinDenom: 'ARCH', coinMinimalDenom: 'aarch', coinDecimals: 18, coinGeckoId: 'archway',};const ChainInfo = { chainId: 'archway-1', chainName: 'Mainnet', rpc: 'https://rpc.mainnet.archway.io', rest: 'https://api.mainnet.archway.io', stakeCurrency: currency, bip44: { coinType: 118, }, bech32Config: { bech32PrefixAccAddr: 'archway', bech32PrefixAccPub: 'archwaypub', bech32PrefixValAddr: 'archwayvaloper', bech32PrefixValPub: 'archwayvaloperpub', bech32PrefixConsAddr: 'archwayvalcons', bech32PrefixConsPub: 'archwayvalconspub', }, currencies: [currency], feeCurrencies: [currency], coinType: 118, features: ['cosmwasm', 'ibc-transfer', 'ibc-go'], // walletUrlForStaking: '',};export default chainInfo;
Connecting to keplr
- The following imports are required to complete your transaction.
mainnet
testnet
import { SigningArchwayClient } from '@archwayhq/arch3.js';import ChainInfo from './triomphe.config.js';import { MsgExecuteContract } from 'cosmjs-types/cosmwasm/wasm/v1/tx.js';import { toUtf8 } from '@cosmjs/encoding';
- Next, verify that Keplr is installed on the browser and has at least one account set up. If Keplr is installed, use the suggestChain method to add the Constantine network to Keplr. Also, to prevent Keplr from overriding fees set by arch3.js, set the Interactive Option value of preferNoSetFee to true.
window.onload = async () => { if (!window.getOfflineSignerAuto || !window.keplr) { alert("Please install keplr extension"); } else { if (window.keplr.experimentalSuggestChain) { try { await window.keplr.experimentalSuggestChain(ChainInfo); window.keplr.defaultOptions = { sign: { preferNoSetFee: true, } } } catch { alert("Failed to suggest the chain"); } } else { alert("Please use the recent version of keplr extension"); } }};
- Enable the chain to then connect to it.
const chainId = ChainInfo.chainId;await window.keplr.enable(chainId);
- Create an offline signer using the getOfflineSignerAuto method and also a signing client using SigningArchwayClient.
const offlineSigner = window.getOfflineSigner(chainId);const signingClient = await SigningArchwayClient.connectWithSigner(ChainInfo.rpc, offlineSigner);
- Obtain the signer's account, which will provide their address.
const accounts = await offlineSigner.getAccounts();const signerAddress = accounts[0].address;
Execute transaction
- Set the fee granter and contract addresses.
const smartContractAddress = process.env.SMART_CONTRACT_ADDRESS;const feeGranterAddress = process.env.FEE_GRANTER_ADDRESS;
- Define the transaction details which includes the message to the contract.
// Increment contract message to increase counterconst contractMsg = { increment: {},};// Message to execute a transaction via the smart contractconst executeMsg = { typeUrl: '/cosmwasm.wasm.v1.MsgExecuteContract', value: MsgExecuteContract.fromPartial({ sender: signerAddress, contract: smartContractAddress, msg: toUtf8(JSON.stringify(contractMsg)), funds: [], }),};const messages = [executeMsg];
- Calculate the fee dynamically but also set fee granter address will pay the transaction fee if an allowance exists. The memo is set to an empty string and the fee adjustment is set to 1.5.
const fee = await signingClient.calculateFee(signerAddress, messages, '', 1.7, feeGranterAddress);
- Sign and broadcast the transaction.
const broadcastResult = await signingClient.signAndBroadcast(signerAddress, messages, fee);if (broadcastResult.code !== undefined && broadcastResult.code !== 0) { alert("Failed to send tx: " + broadcastResult.log || broadcastResult.rawLog);} else { alert("Succeed to send tx:" + broadcastResult.transactionHash);}
Clone and try it yourself
You can find a working example of this frontend dapp in the dapp examples repository.