Off-ramp Flow

To off-ramp to a Holyheld account the following steps should be completed:

  1. Get settings and ensure that off-ramping is available using getServerSettings method.
  2. Check that selected wallet or holytag can transact using methods: validateAddress for a wallet or getTagInfoForTopUp for a $holytag.
  3. Provide two parameters: token and amount.
  4. Get binary data to pass as swap parameters using convertTokenToEUR or convertEURToToken methods.
  5. Call the topup method to execute the transaction.

🔔 If multiple wallet interactions are required (signing allowance and executing a transaction, or permit signing and executing a transaction), they will be processed automatically.

  1. Wait for the transaction hash of the operation to be received.

Here are the functions that are available for you to use.

getServerSettings Get settings:

This method gets current state/settings for interacting with the service. Please always use this method to check:

  • if the feature is available;
  • the minimum and maximum allowed amounts to off-ramp.

🔔 Please note, that financial values are provided and consumed as strings to avoid floating point conversion problems.

(async () => {
  const data = await holyheldSDK.getServerSettings();
})();

Types:

type Response = {
  external: {
    // indicates if the sending feature is available at the moment
    isTopupEnabled: boolean;
    // maximum amount (equivalent in EUR) that is allowed to be processed
    maxTopUpAmountInEUR: string; // example: '1000'
    // minimum amount (equivalent in EUR) that is allowed to be processed
    minTopUpAmountInEUR: string; // example: '5'
  };
  common: {
    // fee (in percent) that is deducted when making an off-ramping operation on mainnet
    topUpFeePercent: string; // 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.

🔔 Please note that a valid wallet address is 42 strings long and begins with 0x prefix.

🔔 Please note that this method does not support ENS domains.

(async () => {
  // a wallet address could be pre-set or have to be input by user, depends on the application
  const data = await holyheldSDK.validateAddress('0x000000000000000000000000000000000000dEaD');
})();

Types:

type Response = {
  isTopupAllowed: boolean;
  isOnRampAllowed: boolean;
}

getTagInfoForTopUp Get tag information:

$Holytag is a unique identifier which can have account, card and multiple Ethereum addresses bound to it. It is alphanumeric string with a few special characters allowed.

🔔 Please note that a valid HH tag could be as short as one character in length.

When displaying $holytag usually is 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, meaning if there is a tag $ToTheMoon registered, there couldn't be tag $toTHEmoon created afterwards.

🔔 Test $holytag

You can use TESTSDK as a test $holytag. All transactions to this $holytag will NOT trigger an actual fiat transaction, but will return a fully valid response. There is no minimum amount set for the test $holytag. Funds can be retrieved back. This test $holytag works across all supported networks an tokens.

(async () => {
  // a tag name could be pre-set or have to be input by user, depends on the application
  const data = await holyheldSDK.offRamp.getTagInfoForTopUp('TESTSDK');
})();

Types:

type Response = {
  // if the tag exists and active
  found: boolean;
  // tag name (with writing preserving capital case, as registered)
  tag?: string; // example: 'TESTSDK'
  // if created, a link to avatar image (tag can have avatar picture set)
  avatarSrc?: string; // 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. Holyheld natively supports 14 Networks. The full list of supported networks is here.

(async () => {
  const data = await holyheldSDK.getWalletBalances(
    '0x...', // user wallet address
  );
})();

Types:

import { Network } from '@holyheld/sdk';

type WalletToken = {
  // name of the token
  name: string; // example: 'Ether'
  // smart contract address of the token
  address: string; // example: '0x...'
  // token symbol
  symbol: string; // example: 'ETH'
  // token decimal digits (as in ERC20 implementation)
  decimals: number; // example: 18
  // network (blockchain), on which this token resides
  network: Network;
  // logo (picture) for the token
  iconURL: string; // example: 'https://holyheld.com/static/tokens/eth/eth.png'
  // current estimated price (in USD)
  priceUSD: string; // example: '1796.55'
  // amount of token in the user's wallet
  balance: string; // example: '0.0000099999999'
  // if the token supports permit signatures
  hasPermit: boolean;
  // type of permit signature, 'erc2612' is expected
  permitType?: string;
  // permit version (currently, if permit supported, '1' is expected)
  permitVersion?: string; // example: '1'
  // token price converted from USD valuation to EUR
  priceInEURForTopUp: string; // example: '1726.53'
};

type Response = {
  tokens: WalletToken[];
}

convertTokenToEUR Convert token to EUR:

This method is used to estimate a token value in EUR to proceed with the off-ramping. convertTokenToEUR method can also be used in some scenarios/apps where token to be sent is pre-set 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 off-ramping transaction.

import { Network } from '@holyheld/sdk';

(async () => {
  const data = await holyheldSDK.offRamp.convertTokenToEUR(
    '0x...', // token address
    6, // token decimals
    '9.99', // token amount
    Network.ethereum, // token network
  );
})();

Types:

import type { TransferData } from '@holyheld/sdk';

type Response = {
  // amount of token that was passed to query
  tokenAmount: string; // example: '1.99'
  // EUR valuation of the token amount provided
  EURAmount: string; // example: '314.25'
  // data to be passed in sending transaction for this specific token (and amount)
  transferData?: TransferData;
}

convertEURToToken Convert EUR to token:

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.

import { Network } from '@holyheld/sdk';

(async () => {
  const data = await holyheldSDK.offRamp.convertEURToToken(
    '0x...', // token address
    6, // token decimals
    '999.99', // EUR amount
    Network.ethereum, // token network
  );
})();

Types:

import type { TransferData } from '@holyheld/sdk';

type Response = {
  // amount (in EUR) that was passed to query
  EURAmount: string; // example: '30.00'
  // token amount to match expected valuation
  tokenAmount: string; // example: '4.18'
  // data to be passed in sending transaction for this specific token (and amount)
  transferData?: TransferData;
}

Off-ramp:

This is the 'main' method to call that executes off-ramping to the user card. Parameter values should be retrieved using methods described above, such as transferData matching token and token amount provided.

🚨 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, in order 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 callbackConfig; // callbacks
const chainId; // token chain id

// get chain entity from viem
const chain = Object.values(chains).find((item) => item.id === chainId);

// create viem public client
// https://viem.sh/docs/clients/public.html
const publicClient = createPublicClient({
  chain,
  transport: http(),
});

// wrap your provider in viem wallet client
// https://viem.sh/docs/clients/wallet.html
const walletClient = createWalletClient({
  chain,
  transport: custom(provider), // current provider in your app (see examples below)
  account: '0x...', // wallet address
});

(async () => {
  await holyheldSDK.offRamp.topup(
    publicClient,
    walletClient,
    '0x...', // wallet address
    '0x...', // token address
    Network.ethereum, // token network
    '5.25', // token amount
    transferData, // if was provided by 'convertTokenToEUR' and/or 'convertEURToToken'
    'TESTSDK', // funds recipient tag
    true, // true if connected wallet supportsSignTypedDataV4 (for more human friendly signature request)
    callbackConfig, // callbacks (see below)
  );
})();

Types:

enum TopUpStep {
  Confirming = 'confirming', // user is confirming action on review screen
  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;
}