Offramp Flow
To offramp to a Holyheld account the following steps should be completed:
- Get settings and ensure that offramping is available using
getServerSettings
method. - Check that selected wallet or holytag can transact using methods:
validateAddress
for a wallet orgetTagInfo
for a $holytag. - Provide two parameters: token and amount.
- Get binary data to pass as swap parameters using
convertTokenToEUR
orconvertEURToToken
methods. - Call the
topup
method to execute the transaction.
🔔 Please note! If multiple wallet interactions are required (e.g. signing allowance and executing a transaction, or permit signing and executing a transaction) they will be processed automatically.
- Wait for the transaction hash of the operation to be received.
There are six functions available to use:
getServerSettings
- to get server settings.validateAddress
- to get wallet information.getTagInfo
- to get holytag information.convertTokenToEUR
- to get a EUR quote for a specific amount of tokens.convertEURToToken
- to get a a token quote for a specific amount of EUR.topup
- to execute offramp.
getServerSettings
Get settings
This method gets current state/settings when interacting with the service. Please always use this method to check:
- if the feature is available;
- the minimum and maximum allowed amounts to offramp.
🔔 Please note! Financial values are provided and consumed as strings to avoid floating point conversion problems.
(async () => {
const data = await holyheldSDK.getServerSettings();
})();
Types:
type ServerExternalSettings = {
external: {
isTopupEnabled: boolean; // indicates if offramp is available at the moment
isOnRampEnabled: true; // indicates if onramp is available at the moment
maxTopUpAmountInEUR: string; // maximum amount (equivalent in EUR) that is allowed to be processed, for example: '1000'
minTopUpAmountInEUR: string; // minimum amount (equivalent in EUR) that is allowed to be processed, for example '5'
maxOnRampAmountInEUR: string; // maximum amount in EUR that is allowed to be processed, for example: '1000'
minOnRampAmountInEUR: string; // minimum amount in EUR that is allowed to be processed, for example: '5'
};
common: {
topUpFeePercent: string; // fee (in percent) that is deducted when making an offramp operation, for example: '0.75'
};
}
validateAddress
Get wallet information
User wallet address is a unique identifier which can have account, card and a $holytag bound to it. It is alphanumeric string. Wallet address must be a valid EVM (0x..., 42 chars) or Solana (Base58, ~32–44 chars) address.
🔔 Please note! Ethereum Name Service (ENS) and Solana Name Service (SNS) domains are not supported.
(async () => {
const data = await holyheldSDK.validateAddress('0x000000000000000000000000000000000000dEaD'); // a wallet address could be preset or have to be entered by user, depends on what user flow you as a developer want to set
})();
Types:
type ValidateAddressResult = {
isTopupAllowed: boolean;
isOnRampAllowed: boolean;
}
getTagInfo
Get tag information
$holytag is a unique identifier which can have account, card and multiple Ethereum and/or Solana addresses bound to it. $holytag is alphanumeric string with a few special characters allowed. A valid holytag can be as short as one (1) and as long as thirty one (31) characters.
🔔 Please note! The only two special characters allowed are: dash
-
and underscore_
.
$holytag is usually displayed prepended with a $
prefix, for example: $JohnSmith holytag is JohnSmith
or $PEPE holytag PEPE
, etc.
Tags are stored case-sensitive for display, but not case-sensitive for search, and are not allowed to have multiple case variants registered. It means that if there is a holytag $ToTheMoon
registered, other case sensitive variations are not allowed (e.g. $toTHEmoon
).
Test $holytag
You can use SDKTEST
as a test $holytag. All transactions to this $holytag will NOT trigger an actual fiat-corresponding transaction, but will return a fully valid response. There is no minimum amount set for the test $holytag. SDKTEST
test $holytag works across all supported networks and tokens.
🔔 Please note! Funds from test transactions to
SDKTEST
can NOT be retrieved. Do not initiate large test transactions.
(async () => {
// a tag name could be preset by the developer (you) or inputted by the user. It depends on the user flow you want to have
const data = await holyheldSDK.getTagInfo('SDKTEST');
})();
Types:
type TagInfo = {
found: boolean; // if the holytag exists and active
tag?: string; // holytag name (case sensitive, as registered), for example: 'SDKTEST'
avatarSrc?: string; // if set, a link to avatar image, for example example: 'https://holyheld.com/static/avatar.png'
}
getWalletBalances
Get wallet balances
You can use getWalletBalances
method to retrieve all tokens on the connected user wallet address. The full list of supported networks is here.
EVM Networks
(async () => {
const data = await holyheldSDK.evm.getWalletBalances(
'0x...', // user wallet address
);
})();
Types:
import { Network } from '@holyheld/sdk';
type WalletTokenEVM = {
name: string; // name of the token, for example: 'USD Coin'
address: string; // smart contract address of the token, for example: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
symbol: string; // token symbol, for example: 'USDC'
decimals: number; // token decimal digits (as in ERC20 implementation), for example: 6
network: Network; // network (blockchain), on which this token resides
networkKind: NetworkKind // blockchain type
iconURL: string; // logo (icon) for the token
priceUSD: string; // current estimated price (in USD), for example: '1796.55'
balance: string; // amount of token in the user's wallet, for example: '0.0000099999999'
priceInEURForTopUp: string; // token price converted from USD to EUR, for example: '1726.53'
meta: {
permitData: {
hasPermit: boolean; // if the token supports permit signatures
permitType?: string; // type of permit signature, 'erc2612' is expected
permitVersion?: string; // permit version (currently, if permit supported, '1' is expected)
}
}
};
type WalletBalancesEVM = {
tokens: WalletTokenEVM[];
}
Solana Network
(async () => {
const data = await holyheldSDK.solana.getWalletBalances(
'...', // user wallet address
);
})();
Types:
import { Network } from '@holyheld/sdk';
type WalletTokenSolana = {
name: string; // name of the token, for example: 'Solana'
decimals: number; // token decimal digits, for example: '9'
address: string; // smart contract address of the token, for example: 'So11111111111111111111111111111111111111112'
symbol: string; // token symbol, for example: 'SOL'
network: SolanaNetwork; // network (blockchain), on which this token resides
networkKind: NetworkKind.Solana // blockchain type
iconURL: string; // logo (icon) for the token
priceUSD: string; // example: '1796.55' // current estimated price (in USD)
balance: string; // amount of token in the user's wallet, for example: '0.0000099999999'
priceInEURForTopUp: string; // token price converted from USD to EUR, for example: '1726.53'
meta: {
tokenProgramId?: string; // SPL token program address (usually the standard TokenkegQfeZyi...)
}
};
type WalletBalancesSolana = {
tokens: WalletTokenSolana[];
}
convertTokenToEUR
token to EUR quote
This method is used to estimate a token value in EUR to proceed with the offramping. convertTokenToEUR
method can also be used in some scenarios/apps where token to be sent is preset and not selectable.
This method also returns transferData
— a hexadecimal string which can contain token-specific transfer, unwrap or swap data that is passed in an offramp transaction.
EVM Networks
import { Network } from '@holyheld/sdk';
(async () => {
const data = await holyheldSDK.evm.offRamp.convertTokenToEUR({
walletAddress: '0x...', // wallet address
tokenAddress: '0x...', // token address
tokenDecimals: 6, // token decimals
amount: '9.99', // token amount
network: Network.ethereum, // token network
});
})();
Types:
import type { TransferDataEVM } from '@holyheld/sdk';
type ConvertTopUpDataEVM = {
tokenAmount: string; // amount of token that was passed to query, for example: '1.99'
EURAmount: string; // EUR valuation of the token amount provided, for example: '314.25'
transferData?: TransferDataEVM; // data to be passed in sending transaction for this specific token (and amount)
}
Solana Network
import { SolanaNetwork } from '@holyheld/sdk';
(async () => {
const data = await holyheldSDK.solana.offRamp.convertTokenToEUR({
walletAddress: '...', // wallet address
tokenAddress: '...', // token address
tokenDecimals: 6, // token decimals
amount: '9.99', // token amount
network: SolanaNetwork.Mainnet, // token network
});
})();
Types:
import type { TransferDataSolana } from '@holyheld/sdk';
type ConvertTopUpDataSolana = {
tokenAmount: string; // amount of token that was passed to query, for example: '1.99'
EURAmount: string; // EUR valuation of the token amount provided, for example: '314.25'
transferData?: TransferDataSolana; // data to be passed in sending transaction for this specific token (and amount)
}
convertEURToToken
EUR to token quote
convertEURToToken
method returns a calculated token amount to match provided (expected) EUR amount.
This method also returns transferData
, that is hexadecimal string which could contain token-specific transfer, unwrap or swap data that is passed in sending to tag transaction.
EVM Networks
import { Network } from '@holyheld/sdk';
(async () => {
const data = await holyheldSDK.evm.offRamp.convertEURToToken({
walletAddress: '0x...', // wallet address
tokenAddress: '0x...', // token address
tokenDecimals: 6, // token decimals
amount: '9.99', // token amount
network: Network.ethereum, // token network
});
})();
Types:
import type { TransferDataEVM } from '@holyheld/sdk';
type ConvertTopUpDataEVM = {
EURAmount: string; // amount (in EUR) that was passed to query, for example: '30.00'
tokenAmount: string; // token amount to match expected valuation, for example: '4.18'
transferData?: TransferDataEVM; // data to be passed in sending transaction for this specific token (and amount)
}
Solana Network
import { Network } from '@holyheld/sdk';
(async () => {
const data = await holyheldSDK.solana.offRamp.convertEURToToken({
walletAddress: '0x...', // wallet address
tokenAddress: '0x...', // token address
tokenDecimals: 6, // token decimals
amount: '9.99', // token amount
network: SolanaNetwork.Mainnet, // token network
});
})();
Types:
import type { TransferDataSolana } from '@holyheld/sdk';
type ConvertTopUpDataSolana = {
tokenAmount: string; // amount of token that was passed to query, for example: '1.99'
EURAmount: string; // EUR valuation of the token amount provided, for example: '314.25'
transferData?: TransferDataSolana; // data to be passed in sending transaction for this specific token (and amount)
}
Offramp
This is the 'main' method to call that executes offramping to the user card. Parameter values should be retrieved using methods described above, such as transferData
matching token and token amount provided.
EVM Networks
🚨 Please note! Some wallets like Metamask are single-network handled. It means that while Holyheld can return/accept transaction on any supported network, user must switch to the correct network in the wallet for the transaction to be processed.
import { Network } from '@holyheld/sdk';
import * as chains from 'viem/chains';
import { createPublicClient, createWalletClient, custom, http } from 'viem';
const provider; // current provider in your app (see examples below)
const transferData; // transfer data from conversion methods or undefined
const eventConfig; // callbacks
const chainId; // token chain id
const chain = Object.values(chains).find((item) => item.id === chainId); // get chain entity from viem
const publicClient = createPublicClient({ // create viem public client - https://viem.sh/docs/clients/public.html
chain,
transport: http(),
});
const walletClient = createWalletClient({ // wrap your provider in viem wallet client - https://viem.sh/docs/clients/wallet.html
chain,
transport: custom(provider), // current provider in your app (see examples below)
account: '0x...', // wallet address
});
(async () => {
await holyheldSDK.evm.offRamp.topup({
publicClient: publicClient,
walletClient: walletClient,
walletAddress: '0x...',
tokenAddress: '0x...',
tokenNetwork: Network.ethereum,
tokenAmount: '5.25',
transferData: transferData, // if was provided by 'convertTokenToEUR' and/or 'convertEURToToken'
holytag: 'SDKTEST', // funds recipient tag
supportsSignTypedDataV4: true, // true if connected wallet supports eth_signTypedData_v4 (default: false)
supportsRawTransactionsSigning: true, // true if connected wallet supports raw transactions signing via "eth_sign" or "eth_signTransaction"
eventConfig: eventConfig, // callbacks (see below)
});
})();
Types:
enum TopUpStep {
Confirming = 'confirming', // user is confirming action
Approving = 'approving', // a request was sent to wallet for approval or permit signature
Sending = 'sending', // a request was sent to wallet for executing sending funds to a tag
}
interface TopUpCallbackConfig {
onHashGenerate?: (hash: string) => void;
onStepChange?: (step: TopUpStep) => void;
}
Solana
import { Connection, clusterApiUrl } from '@solana/web3.js';
import { PhantomWalletAdapter } from '@solana/wallet-adapter-phantom';
import { SolanaNetwork, createSolanaWalletClientFromAdapter } from '@holyheld/sdk';
const transferData; // transfer data from conversion methods or undefined
const eventConfig; // callbacks
const networkInfo = holyheldSDK.solana.getNetwork(SolanaNetwork.Mainnet);
const connection = new Connection(networkInfo.httpRpcURL, {
commitment: 'confirmed',
wsEndpoint: networkInfo.wsRpcURL ?? clusterApiUrl(networkInfo.cluster, true)
});
const walletAdapter = new PhantomWalletAdapter();
const walletClient = createSolanaWalletClientFromAdapter(walletAdapter, connection);
(async () => {
await holyheldSDK.solana.offRamp.topup({
connection: connection,
walletClient: walletClient,
walletAddress: '...',
tokenAddress: '...',
tokenNetwork: SolanaNetwork.Mainnet,
tokenAmount: '5.25',
transferData: transferData, // if was provided by 'convertTokenToEUR' and/or 'convertEURToToken'
holytag: 'SDKTEST', // funds recipient tag
eventConfig: {}, // callbacks (see below)
});
})();
Types:
enum TopUpStep {
Confirming = 'confirming', // user is confirming action
Sending = 'sending', // a request was sent to wallet for executing sending funds to a tag
}
interface TopUpCallbackConfig {
onHashGenerate?: (hash: string) => void;
onStepChange?: (step: TopUpStep) => void;
}