In this guide we will provide an example of how to use the NFDomains API to send assets to and from an NFD's vault, as a reference for adding Vault support in your own application.
Overview
A vault is an Algorand account controlled by an NFD's smart contract that can automatically opt-in to assets it receives.
The vault account is the 'nfdAccount' property in all NFDs. It is the contract account of the NFD itself. As each NFD is a distinct contract instance, each NFD has its own account - its vault.
Sending TO a vault (or account) using the API will check if the receiver is already opted-in and just provide a transfer transaction instead. If the receivers vault is not opted-in and is unlocked (or you're the owner of the vault), then the API returns transactions to have the vault opt-in. The transactions will pay the MBR (.1 per asset) of the assets being sent, and then vault_optin calls to the vault to opt-in each of the assets, followed by asset transfers to the vault.
Sending FROM a vault follows a similar process, with the distinction that the receiverType must be designated as either a standard 'account' or another 'nfdVault'.
Vaults are locked by default, meaning only the NFD's owner can send assets to it. When the owner unlocks the vault, anyone can send assets to it. The owner can lock or unlock the vault at any time.
API
TypeScript Example
Setup
In this example we will create two very basic React components that will prompt the user to sign transactions for sending an asset to and from an NFD's vault.
We will use Axios for handling HTTP requests to fetch the transactions, and the @txnlab/use-wallet library to sign and send the transactions. Make sure these libraries are installed in your project:
npminstallaxios@txnlab/use-wallet
Note:@txnlab/use-wallet is not required, but it is used in this example to simplify the process of signing and sending transactions. See https://github.com/TxnLab/use-wallet for full setup instructions.
First we define functions for making requests to the NFD Vaults API using Axios. The sendToVault and sendFromVault functions will make POST requests to the /nfd/vault/sendTo/{name} and /nfd/vault/sendFrom/{name} endpoints, respectively.
// src/api.tsimport axios from'axios'constAPI_BASE_URL='https://api.nf.domains'interfaceSendToVaultRequestBody {/* Base amount (in base units of specified asset - so decimals must be considered) of asset to send. If multiple assets specified, amount is ignored and ALL of each are sent */ amount:number/* Algorand ASA IDs to transfer (and opt-in inside vault if necessary) - use asset 0 to send ALGO. Specifying multiple assets means ALL of each are sent and amount is ignored. 13 is max assets that can be specified if they're being sent (2 for MBR payments, 2 for opt-in txns (8+4 asset opt-ins), 12 asset transfers). If opt-in only then 64 is maximum (1 MBR per 8 assets, 8 assets per txn * 8 txns) */ assets:number[]/* Optional note to include in asset send transaction */ note?:string/* Whether to only opt-in to the asset, instead of including asset transfer txn */ optInOnly:boolean/* Sender of transaction, an Algorand account */ sender:string}exportfunctionsendToVault(name:string, data:SendToVaultRequestBody) {returnaxios<string>({ url:`${API_BASE_URL}/nfd/vault/sendTo/${name}`, method:'post', headers: { 'Content-Type':'application/json' }, data })}interfaceSendFromVaultRequestBody { amount:number/* Algorand ASA IDs to transfer FROM vault - use asset 0 to send ALGO. Specifying multiple assets means ALL of each are sent and amount is ignored. If receiver is a vault and needs to opt-in, then need MBR/opt-in pairs (5 pairs - 8 opt-ins each - 40 assets), then 6 send calls of 7 assets w/ 5 at end for total of 40. If receiver is already opted-in, then 112 (7 per txn, 16 tnxs) is max. */ assets:number[]/* Optional note to include in asset send transaction */ note?:string/* Algorand account or NFD Name (if vault receiver) the asset(s) should be sent to */ receiver:string/* Specifies that the receiver account is something the caller can sign for. If specified, then opt-in transactions it signs may be included */ receiverCanSign?:boolean/* Account or NFD Vault the asset should be sent to (if allowed) */ receiverType?:'account'|'nfdVault'/* Sender of transaction, must be NFD owner */ sender:string}exportfunctionsendFromVault(name:string, data:SendFromVaultRequestBody) {returnaxios<string>({ url:`${API_BASE_URL}/nfd/vault/sendFrom/${name}`, method:'post', headers: { 'Content-Type':'application/json' }, data })}
Send To Vault
Using the sendToVault function, we create a component that prompts the user to sign and send transactions for sending an asset to an NFD's vault.
If the sender is not the owner, the receiving vault must be unlocked to auto opt-in and receive assets
If the vault is locked, only the NFD owner can send assets to it
The NFD must be upgraded to smart contract version 2.6 or higher to receive vault assets
Using the sendFromVault function, we create a component that prompts the user to sign and send transactions for sending an asset from the vault of an NFD they own.
The transactions must be signed by the NFD's owner account
The receiver can be either an Algorand account or another NFD's vault (same rules described above apply to a receiving vault)
The NFD must be upgraded to smart contract version 2.6 or higher
// src/sendFromVault.tsximport React from'react'import { useWallet, encodeNFDTransactionsArray, TransactionsArray} from'@txnlab/use-wallet'import { sendFromVault } from'./api'exportdefaultfunctionSendFromVaultDemo() {constwallet=useWallet()const { activeAddress } = wallet // must match the NFD's `owner` accountasyncfunctionsignAndSendTransactions() {constNFD_NAME='doug.algo'constASSET_ID=212389838constAMOUNT=1constRECEIVER='receiver-address'// replace with valid Algorand accounttry {if (!activeAddress) {thrownewError('No account connected') }constresponse=awaitsendFromVault(NFD_NAME, { assets: [ASSET_ID], amount:AMOUNT, receiver:RECEIVER, receiverType:'account' })if (typeofresponse.data !=='string') {thrownewError('Failed to fetch transactions') }consttransactionsArray=JSON.parse(response.data) asTransactionsArrayconstsignedTransactions=awaitwallet.signTransactions(encodeNFDTransactionsArray(transactionsArray) )const { id } =awaitwallet.sendTransactions(signedTransactions)console.log(`Successfully sent asset ${ASSET_ID} from ${NFD_NAME}'s vault!`,`Transaction ID: ${id}` ) } catch (error) {console.error(`Send from vault failed`, error) } }if (!activeAddress) {return <p>Connect an account first.</p> }return ( <div> <buttontype="button"onClick={signAndSendTransactions}> Sign and send transactions </button> </div> )}
Base amount (in base units of specified asset - so decimals must be considered) of asset to send. If multiple assets are specified, amount is should be 0 as ALL of each are sent and closed out
Example: 21430180502795
assets*array of integer
Algorand ASA IDs to transfer FROM vault - use asset 0 to send ALGO. Specifying multiple assets means ALL of each are sent and amount is ignored. If destination is vault and needs to opt-in, then need MBR/opt-in pairs (5 pairs - 8 opt-ins each - 40 assets), then 6 send calls of 7 assets w/ 5 at end for total of 40. If destination is already opted-in, then 112 (7 per txn, 16 tnxs) is max.
notestring
Optional note to include in asset send transaction
Example: "xqz"
receiver*string
Algorand account or NFD Name (if vault destination) the asset(s) should be sent to
Example: "Ut et ea vitae."
receiverCanSignboolean
Specifies that the receiver account is something the caller can sign for. If specified, then opt-in transactions it signs may be included
Example: true
receiverTypeenum
Account or NFD Vault the asset should be sent to (if allowed)
Returns array of paired values representing a transaction group to submit to an Algorand node. U or S for unsigned or signed, followed by the base64-encoded message-pack of an unsigned transaction (to be signed by sender/buyer) or a signed transaction to be submitted as-is.
Body
string
Example: "Velit qui qui tenetur."
Request
constresponse=awaitfetch('https://api.nf.domains/nfd/vault/sendFrom/{name}', { method:'POST', headers: {"Content-Type":"application/json" }, body:JSON.stringify({"amount":34772186958805,"assets": [13992502780418464000 ],"note":"sgm","receiver":"Perspiciatis est autem praesentium quidem.","receiverCanSign":false,"receiverType":"nfdVault","sender":"DWVJ7JWRA574PKRFMJF47W6RMWW4FVAPVBQ4I5Y3MYTJIN4LTN5F2EMBGV" }),});constdata=awaitresponse.json();
Response
Velit qui qui tenetur.
sendToVault nfd
Provide transaction to send an asset owned by sender account to an NFD vault. Call to have opt-in to vault will be included if necessary. Callable by NFD owner, or if Opt-in is UNLOCKED (or asset already opted-in), anyone can call
Base amount (in base units of specified asset - so decimals must be considered) of asset to send. If multiple assets specified, amount is ignored and ALL of each are sent
Example: 82202057335358
assets*array of integer
Algorand ASA IDs to transfer (and opt-in inside vault if necessary) - use asset 0 to send ALGO. Specifying multiple assets means ALL of each are sent and amount is ignored. 13 is max assets that can be specified if they're being sent (2 for MBR payments, 2 for opt-in txns (8+4 asset opt-ins), 12 asset transfers). If opt-in only then 64 is maximum (1 MBR per 8 assets, 8 assets per txn * 8 txns)
notestring
Optional note to include in asset send transaction
Example: "3ms"
optInOnly*boolean
Whether to only opt-in to the asset, instead of including asset transfer txn
Returns array of paired values representing a transaction group to submit to an Algorand node. U or S for unsigned or signed, followed by the base64-encoded message-pack of an unsigned transaction (to be signed by sender/buyer) or a signed transaction to be submitted as-is.