Allowances grant another account (spender) the right to transfer HBAR, fungible tokens, and non-fungible tokens from your account (owner). The ability to approve allowances is important because it enables applications like exchanges and wallets to perform transfers on behalf of their customers without requiring a customer to sign every single transaction in advance. You can approve allowances and perform approved transfers on Hedera as you build things like NFT exchanges, marketplaces for carbon assets, games, and more.
This tutorial shows you how to approve HBAR allowances using the Hedera JavaScript SDK.
This example guides you through the following steps:
After completing all steps, your console should look something like this:
There are four entities in this scenario: Operator, Treasury, Alice, and Bob. Your testnet credentials from the Hedera portal should be used for the operator variables, which are used to initialize the Hedera client that submits transactions to the network and gets confirmations.
console.log(`\nSTEP 1 ===================================\n`); console.log(`- Creating Hedera accounts...\n`); const initBalance = new Hbar(10); const treasuryKey = PrivateKey.generateED25519(); const [treasurySt, treasuryId] = await accountCreateFcn(treasuryKey, initBalance, client); console.log(`- Treasury's account: https://hashscan.io/#/testnet/account/${treasuryId}`); const aliceKey = PrivateKey.generateED25519(); const [aliceSt, aliceId] = await accountCreateFcn(aliceKey, initBalance, client); console.log(`- Alice's account: https://hashscan.io/#/testnet/account/${aliceId}`); const bobKey = PrivateKey.generateED25519(); const [bobSt, bobId] = await accountCreateFcn(bobKey, initBalance, client); console.log(`- Bob's account: https://hashscan.io/#/testnet/account/${bobId}`);
Using accountCreateFcn simplifies the account creation process and is reusable in case you need to create more accounts in the future. This function uses the AccountCreateTransaction() class of the SDK. We’ll use this modular approach throughout the article.
async function accountCreateFcn(pvKey, iBal, client) { const response = await new AccountCreateTransaction() .setInitialBalance(iBal) .setKey(pvKey.publicKey) .setMaxAutomaticTokenAssociations(10) .execute(client); const receipt = await response.getReceipt(client); return [receipt.status, receipt.accountId]; }
Console Output:
STEP 1 ===================================
- Creating Hedera accounts...
- Treasury's account: https://hashscan.io/#/testnet/account/0.0.48520992
- Alice's account: https://hashscan.io/#/testnet/account/0.0.48520993
- Bob's account: https://hashscan.io/#/testnet/account/0.0.48520995
From the account creation in the previous step, Treasury has a balance of 10 HBAR.
console.log(`\nSTEP 2 ===================================\n`); console.log(`- Treasury approving HBAR allowance for Alice...\n`); let allowBal = new Hbar(10); const allowanceApproveHbarRx = await approvals.hbarAllowanceFcn(treasuryId, aliceId, allowBal, treasuryKey, client); console.log(`- Allowance approval status: ${allowanceApproveHbarRx.status}`); console.log(`- https://testnet.mirrornode.hedera.com/api/v1/accounts/${treasuryId}/allowances/crypto \n`); await queries.balanceCheckerFcn(treasuryId, [], client); await queries.balanceCheckerFcn(aliceId, [], client); await queries.balanceCheckerFcn(bobId, [], client);
The function approvals.hbarAllowanceFcn uses AccountAllowanceApproveTransaction() from the SDK to grant the allowance for the spender from an owner’s account balance. The function queries.balanceCheckerFcn uses AccountBalanceQuery() to check and display the HBAR balance (and optionally a token balance) for a given account ID or contract ID.
export async function hbarAllowanceFcn(owner, spender, allowBal, pvKey, client) { const allowanceTx = new AccountAllowanceApproveTransaction().approveHbarAllowance(owner, spender, allowBal).freezeWith(client); const allowanceSign = await allowanceTx.sign(pvKey); const allowanceSubmit = await allowanceSign.execute(client); const allowanceRx = await allowanceSubmit.getReceipt(client); return allowanceRx; }
export async function balanceCheckerFcn(acId, tkId, client) { let balanceCheckTx = []; try { balanceCheckTx = await new AccountBalanceQuery().setAccountId(acId).execute(client); console.log( `- Balance of account ${acId}: ${balanceCheckTx.hbars.toString()} + ${balanceCheckTx.tokens._map.get( tkId.toString() )} unit(s) of token ${tkId}` ); } catch { balanceCheckTx = await new AccountBalanceQuery().setContractId(acId).execute(client); console.log( `- Balance of contract ${acId}: ${balanceCheckTx.hbars.toString()} + ${balanceCheckTx.tokens._map.get( tkId.toString() )} unit(s) of token ${tkId}` ); } }
STEP 2 ===================================
- Treasury approving HBAR allowance for Alice...
- Allowance approval status: SUCCESS
- https://testnet.mirrornode.hedera.com/api/v1/accounts/0.0.48520992/allowances/crypto
- Balance of account 0.0.48520992: 10 ℏ + undefined unit(s) of token
- Balance of account 0.0.48520993: 10 ℏ + undefined unit(s) of token
- Balance of account 0.0.48520995: 10 ℏ + undefined unit(s) of token
In this step, Alice spends 8 HBAR (sendBal) from the allowance granted by Treasury. This means that Alice transfers 8 HBAR from Treasury to Bob.
console.log(`\nSTEP 3 ===================================\n`); console.log(`- Alice performing allowance transfer from Treasury to Bob...\n`); const sendBal = new Hbar(8); // Spender must generate the TX ID or be the client const allowanceSendHbarRx = await transfers.hbarAllowanceFcn(treasuryId, bobId, sendBal, aliceId, aliceKey, client); console.log(`- Allowance transfer status: ${allowanceSendHbarRx.status} \n`); await queries.balanceCheckerFcn(treasuryId, [], client); await queries.balanceCheckerFcn(aliceId, [], client); await queries.balanceCheckerFcn(bobId, [], client);
The function transfers.hbarAllowanceFcn uses TransferTransaction() from the SDK to enable a spender to use an allowance approved by an owner. Notice the following:
export async function hbarAllowanceFcn(owner, receiver, sendBal, spender, spenderPvKey, client) { const approvedSendTx = new TransferTransaction() .addApprovedHbarTransfer(owner, sendBal.negated()) .addHbarTransfer(receiver, sendBal) .setTransactionId(TransactionId.generate(spender)) // Spender must generate the TX ID or be the client .freezeWith(client); const approvedSendSign = await approvedSendTx.sign(spenderPvKey); const approvedSendSubmit = await approvedSendSign.execute(client); const approvedSendRx = await approvedSendSubmit.getReceipt(client); return approvedSendRx; }
STEP 3 ===================================
- Alice performing allowance transfer from Treasury to Bob...
- Allowance transfer status: SUCCESS
- Balance of account 0.0.48520992: 2 ℏ + undefined unit(s) of token
- Balance of account 0.0.48520993: 9.9971708 ℏ + undefined unit(s) of token
- Balance of account 0.0.48520995: 18 ℏ + undefined unit(s) of token
In this step, Treasury removes the HBAR allowance for Alice. HBAR allowances are removed by simply setting the allowance value to zero. The function approvals.hbarAllowanceFcn from before is used again, but now passing a value of 0 HBAR.
The last step is to join the Hedera Developer Discord!
console.log(`\nSTEP 4 ===================================\n`); console.log(`- Treasury deleting HBAR allowance for Alice...\n`); allowBal = new Hbar(0); const allowanceDeleteHbarRx = await approvals.hbarAllowanceFcn(treasuryId, aliceId, allowBal, treasuryKey, client); console.log(`- Allowance deletion status: ${allowanceDeleteHbarRx.status}`); console.log(`- https://testnet.mirrornode.hedera.com/api/v1/accounts/${treasuryId}/allowances/crypto`); console.log(` ==================================================== THE END - NOW JOIN: https://hedera.com/discord ====================================================\n`);
STEP 4 ===================================
- Treasury deleting HBAR allowance for Alice...
- Allowance deletion status: SUCCESS
- https://testnet.mirrornode.hed...
====================================================
🎉🎉 THE END - NOW JOIN: https://hedera.com/discord
Now you know how to approve HBAR allowances on Hedera using the JavaScript SDK. You can try this example with the other officially supported SDKs for Java, Go, and Swift.