HollaEx Forum - Latest posts https://forum.hollaex.com Latest posts Level up/down based on trading volume Below is a sample volume-based tier plugin.

It automatically upgrades or downgrades users based on their trading volume over a rolling 30-day period.

1. Tiers are defined statically

const TIERS = [
  { level: 1, min: 0 },
  { level: 2, min: 1000 },
  { level: 3, min: 10000 },
  { level: 4, min: 50000 }
];

Each tier sets:

  • level → the verification level

  • min → minimum required volume (in native currency)

You can adjust these thresholds as needed.

2. Rolling window

const VOLUME_WINDOW_DAYS = 30;

The plugin calculates total trading volume for each user within this period.

3. Automatic update

For each user:

  • It sums their trades (converted to native currency).

  • It determines the correct tier.

  • If their current level differs, it updates it.

The cron job runs daily, but you can change the schedule if needed.

This provides a simple, fully customizable way to implement volume-based tiering.

'use strict';

/**
 * Simple Static Volume-Based Tier Plugin
 *
 * - Calculates rolling 30-day trading volume
 * - Converts to native currency using oracle prices
 * - Automatically upgrades/downgrades users
 * - Runs once per day
 */

module.exports = async function () {
	const { loggerPlugin, toolsLib, moment, cron } = this;

	// -----------------------------
	// Static Configuration
	// -----------------------------

	const VOLUME_WINDOW_DAYS = 30;

	// Define tier thresholds here
	// Ordered from lowest to highest
	const TIERS = [
		{ level: 1, min: 0 },
		{ level: 2, min: 1000 },
		{ level: 3, min: 10000 },
		{ level: 4, min: 50000 }
	];

	// -----------------------------
	// Helpers
	// -----------------------------

	const determineLevelFromVolume = (volume) => {
		let level = TIERS[0].level;

		for (const tier of TIERS) {
			if (volume >= tier.min) {
				level = tier.level;
			}
		}

		return level;
	};

	const getOracleIndex = async () => {
		const coins = toolsLib.getKitCoins();
		return toolsLib.getAssetsPrices(
			coins,
			toolsLib.getKitConfig().native_currency
		);
	};

	const calculateUserTradeVolume = async (user_id, from, to) => {
		let volume = 0;

		const oracleIndex = await getOracleIndex();
		const native = toolsLib.getKitConfig().native_currency;

		const trades = await toolsLib.order.getAllUserTradesByKitId(
			user_id,
			null, null, null, null, null,
			from,
			to,
			'all'
		);

		for (const trade of (trades.data || [])) {
			let size = Number(trade.size) || 0;
			const base = trade.symbol.split('-')[0];

			if (base !== native) {
				const price = oracleIndex[base];
				if (!price || price <= 0) continue;
				size = size * price;
			}

			volume += size;
		}

		return volume;
	};

	// -----------------------------
	// Main Tier Logic
	// -----------------------------

	const runVolumeTiering = async () => {
		try {
			const now = moment().seconds(0).milliseconds(0);
			const from = now.clone().subtract(VOLUME_WINDOW_DAYS, 'days').toISOString();
			const to = now.toISOString();

			const users = await toolsLib.database.findAll('user', {
				where: { activated: true, flagged: false },
				raw: true,
				attributes: ['id', 'verification_level']
			});

			for (const user of users) {
				const volume = await calculateUserTradeVolume(user.id, from, to);
				const newLevel = determineLevelFromVolume(volume);

				if (user.verification_level !== newLevel) {
					loggerPlugin.info(
						`volume-tier update: user=${user.id} volume=${volume} ${user.verification_level} -> ${newLevel}`
					);

					await toolsLib.user.changeUserVerificationLevelById(
						user.id,
						newLevel
					);
				}
			}
		} catch (err) {
			loggerPlugin.error('runVolumeTiering error', err.message);
		}
	};

	// -----------------------------
	// Daily Execution (00:00 UTC)
	// -----------------------------

	cron.schedule('0 0 * * *', runVolumeTiering, {
		timezone: 'UTC'
	}).start();

	loggerPlugin.info('static volume-based tier plugin initialized');
};
]]>
https://forum.hollaex.com/t/level-up-down-based-on-trading-volume/2079#post_4 Tue, 03 Mar 2026 21:53:55 +0000 forum.hollaex.com-post-3819
Mobile App version management

Yes, we support backend-controlled app versioning for both iOS and Android without requiring a new app release.

Operators can configure version values directly from the Operator Control Panel → General → Apps section. Specifically, you can set:

  • Current Version

  • Minimum Version

  • Store URLs (iOS / Android)

These values are exposed publicly via the /kit endpoint under the apps object. The mobile application can read these values at runtime and apply different upgrade logics accordingly.

Hard vs. Soft Upgrade

The platform provides the version values, and the mobile app implements the enforcement logic:

  • Hard upgrade: If the app version is below min_version, the app can block access and force the user to update.

  • Soft upgrade: If the app version is below current_version but above min_version, the app can display an optional update prompt.

This allows full flexibility in how strict the upgrade policy should be, without requiring a new app release.

Version Check Endpoint

  • Endpoint: GET /kit

  • Field: apps

  • Includes: current_version, min_version, and store URLs.

This configuration can be managed by the exchange operator (Admin role) via the Operator Control Panel.

]]>
https://forum.hollaex.com/t/mobile-app-version-management/2127#post_2 Tue, 03 Mar 2026 21:41:20 +0000 forum.hollaex.com-post-3818
How to use a root domain for the cloud exchange Hey there.

You can definitely use a root domain here but you’ll need to add the domain to Cloudflare first.

There’s an official document for this so please take a look.

  1. Go to Cloudflare and click “Add a Site,” then enter your root domain.
  2. Choose the free plan (the free plan is fine for most of the users), and Cloudflare will scan your existing DNS records. After that, it will give you two nameservers.
  3. Next, go to your domain registrar (where you bought the domain) and replace the current nameservers with the ones Cloudflare provides.
  4. Come back to the HollaEx dashboard and go through the domain setup again.

TL;DR: Configure it in Cloudflare first and go through the dashboard setup.

Cheers!

]]>
https://forum.hollaex.com/t/how-to-use-a-root-domain-for-the-cloud-exchange/2134#post_2 Tue, 17 Feb 2026 15:46:20 +0000 forum.hollaex.com-post-3810
How to use a root domain for the cloud exchange Hi guys!

I want to use a root domain for my cloud exchange (something like example.com, without a subdomain), but the dashboard is showing me this popup and doesn’t let me continue. What should I do?

Thanks in advance.

]]>
https://forum.hollaex.com/t/how-to-use-a-root-domain-for-the-cloud-exchange/2134#post_1 Tue, 17 Feb 2026 15:34:57 +0000 forum.hollaex.com-post-3809
Mobile App version management Do you support backend-controlled minimum app versions for iOS and Android that can be managed without releasing a new app? If so, could you share details on hard vs. soft upgrade behavior, the version-check endpoint, expected behavior if the endpoint is unreachable, and who can manage this configuration?

]]>
https://forum.hollaex.com/t/mobile-app-version-management/2127#post_1 Tue, 27 Jan 2026 01:40:42 +0000 forum.hollaex.com-post-3802
Custom Wallet Custody bumping this as i also would like to know more about this

]]>
https://forum.hollaex.com/t/custom-wallet-custody/2102#post_2 Fri, 23 Jan 2026 04:48:58 +0000 forum.hollaex.com-post-3798
Hello about an application This is a public forum. You should ask [email protected].

]]>
https://forum.hollaex.com/t/hello-about-an-application/2106#post_2 Fri, 09 Jan 2026 02:49:12 +0000 forum.hollaex.com-post-3782
Hello about an application Can you give me an application update about the first form i filled on hollaex?

]]>
https://forum.hollaex.com/t/hello-about-an-application/2106#post_1 Wed, 07 Jan 2026 11:05:04 +0000 forum.hollaex.com-post-3779
Custom Wallet Custody Hi all,

Is there a way to use different wallet for my exchange? For example, if we currently have users and wallets already but want to use the exchange with our existing system?

]]>
https://forum.hollaex.com/t/custom-wallet-custody/2102#post_1 Tue, 06 Jan 2026 03:41:07 +0000 forum.hollaex.com-post-3775
How to install npm dependencies for plugins? You don’t install npm packages manually inside a HollaEx plugin.

Instead, plugins support a prescript field in the plugin’s .json file. This is the recommended and supported way to install dependencies.

You can define multiple npm packages there, and they’ll be installed automatically when the plugin is built/loaded.

Example:

"prescript": {
  "run": null,
  "install": [
    "aws-sdk",
    "awesome-phonenumber"
  ]
}

If you need a specific version, you can specify it directly:

"install": [
  "[email protected]",
  "[email protected]"
]

Notes / best practices

  • HollaEx plugins already have access to some pre-installed core dependencies, so you don’t need to reinstall common libraries unless you need a specific version.
  • Any additional third-party library can be added via prescript.
  • Avoid very large or unnecessary dependencies to keep plugin load time fast.
  • Version pinning is recommended for production plugins to avoid unexpected breaking changes.

Below is a list of libraries that are already available in the plugins:

[
  "express",
  "morgan",
  "cors",
  "latest-version",
  "npm-programmatic",
  "sequelize",
  "eval",
  "hollaex-tools-lib",
  "lodash",
  "express-validator",
  "multer",
  "moment",
  "mathjs",
  "bluebird",
  "umzug",
  "request-promise",
  "uuid",
  "jsonwebtoken",
  "moment-timezone",
  "json2csv",
  "flat",
  "ws",
  "node-cron",
  "random-string",
  "bcryptjs",
  "expect-ct",
  "validator",
  "otp",
  "geoip-lite",
  "nodemailer",
  "ws-heartbeat",
  "winston",
  "elastic-apm-node",
  "winston-elasticsearch-apm",
  "triple-beam",
  "uglify-js",
  "body-parser",
  "express-limiter"
]
]]>
https://forum.hollaex.com/t/how-to-install-npm-dependencies-for-plugins/2091#post_2 Sun, 04 Jan 2026 00:08:42 +0000 forum.hollaex.com-post-3768
How to install npm dependencies for plugins? Hi guys,

Go question on installing npm dependencies for my plugins. How do you do it? I know HollaEx plugins include some pre-installed dependencies, but what is best way to use them?

Also, how to add other libraries beyond the above?

]]>
https://forum.hollaex.com/t/how-to-install-npm-dependencies-for-plugins/2091#post_1 Tue, 23 Dec 2025 07:07:49 +0000 forum.hollaex.com-post-3763
Level up/down based on trading volume +1, would also like this plugin

]]>
https://forum.hollaex.com/t/level-up-down-based-on-trading-volume/2079#post_3 Fri, 19 Dec 2025 07:09:43 +0000 forum.hollaex.com-post-3757
Is there a way to make the footer links hidden? Looks nice!

I just want to highlight that in the code snippet posted by @Ella the lines highlighted below is quite important. It tries to run the function 0.5 second after the site is loaded in order to avoid site rerendering on ReactJS to override this.

]]>
https://forum.hollaex.com/t/is-there-a-way-to-make-the-footer-links-hidden/2082#post_3 Thu, 18 Dec 2025 22:41:01 +0000 forum.hollaex.com-post-3756
Is there a way to make the footer links hidden? The following code snippet should help resolve this. You can add the following script to your console in your body. Once added to your code, publish the changes.

<script>
function hideFooterRowBottom() {
  var footers = document.getElementsByClassName('footer-row-bottom');
  for (var i = 0; i < footers.length; i++) {
    footers[i].style.setProperty('display', 'none', 'important');
  }
}

// run once
hideFooterRowBottom();

// keep enforcing (in case of re-render)
setInterval(function () {
  hideFooterRowBottom();
}, 500);
</script>

]]>
https://forum.hollaex.com/t/is-there-a-way-to-make-the-footer-links-hidden/2082#post_2 Thu, 18 Dec 2025 04:24:54 +0000 forum.hollaex.com-post-3752
Is there a way to make the footer links hidden? Is there a way to make the footer links hidden?

]]>
https://forum.hollaex.com/t/is-there-a-way-to-make-the-footer-links-hidden/2082#post_1 Thu, 18 Dec 2025 04:17:53 +0000 forum.hollaex.com-post-3751
Level up/down based on trading volume +1
upgrading users based on activity/trade vol. would be useful as a plugin

]]>
https://forum.hollaex.com/t/level-up-down-based-on-trading-volume/2079#post_2 Wed, 17 Dec 2025 06:00:07 +0000 forum.hollaex.com-post-3748
Level up/down based on trading volume In this post there’s an example of automatically leveling up a user account after successful verification:

I’m wondering if there are other plugins or modules that can automatically upgrade or downgrade a user’s account based on their trading volume for example, how much a user has traded in a month, and then dynamically adjust their account level accordingly.

Specifically:

  • Are there existing plugins for automatically adjusting user tiers based on trading activity?
  • Can this be customized (e.g., monthly reset, tier thresholds, etc.)?
]]>
https://forum.hollaex.com/t/level-up-down-based-on-trading-volume/2079#post_1 Tue, 16 Dec 2025 20:40:00 +0000 forum.hollaex.com-post-3747
Automatic level up after successful KYC verification This is very interesting with the redis subscriber for the hook based. What are all the events other than this that you can subscribe too?

]]>
https://forum.hollaex.com/t/automatic-level-up-after-successful-kyc-verification/2033#post_3 Tue, 16 Dec 2025 20:36:29 +0000 forum.hollaex.com-post-3746
Automatic level up after successful KYC verification In HollaEx, user tiers are represented by verification_level, while KYC status is stored in id_data.status.

id_data.status values are typically:

  • 0: no status
  • 1: pending (KYC is being processed)
  • 2: rejected
  • 3: completed (approved)

There are two approaches to do this using Event-driven and Cron-based setup.

Event-driven (recommended on v2.17.1+)

Plugins can subscribe to the internal events channel:

toolsLib.database.subscriber.subscribe('channel:events');

toolsLib.database.subscriber.on('message', async (channel, message) => {
  try {
    if (channel === 'channel:events') {
      const { type, data } = JSON.parse(message);

      // For tier changes:
      if (type === 'user' && data.action === 'update') {
         loggerPlugin.info('/plugins/tier-upgrade-kyc/events update',
           data.user_id,
           data.email,
           data.id_data);
        // upgrade user's verification_level if all conditions are met

      }
    }
  } catch (err) {
    loggerPlugin.error('/plugins/tier-upgrade-kyc/events', err);
  }
});

From there, you can implement your logic to upgrade the user automatically (e.g., when you confirm id_data.status === 3, or when your KYC provider marks the user approved), using:

await toolsLib.user.changeUserVerificationLevelById(userId, 2);

Cron-based approach

You can periodically scan for users who:

  • are active (activated: true)
  • are not flagged (flagged: false)
  • are currently Tier 1 (verification_level: 1)
  • have approved KYC (id_data.status: 3)

Example query:

const users = await toolsLib.database.findAll('user', {
  where: {
    activated: true,
    flagged: false,
    verification_level: 1,
    id_data: {
      status: 3
    }
  },
  raw: true,
  attributes: [
    'id',
    'email',
    'network_id',
    'id_data',
    'verification_level',
    'email_verified',
    'activated',
    'flagged',
    'created_at'
  ]
});

Then loop through the matches and upgrade them:

await toolsLib.user.changeUserVerificationLevelById(user.id, 2);

Full example plugin (runs hourly for cron with hook-based setup)

'use strict';

const {
	toolsLib,
	loggerPlugin,
	cron
} = this;

const EVENTS_CHANNEL = 'channel:events';

// Event-based approach
toolsLib.database.subscriber.subscribe(EVENTS_CHANNEL);

toolsLib.database.subscriber.on('message', async (channel, message) => {
	try {
		if (channel !== EVENTS_CHANNEL) return;

		const { type, data } = JSON.parse(message);

		// For tier changes:
		if (type === 'user' && data && data.action === 'update') {
			loggerPlugin.info(
				'/plugins/tier-upgrade-kyc/events update',
				data.user_id,
				data.email,
				data.id_data,
				data.previous_user
			);

			// Extra guard: only upgrade if the user is still eligible (prevents loops / bad events)
			const user = await toolsLib.database.findOne('user', {
				where: { id: data.user_id },
				raw: true,
				attributes: ['id', 'email', 'id_data', 'verification_level', 'activated', 'flagged']
			});

			if (
				user &&
				user.activated === true &&
				user.flagged === false &&
				user.verification_level === 1 &&
				user.id_data &&
				user.id_data.status === 3
			) {
				loggerPlugin.verbose(
					'/plugins/tier-upgrade-kyc/events',
					`Upgrading user ${user.id} (${user.email}) -> level 2`
				);
				await toolsLib.user.changeUserVerificationLevelById(user.id, 2);
			}
		}
	} catch (err) {
		loggerPlugin.error('/plugins/tier-upgrade-kyc/events', err);
	}
});

// Cron-based approach
const run = async () => {
	loggerPlugin.verbose('/plugins/tier-upgrade-kyc/run', 'Running tier upgrade KYC plugin');

	const users = await toolsLib.database.findAll('user', {
		where: {
			activated: true,
			flagged: false,
			verification_level: 1,
			id_data: {
				status: 3
			}
		},
		raw: true,
		attributes: [
			'id',
			'email',
			'network_id',
			'id_data',
			'verification_level',
			'email_verified',
			'activated',
			'flagged',
			'created_at'
		]
	});

	loggerPlugin.verbose('/plugins/tier-upgrade-kyc/run', `Found ${users.length} users to upgrade`);

	if (!users.length) return;

	for (const user of users) {
		loggerPlugin.verbose('/plugins/tier-upgrade-kyc/run', `Upgrading user ${user.id} (${user.email}) -> level 2`);
		await toolsLib.user.changeUserVerificationLevelById(user.id, 2);
		loggerPlugin.verbose('/plugins/tier-upgrade-kyc/run', `User ${user.id} upgraded successfully`);
	}
};


run();

// Runs at minute 0 of every hour (UTC)
const task = cron.schedule(
	'0 * * * *',
	() => run(),
	{ timezone: 'Etc/UTC' }
);

task.start();
]]>
https://forum.hollaex.com/t/automatic-level-up-after-successful-kyc-verification/2033#post_2 Mon, 15 Dec 2025 23:05:01 +0000 forum.hollaex.com-post-3744
Store new fields for the users To store a persistent custom field like an internal_system_id on a user and use it inside plugins, you can use the user meta system in HollaEx.

Enable the Meta Field in the Exchange Config (UI)

First, you need to define the meta key so it’s supported in the operator panel:

  1. Go to Users in the admin UI.
  2. Select any user.
  3. Go to the Meta tab.
  4. Click “Configure Meta”.
  5. Add the meta key you want, e.g.: internal_system_id

Once this is configured, you can manually set internal_system_id for users from the admin UI if needed.

If you want to do this programmatically from outside (e.g., from a backend service), you can use the Admin APIs, for example via hollaex-node-lib with admin keys and updateExchangeUser.

Example:

// Pseudo code using hollaex-node-lib

await updateExchangeUser(userId, {
  meta: {
    internal_system_id: 'ABC123XYZ'
  }
});

This will persist the value in the user’s meta and can be used for other operations later.

If you are doing this inside a plugin, you can update the user meta directly using toolsLib.user.updateUserMeta.

Example:

async function updateMeta() {
  const userId = 123; // HollaEx user ID

  const metaUpdate = {
    internal_system_id: 'ABC123XYZ'
  };

  const auditInfo = {
    userEmail: '[email protected]',
    sessionId: 'sess-123',
    apiPath: '/admin/user/meta',
    method: 'put'
  };

  const user = await toolsLib.user.updateUserMeta(
    userId,
    metaUpdate,
    { overwrite: false }, // set true if you want to overwrite existing meta fields
    auditInfo
  );

  console.log(user.meta); // will include internal_system_id
}
  • overwrite: false will merge the provided meta fields with existing ones, instead of wiping them.
  • auditInfo is used for logging/auditing so the system knows who performed the change and via which path.
]]>
https://forum.hollaex.com/t/store-new-fields-for-the-users/2075#post_2 Mon, 08 Dec 2025 20:43:01 +0000 forum.hollaex.com-post-3741
Store new fields for the users I’m exploring how to extend the user model via plugins, and I’m specifically trying to figure out how to store persistent custom data on a user’s account.

I want to add a new field to each user — for example, something like:
internal_system_id: “ABC123XYZ”

This value needs to be:

  • Persisted in the database
  • Accessible later in other plugin actions
  • Usable for internal queries or third-party integrations
  • Attached to a user in a stable, non-volatile way

From my understanding, there is a meta field in the system but I am not sure how I can customize that.

]]>
https://forum.hollaex.com/t/store-new-fields-for-the-users/2075#post_1 Mon, 08 Dec 2025 20:00:48 +0000 forum.hollaex.com-post-3740
Manually Review Large Deposit Transactions very useful plugin, thanks

]]>
https://forum.hollaex.com/t/manually-review-large-deposit-transactions/2073#post_3 Mon, 01 Dec 2025 07:55:17 +0000 forum.hollaex.com-post-3738
Manually Review Large Deposit Transactions First, you’ll need to disable the automatic deposit processing feature in your Operator Control Panel (introduced in v2.17). You can find this setting under:

General → Security

Once auto-deposit is turned off, all incoming crypto deposits will remain in an “on hold” state, meaning they will require manual approval unless you automate the process yourself.

From there, you can create a simple plugin, similar to the example below that retrieves all deposits where onhold: true, checks their value, and processes them accordingly.
For example:

  • If the deposit amount is under $1,000, the plugin can automatically approve and process it.
  • If the amount is over $1,000, the deposit will remain on hold, allowing you to manually review and verify it through the Operator Control Panel.

This setup gives you full control while still allowing smaller deposits to be handled automatically.

'use strict';

const { publicMeta, meta } = this.configValues;
const {
	app,
	loggerPlugin,
	toolsLib
} = this.pluginLibraries;

const init = async () => {
	loggerPlugin.info(
		'/plugins/txanalysor/init/initializing'
	);
};

const parseNumber = (v, fallback = 0) => {
	const n = Number(v);
	return Number.isFinite(n) ? n : fallback;
};

const valueInQuote = async (currency, amount, quote) => {
	const sym = String(currency || '').toLowerCase();
	const tgt = String(quote || '').toLowerCase();
	if (!sym || !amount || !tgt) return null;
	try {
		if (sym === tgt) return parseNumber(amount, null);
		const prices = await toolsLib.getAssetsPrices([sym], tgt);
		const rate = prices && prices[sym];
		if (typeof rate !== 'number' || !(rate > 0)) return null;
		return parseNumber(amount, null) * rate;
	} catch (err) {
		loggerPlugin.warn('/plugins/txanalysor/valueInQuote price fetch failed', sym, '->', tgt, err.message);
		return null;
	}
};

const processOnHoldDeposits = async () => {
	const threshold = parseNumber(meta.THRESHOLD_USDT.value, 1000);
	const quote = (meta.QUOTE_CURRENCY.value || 'usdt').toLowerCase();

	let scanned = 0;
	let validated = 0;
	let skipped = 0;
	const res = await toolsLib.wallet.getExchangeDeposits(
		null,   // currency
		false,  // status (pending)
		false,  // dismissed
		false,  // rejected
		false,  // processing
		false,  // waiting
		null,   // limit
		null,      // page
		null,   // orderBy
		null,   // order
		null,   // startDate
		null,   // endDate
		null,   // transactionId
		null,   // address
		null,   // format
		{ onhold: true } // opts
	);
	const list = res && Array.isArray(res.data) ? res.data : [];
	if (!list.length) {
		loggerPlugin.info('/plugins/txanalysor/process complete', { scanned, validated, skipped });
		return { scanned, validated, skipped };
	}

	for (const d of list) {
		// Defensive parsing
		if (!d || !d.transaction_id) continue;

		// Only pending + onhold deposits
		const isOnHold = !!d.onhold;
		if (!isOnHold) {
			skipped += 1;
			continue;
		}

		const currency = String((d.currency || d.symbol) || '').toLowerCase();
		const amount = parseNumber(d.amount, null);
		if (!currency || !(amount > 0)) {
			skipped += 1;
			continue;
		}

		const valueQuote = await valueInQuote(currency, amount, quote);
		if (valueQuote === null) {
			skipped += 1;
			continue;
		}

		if (valueQuote < threshold) {
			try {
				await toolsLib.wallet.updatePendingMint(d.transaction_id, {
					status: true,
					onhold: false
				});
				loggerPlugin.info('/plugins/txanalysor/validated', {
					transaction_id: d.transaction_id,
					currency,
					amount,
					value_in_quote: valueQuote,
					quote,
					threshold
				});
				validated += 1;
			} catch (err) {
				loggerPlugin.error('/plugins/txanalysor/updatePendingMint failed', d.transaction_id, err.message);
				skipped += 1;
			}
		} else {
			skipped += 1;
		}
		scanned += 1;
	}

	loggerPlugin.info('/plugins/txanalysor/process complete', { scanned, validated, skipped });
	return { scanned, validated, skipped };
};

init()
	.then(() => {
		setTimeout(() => {
			processOnHoldDeposits().catch((err) => {
				loggerPlugin.error('/plugins/txanalysor/initial run error', err.message);
			});
		}, 10000);
			// Run every minute
			setInterval(() => {
				processOnHoldDeposits().catch((err) => {
					loggerPlugin.error('/plugins/txanalysor/scheduled run error', err.message);
				});
			}, 60 * 1000);
	})
	.catch((err) => {
		loggerPlugin.error(
			'/plugins/txanalysor/init/error during initialization',
			err.message
		);
	});


]]>
https://forum.hollaex.com/t/manually-review-large-deposit-transactions/2073#post_2 Thu, 27 Nov 2025 19:44:09 +0000 forum.hollaex.com-post-3737
Manually Review Large Deposit Transactions I’m looking for a way to review and validate crypto deposits on my exchange before they are fully processed.

Ideally, I’d like all deposits under $1,000 to be handled automatically, but for any deposit above that threshold, I want to introduce a manual review step so I can verify and approve the transaction myself.

Is there a recommended method or feature in HollaEx that allows setting up this kind of conditional deposit flow? Any guidance or best practices would be greatly appreciated.

Thanks!

]]>
https://forum.hollaex.com/t/manually-review-large-deposit-transactions/2073#post_1 Wed, 26 Nov 2025 20:46:54 +0000 forum.hollaex.com-post-3736
Future trading availability Anybody aware if Future trading options will be added in additional to the spot trade?

]]>
https://forum.hollaex.com/t/future-trading-availability/2069#post_1 Mon, 17 Nov 2025 19:57:12 +0000 forum.hollaex.com-post-3732
Flutter App Development Company Qbecus is a highly recommended and trusted software development company, recognized for delivering quality digital solutions. We specialize in custom mobile app development for iOS and Android, along with professional website development, ERP systems, CRM solutions, and modern UI/UX design. Our goal is to help businesses grow with technology that is smart, scalable, and easy to use. Whether you’re building something new or improving what you already have, Qbecus is here to support your vision every step of the way.

]]>
https://forum.hollaex.com/t/flutter-app-development-company/880#post_19 Sat, 25 Oct 2025 11:22:22 +0000 forum.hollaex.com-post-3703
Automatic level up after successful KYC verification I’m looking to develop a plugin that automatically updates a user’s tier once their KYC verification is successfully completed and their documents are approved. At the moment, we handle this process manually, but I’d like to streamline it.

Does the plugin system provide a way to trigger these tier updates automatically when KYC verification is confirmed? Any guidance or examples on how to implement this would be greatly appreciated.

Thanks in advance!

]]>
https://forum.hollaex.com/t/automatic-level-up-after-successful-kyc-verification/2033#post_1 Thu, 18 Sep 2025 20:21:00 +0000 forum.hollaex.com-post-3669
Recurring 404s to /api/v2/announcements (Testnet) Hi @nickyvel @mbpetr_75112.

Thanks for reporting the issue.

I just set up a new testnet exchange from scratch on my computer, but I was not able to reproduce the issue.

Could you please provide some more information?

  • Which version of the HollaEx Kit did you use?
  • Any customizations you made?
  • Any errors occurred during the setup?
  • Any server logs (especially error logs)?

Thank you.

]]>
https://forum.hollaex.com/t/recurring-404s-to-api-v2-announcements-testnet/1996#post_4 Thu, 04 Sep 2025 08:20:04 +0000 forum.hollaex.com-post-3656
HollaEx Server Setup fails Hi there. Could you please try it from scratch on a clean machine?

I went through the testnet setup flow on my own computer (macOS) and found no issues.

Additionally, could you please tell me which OS you are using too?

Thank you.

]]>
https://forum.hollaex.com/t/hollaex-server-setup-fails/1994#post_2 Thu, 04 Sep 2025 08:13:04 +0000 forum.hollaex.com-post-3655
Recurring 404s to /api/v2/announcements (Testnet) Starting the server and the web manually with docker-up, instead of using hollaex-cli worked for me. Follow the instructions on this page:

docs.hollaex.com/developers/run-dev-mode

]]>
https://forum.hollaex.com/t/recurring-404s-to-api-v2-announcements-testnet/1996#post_3 Thu, 21 Aug 2025 09:55:19 +0000 forum.hollaex.com-post-3652
Recurring 404s to /api/v2/announcements (Testnet) I have the same error when I try to run hollaex web

]]>
https://forum.hollaex.com/t/recurring-404s-to-api-v2-announcements-testnet/1996#post_2 Thu, 07 Aug 2025 06:25:13 +0000 forum.hollaex.com-post-3630
Recurring 404s to /api/v2/announcements (Testnet) I’m running the HollaEx server against the Testnet environment. Upon startup, I only see a blank page, and after about 15–20 seconds the server responds with a 503 Service Unavailable error. In the logs I also see repeated 404 Not Found requests to the /api/v2/announcements endpoint. As a result, the server never becomes fully operational on testnet.

Has anyone encountered this before or found a solution?

Screenshot from 2025-08-06 15-11-23


]]>
https://forum.hollaex.com/t/recurring-404s-to-api-v2-announcements-testnet/1996#post_1 Wed, 06 Aug 2025 12:11:52 +0000 forum.hollaex.com-post-3628
HollaEx Server Setup fails Hello, I am trying to install HollaEx exchange ( test environment) by following instructions from the documentation.

I got to the point of creating an admin account and got an error:

Welcome to HollaEx Server Setup!
Checking docker-compose availability...
Docker Compose version v2.29.1

Select the network

Before you continue, You need to select the network that you want to use with the exchange.
HollaEx Kit by default, will be connected to the official mainnet HollaEx Network (api.hollaex.network).
You can also run HollaEx Kit with official testnet HollaEx Network for testing purpose (api.testnet.hollaex.network).
If you want to connect to a different custom network, you can type the URL.


1) Mainnet HollaEx Network
2) Testnet HollaEx Network
3) Custom HollaEx Network

Please select the network: 2

{"name":"HollaEx Testnet","version":"2.15.0","host":"api.testnet.hollaex.network","basePath":"/v2"}
Successfully reached to the network health page.

https://api.testnet.hollaex.network ✔


Create Admin

Please type your email address and password that you are going to use for your admin account.

Email:
[email protected]

Password:
-Password must contain at least 8 characters and one digit.


Create Exchange

Please type in the name of your new exchange.
- Alphanumeric, Dash (-), Underscore Only (_). No space or special character allowed.
ADEX

ADEX ✔

Error 1001 - relation "deposits" does not exist

Error: Failed to create an account on HollaEx Network.
Please review the logs and try it again.

I tried to run the setup again but got different error:

ubuntu@ip-172-31-7-77:~/hollaex-kit$ sudo hollaex server --setup
Checking docker-compose availability...
Docker Compose version v2.29.1
Checking docker-compose availability...
Docker Compose version v2.29.1
/usr/local/bin/hollaex: line 1115: /root/.hollaex-cli/tools_generator.sh: No such file or directory
/usr/local/bin/hollaex: line 1121: hollaex_setup_existing_exchange_check: command not found
/usr/local/bin/hollaex: line 1125: hollaex_setup_initialization: command not found
/usr/local/bin/hollaex: line 1164: system_dependencies_check: command not found
/usr/local/bin/hollaex: line 1166: check_docker_daemon_status: command not found
Checking docker-compose availability...
Docker Compose version v2.29.1
Target hollaex docker registry : bitholla/my-hollaex-server.
/usr/local/bin/hollaex: line 4222: /root/.hollaex-cli/tools_generator.sh: No such file or directory
/usr/local/bin/hollaex: line 4223: load_config_variables: command not found
/usr/local/bin/hollaex: line 4236: build_user_hollaex_core: command not found
Error: The image (bitholla/my-hollaex-server:2.15.10) is currently not available.
This could be an temporary issue, especially when there is a recent Kit release came up just a while ago.
Please try it again after a while, or run 'hollaex server --setup --local_build' to force build local image.

Please help

]]>
https://forum.hollaex.com/t/hollaex-server-setup-fails/1994#post_1 Tue, 05 Aug 2025 14:30:52 +0000 forum.hollaex.com-post-3626
Where can I download exchange software exactly? I tried to install Hollaes kit to locall but was not sucessfull, after download files I run instal command but yml and env file was not created

]]>
https://forum.hollaex.com/t/where-can-i-download-exchange-software-exactly/64#post_3 Sun, 03 Aug 2025 19:10:36 +0000 forum.hollaex.com-post-3624
Flutter App Development Company I’d like to highlight that HollaEx provides a ready-made solution for launching both mobile and desktop applications built with Flutter, included at no additional cost as part of the Enterprise Plan.

While it’s technically possible to build your own app from scratch, we generally advise against it. Doing so can require substantial development time and resources. Instead, we strongly recommend leveraging the existing, production-ready solution offered within the Enterprise Plan. It’s optimized for speed, reliability, and ease of deployment, allowing you to focus on customization and growth rather than foundational engineering.

]]>
https://forum.hollaex.com/t/flutter-app-development-company/880#post_18 Mon, 07 Jul 2025 19:25:55 +0000 forum.hollaex.com-post-3613
Batch fiat mint/burn through CSV file Your code snippet doesn’t appear to be related to HollaEx in any meaningful way. It looks quite generic and seems more like a promotional effort to showcase your development work rather than contribute to the topic at hand.

Please note that this is a public technical forum and not a marketing platform. If your goal is to advertise your services or portfolio, we recommend reaching out to HollaEx directly and making open-source contributions that demonstrate your skills. That way, you may have the opportunity to be acknowledged or vouched for by the team if your work aligns with the project’s standards.

Let’s keep this space focused on relevant and constructive discussions.

]]>
https://forum.hollaex.com/t/batch-fiat-mint-burn-through-csv-file/1981#post_5 Mon, 07 Jul 2025 19:23:00 +0000 forum.hollaex.com-post-3612
Batch fiat mint/burn through CSV file Core Architecture Overview:

  1. Frontend Interface: Admin uploads a CSV file (React + role-based access).

  2. Backend:

  • Parses the CSV
  • Validates schema (amounts, reference ID, PSP codes, timestamps)
  1. Business Logic Layer:
  • Maps fiat transactions => user’s wallet address via internal UID
  • Calls the mint/burn smart contract function via a secure internal service (Web3.py)
  • Logs success/failure entries with hashed transaction data
  1. Queue System: We used Celery + Redis

  2. Audit Trail: All processed rows were stored in a MongoDB audit log

Can’t share the exact code due to NDA

Sample code:

@app.post("/upload")
async def upload_csv(file: UploadFile = File(...), user: User = Depends(get_current_user)):
    df = pd.read_csv(file.file)
    for index, row in df.iterrows():
        if not validate_row(row):
            log_error(row, reason="Invalid data format")
            continue
        enqueue_transaction(row)  # sends to Celery worker
    return {"status": "Processing initiated"}
]]>
https://forum.hollaex.com/t/batch-fiat-mint-burn-through-csv-file/1981#post_4 Mon, 07 Jul 2025 08:23:18 +0000 forum.hollaex.com-post-3611
Batch fiat mint/burn through CSV file How did you develop that? Can you share your code script or a sample to see?

]]>
https://forum.hollaex.com/t/batch-fiat-mint-burn-through-csv-file/1981#post_3 Mon, 07 Jul 2025 06:36:33 +0000 forum.hollaex.com-post-3609
Batch fiat mint/burn through CSV file We implemented a similar system for a European crypto exchange at Impero IT Services, where they were manually reconciling 1,000+ fiat deposit & withdrawal requests per day from multiple PSPs.

key considerations

  1. CSV Input Design
  2. Validation Layer
  3. Integration with HollaEx API
  4. Secure Execution
  5. Notifications & Reporting
]]>
https://forum.hollaex.com/t/batch-fiat-mint-burn-through-csv-file/1981#post_2 Mon, 07 Jul 2025 06:06:23 +0000 forum.hollaex.com-post-3608
Batch fiat mint/burn through CSV file I’m planning to implement a function that automates the minting and burning of fiat currencies on my exchange by processing transactions from a CSV file.

This is necessary because I currently have a large volume of fiat transactions that need to be handled manually, and automating this process would significantly streamline operations and reduce the risk of human error.

]]>
https://forum.hollaex.com/t/batch-fiat-mint-burn-through-csv-file/1981#post_1 Sun, 06 Jul 2025 23:45:48 +0000 forum.hollaex.com-post-3607
Flutter App Development Company You should think beyond the usual checklists of expertise & cost, there are some less-talked-about but critical aspects that often get missed in discussions.

  1. Cross-Platform Optimization

Now a days many companies say they do Flutter, but few optimize for both platforms equally, not just about compiling for Android and iOS but fine-tuning performance (animation smoothness, native APIs, device-specific bugs) for both OS.

We built a wellness app for both iOS and Android. The challenge? Complex BLE (Bluetooth) integrations with wearables. Our team used Flutter with native bridges (via platform channels) to make sure real-time health tracking worked flawlessly on both platforms.

  1. DevOps & CI/CD Integration

you should ask how they handle OTA (Over-The-Air) updates using services like CodePush (via third-party plugins), when your app needs rapid iteration.

  1. Communication
  • Weekly Reviews
  • Provides Figma => Flutter mapping
  • Transparent about backend
  1. Maintenance Commitment

A lot of firms disappear post-launch. Look for those who offer maintenance SLAs, when OS upgrades & Flutter version shifts.

At Impero IT Services, we recently managed a project that had an outdated Flutter 2.x codebase. We updated it to Flutter 3.22 with Dart 3, optimized the widget tree for better performance & integrated Firebase’s latest SDKs for analytics and crash reporting ==> all without downtime for the app

]]>
https://forum.hollaex.com/t/flutter-app-development-company/880#post_17 Thu, 29 May 2025 09:59:16 +0000 forum.hollaex.com-post-3597
Fiat controls is not accessible for users with Supervisor role This use case is totally covered with the new role system in 2.15 Singha release.

]]>
https://forum.hollaex.com/t/fiat-controls-is-not-accessible-for-users-with-supervisor-role/1831#post_5 Thu, 08 May 2025 00:32:51 +0000 forum.hollaex.com-post-3586
Fiat controls is not accessible for users with Supervisor role there is a new Roles based update that might be able to help with this.

]]>
https://forum.hollaex.com/t/fiat-controls-is-not-accessible-for-users-with-supervisor-role/1831#post_4 Thu, 08 May 2025 00:19:44 +0000 forum.hollaex.com-post-3585
Customize email templates In Operator Controls you can navigate to GeneralEmail, and under the Customize Email section, select the email template you wish to modify. From there, you can insert your custom email template.

Note:
Dynamic values can be added to your template using the ${value} format. For example, in the case of a login email, using ${name} will display the user’s email address.

Here’s an example of an email I created using a tool called Stripo.

<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
<html dir='ltr' xmlns='http://www.w3.org/1999/xhtml' xmlns:o='urn:schemas-microsoft-com:office:office' lang='en'>
 <head>
  <meta charset='UTF-8'>
  <meta content='width=device-width, initial-scale=1' name='viewport'>
  <meta name='x-apple-disable-message-reformatting'>
  <meta http-equiv='X-UA-Compatible' content='IE=edge'>
  <meta content='telephone=no' name='format-detection'>
  <title>Important: Recent Login Alert for Your Account</title>
  <style type='text/css'>.rollover:hover .rollover-first {
  max-height:0px!important;
  display:none!important;
}
.rollover:hover .rollover-second {
  max-height:none!important;
  display:block!important;
}
.rollover span {
  font-size:0px;
}
u + .body img ~ div div {
  display:none;
}
#outlook a {
  padding:0;
}
span.MsoHyperlink,
span.MsoHyperlinkFollowed {
  color:inherit;
  mso-style-priority:99;
}
a.q {
  mso-style-priority:100!important;
  text-decoration:none!important;
}
a[x-apple-data-detectors],
#MessageViewBody a {
  color:inherit!important;
  text-decoration:none!important;
  font-size:inherit!important;
  font-family:inherit!important;
  font-weight:inherit!important;
  line-height:inherit!important;
}
.g {
  display:none;
  float:left;
  overflow:hidden;
  width:0;
  max-height:0;
  line-height:0;
  mso-hide:all;
}
@media only screen and (max-width:600px) {.bf { padding-bottom:20px!important }  *[class='gmail-fix'] { display:none!important } p, a { line-height:150%!important } h1, h1 a { line-height:120%!important } h2, h2 a { line-height:120%!important } h3, h3 a { line-height:120%!important } h4, h4 a { line-height:120%!important } h5, h5 a { line-height:120%!important } h6, h6 a { line-height:120%!important }  .bc p { } .bb p { }  h1 { font-size:40px!important; text-align:left; margin-bottom:0px!important } h2 { font-size:28px!important; text-align:left; margin-bottom:0px!important } h3 { font-size:20px!important; text-align:left; margin-bottom:0px!important } h4 { font-size:24px!important; text-align:left } h5 { font-size:20px!important; text-align:left } h6 { font-size:16px!important; text-align:left }        .bd p, .bd a { font-size:14px!important } .bc p, .bc a { font-size:14px!important } .bb p, .bb a { font-size:14px!important }       .w .rollover:hover .rollover-second, .x .rollover:hover .rollover-second, .y .rollover:hover .rollover-second { display:inline!important }  .v { display:inline-table }    .p, .p .q, .r, .r td, .e { display:inline-block!important } .m table, .n, .o { width:100%!important } .j table, .k table, .l table, .j, .l, .k { width:100%!important; max-width:600px!important } .adapt-img { width:100%!important; height:auto!important }       table.d, .esd-block-html table { width:auto!important } .h-auto { height:auto!important } .img-6307 { height:36px!important } .a .c, .a .c * { font-size:14px!important; line-height:150%!important } .a .b, .a .b * { font-size:12px!important; line-height:150%!important } }
@media screen and (max-width:384px) {.mail-message-content { width:414px!important } }</style>
 </head>
 <body class='body' style='width:100%;height:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;padding:0;Margin:0'>
  <span style='display:none !important;font-size:0px;line-height:0;color:#ffffff;visibility:hidden;opacity:0;height:0;width:0;mso-hide:all'>Review the details of a recent login to ensure your account's security.</span>
  <div dir='ltr' class='es-wrapper-color' lang='en' style='background-color:#E6F9FE'><!--[if gte mso 9]>
    <v:background xmlns:v='urn:schemas-microsoft-com:vml' fill='t'>
        <v:fill type='tile' color='#f6f6f6'></v:fill>
    </v:background>
    <![endif]-->
   <table width='100%' cellspacing='0' cellpadding='0' class='es-wrapper' role='none' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px;padding:0;Margin:0;width:100%;height:100%;background-repeat:repeat;background-position:center top;background-color:#E6F9FE'>
     <tr>
      <td valign='top' style='padding:0;Margin:0'>
       <table cellspacing='0' cellpadding='0' align='center' background class='k' role='none' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px;width:100%;table-layout:fixed !important;background-color:transparent;background-repeat:repeat;background-position:center top'>
       </table>
       <table cellpadding='0' cellspacing='0' align='center' class='k' role='none' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px;width:100%;table-layout:fixed !important;background-color:transparent;background-repeat:repeat;background-position:center top'>
         <tr>
          <td align='center' bgcolor='transparent' style='padding:0;Margin:0'>
           <table align='center' cellpadding='0' cellspacing='0' bgcolor='#ffffff' class='bd' role='none' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px;background-color:transparent;width:600px'>
             <tr>
              <td align='left' bgcolor='#fbfafa' style='padding:0;Margin:0;padding-bottom:15px;background-color:#fbfafa'>
               <table cellspacing='0' width='100%' cellpadding='0' role='none' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px'>
                 <tr>
                  <td align='left' style='padding:0;Margin:0;width:600px'>
                   <table cellpadding='0' cellspacing='0' width='100%' role='presentation' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px'>
                     <tr>
                      <td align='center' bgcolor='#0b5394' style='padding:0;Margin:0;font-size:0'>
                       <table border='0' width='100%' height='100%' cellpadding='0' cellspacing='0' class='v' role='presentation' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px'>
                         <tr>
                          <td style='padding:0;Margin:0;border-bottom:3px solid #0b5394;background:none;height:0px;width:100%;margin:0px'></td>
                         </tr>
                       </table></td>
                     </tr>
                     <tr>
                      <td align='center' style='padding:0;Margin:0;padding-top:30px;padding-bottom:20px;font-size:0px'><a target='_blank' href='https://viewstripo.email' class='companyWebsite' style='mso-line-height-rule:exactly;text-decoration:underline;color:#0D4259;font-size:14px'><img alt='' height='33' src='https://yscnzh.stripocdn.email/content/guids/CABINET_8263422e3fe53147a17e98df62c92ed0c8dacb60d4e047ec18914664ea1108cc/images/hollaexblack.png' class='companyLogo img-6307' style='display:block;font-size:14px;border:0;outline:none;text-decoration:none;border-radius:0' width='107'></a></td>
                     </tr>
                   </table></td>
                 </tr>
               </table></td>
             </tr>
           </table></td>
         </tr>
       </table>
       <table cellspacing='0' cellpadding='0' align='center' class='j' role='none' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px;width:100%;table-layout:fixed !important'>
       </table>
       <table cellpadding='0' cellspacing='0' align='center' class='j' role='none' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px;width:100%;table-layout:fixed !important'>
         <tr>
          <td align='center' style='padding:0;Margin:0'>
           <table bgcolor='#ffffff' align='center' cellpadding='0' cellspacing='0' class='bc' role='none' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px;background-color:#FFFFFF;width:600px'>
             <tr>
              <td align='left' style='Margin:0;padding-top:10px;padding-right:30px;padding-bottom:10px;padding-left:30px'>
               <table cellpadding='0' cellspacing='0' width='100%' role='none' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px'>
                 <tr>
                  <td align='center' valign='top' style='padding:0;Margin:0;width:540px'>
                   <table cellpadding='0' cellspacing='0' width='100%' role='presentation' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px'>
                     <tr>
                      <td align='left' class='generalTextHtml' style='padding:0;Margin:0'><p style='Margin:0;mso-line-height-rule:exactly;font-family:Lexend, Arial, sans-serif;line-height:16.8px;letter-spacing:0;color:#0D4259;font-size:14px;margin-bottom:10px'><br></p><p style='Margin:0;mso-line-height-rule:exactly;font-family:Lexend, Arial, sans-serif;line-height:16.8px;letter-spacing:0;color:#0D4259;font-size:14px;margin-bottom:10px'>Dear ${name},</p><p style='Margin:0;mso-line-height-rule:exactly;font-family:Lexend, Arial, sans-serif;line-height:16.8px;letter-spacing:0;color:#0D4259;font-size:14px;margin-bottom:10px'><br></p><p style='Margin:0;mso-line-height-rule:exactly;font-family:Lexend, Arial, sans-serif;line-height:16.8px;letter-spacing:0;color:#0D4259;font-size:14px;margin-bottom:10px'>We would like to inform you of a recent login to your account. Please review the details below to ensure this activity was authorized:</p>
                       <ul style='font-family:Lexend, Arial, sans-serif;padding:0px 0px 0px 40px;margin-top:15px;margin-bottom:15px'>
                        <li style='color:#0D4259;margin:0px 0px 15px;font-size:14px'><strong style='line-height:120%'>Time:</strong><span style='line-height:120%'> ${time}</span></li>
                        <li style='color:#0D4259;margin:0px 0px 15px;font-size:14px'><strong style='line-height:120%'>IP Address:</strong><span style='line-height:120%'> ${ip}</span></li>
                        <li style='color:#0D4259;margin:0px 0px 15px;font-size:14px'><strong style='line-height:120%'>Location:</strong><span style='line-height:120%'> ${country}</span></li>
                       </ul><p style='Margin:0;mso-line-height-rule:exactly;font-family:Lexend, Arial, sans-serif;line-height:16.8px;letter-spacing:0;color:#0D4259;font-size:14px;margin-bottom:10px'><br></p><p style='Margin:0;mso-line-height-rule:exactly;font-family:Lexend, Arial, sans-serif;line-height:16.8px;letter-spacing:0;color:#0D4259;font-size:14px;margin-bottom:10px'>If you did not initiate this login, we strongly recommend changing your password immediately and enabling two-factor authentication for enhanced security. Should you have any concerns, please contact our support team without delay.</p><p style='Margin:0;mso-line-height-rule:exactly;font-family:Lexend, Arial, sans-serif;line-height:16.8px;letter-spacing:0;color:#0D4259;font-size:14px;margin-bottom:10px'><br></p><p style='Margin:0;mso-line-height-rule:exactly;font-family:Lexend, Arial, sans-serif;line-height:16.8px;letter-spacing:0;color:#0D4259;font-size:14px;margin-bottom:10px'><em>-- Thank you for your attention to this matter.</em></p><p style='Margin:0;mso-line-height-rule:exactly;font-family:Lexend, Arial, sans-serif;line-height:16.8px;letter-spacing:0;color:#0D4259;font-size:14px;margin-bottom:10px'><br></p></td>
                     </tr>
                   </table></td>
                 </tr>
               </table></td>
             </tr>
           </table></td>
         </tr>
       </table>
       <table cellpadding='0' cellspacing='0' align='center' class='j' role='none' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px;width:100%;table-layout:fixed !important'>
         <tr>
          <td align='center' style='padding:0;Margin:0'>
           <table cellspacing='0' cellpadding='0' align='center' class='bb' role='none' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px;background-color:#BCF0FF;width:600px'>
             <tr>
              <td align='left' bgcolor='#efefef' style='Margin:0;padding-bottom:20px;padding-right:30px;padding-left:30px;padding-top:20px;background-color:#efefef'><!--[if mso]><table style='width:540px' cellpadding='0' cellspacing='0'><tr><td style='width:346px' valign='top'><![endif]-->
               <table cellspacing='0' cellpadding='0' align='left' class='n' role='none' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px;float:left'>
                 <tr>
                  <td align='left' class='bf' style='padding:0;Margin:0;width:346px'>
                   <table width='100%' cellspacing='0' cellpadding='0' role='presentation' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px'>
                     <tr>
                      <td esdev-links-color='#666666' align='left' class='a' style='padding:0;Margin:0'><p class='c' style='Margin:0;mso-line-height-rule:exactly;font-family:Lexend, Arial, sans-serif;line-height:15.4px;letter-spacing:0;color:#0D4259;font-size:14px;margin-bottom:0px'><strong style='color:#0a3142'>HollaEx® </strong><em>— White-label Crypto Software Solutions&nbsp;</em></p><p class='b' style='Margin:0;mso-line-height-rule:exactly;font-family:Lexend, Arial, sans-serif;line-height:13.2px;letter-spacing:0;color:#1b5670;font-size:12px;margin-bottom:0px'><strong><br></strong></p><p class='b' style='Margin:0;mso-line-height-rule:exactly;font-family:Lexend, Arial, sans-serif;line-height:13.2px;letter-spacing:0;color:#1b5670;font-size:12px;margin-bottom:0px'><strong>Exchange:</strong> <a href='https://pro.hollaex.com' target='_blank' class='unsubscribe' style='mso-line-height-rule:exactly;text-decoration:underline;color:#1b5670;font-size:12px;line-height:13.2px'>https://pro.hollaex.com</a></p><p class='b' style='Margin:0;mso-line-height-rule:exactly;font-family:Lexend, Arial, sans-serif;line-height:13.2px;letter-spacing:0;color:#1b5670;font-size:12px;margin-bottom:0px'><strong>Business:</strong> <a href='https://www.hollaex.com' target='_blank' style='mso-line-height-rule:exactly;text-decoration:underline;color:#1b5670;font-size:12px;line-height:13.2px'>https://www.hollaex.com</a></p></td>
                     </tr>
                   </table></td>
                 </tr>
               </table><!--[if mso]></td><td style='width:20px'></td><td style='width:174px' valign='top'><![endif]-->
               <table cellspacing='0' cellpadding='0' align='right' class='o' role='none' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px;float:right'>
                 <tr>
                  <td align='left' style='padding:0;Margin:0;width:174px'>
                   <table width='100%' cellspacing='0' cellpadding='0' role='presentation' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px'>
                     <tr>
                      <td esdev-links-color='#666666' align='left' style='padding:0;Margin:0'><p style='Margin:0;mso-line-height-rule:exactly;font-family:Lexend, Arial, sans-serif;line-height:28px;letter-spacing:0;color:#0D4259;font-size:14px;margin-bottom:0px'><a target='_blank' href='https://www.hollaex.com/resources' style='mso-line-height-rule:exactly;text-decoration:underline;color:#0D4259;font-size:14px'>Questions?</a></p><p style='Margin:0;mso-line-height-rule:exactly;font-family:Lexend, Arial, sans-serif;line-height:28px;letter-spacing:0;color:#0D4259;font-size:14px;margin-bottom:0px'><a target='_blank' href='https://www.hollaex.com/contact#:~:text=contacting%20us%20at%20support%40hollaex.com%E2%80%8D' class='email_us_text' style='mso-line-height-rule:exactly;text-decoration:underline;color:#0D4259;font-size:14px'>Contact Us</a></p><p style='Margin:0;mso-line-height-rule:exactly;font-family:Lexend, Arial, sans-serif;line-height:28px;letter-spacing:0;color:#0D4259;font-size:14px;margin-bottom:0px'><a target='_blank' href='https://www.hollaex.com/about' style='mso-line-height-rule:exactly;text-decoration:underline;color:#0D4259;font-size:14px;line-height:28px'>About Us</a></p></td>
                     </tr>
                     <tr>
                      <td align='left' style='padding:0;Margin:0;padding-top:5px;font-size:0'>
                       <table cellspacing='0' cellpadding='0' class='d r' role='presentation' style='mso-table-lspace:0pt;mso-table-rspace:0pt;border-collapse:collapse;border-spacing:0px'>
                         <tr>
                          <td valign='top' align='center' style='padding:0;Margin:0;padding-right:10px'><a href='https://x.com/hollaex' style='mso-line-height-rule:exactly;text-decoration:underline;color:#0D4259;font-size:14px'><img title='X' src='https://yscnzh.stripocdn.email/content/assets/img/social-icons/rounded-gray/x-rounded-gray.png' alt='X' width='24' height='24' style='display:block;font-size:14px;border:0;outline:none;text-decoration:none'></a></td>
                          <td valign='top' align='center' style='padding:0;Margin:0;padding-right:10px'><a href='https://www.youtube.com/@HollaEx' style='mso-line-height-rule:exactly;text-decoration:underline;color:#0D4259;font-size:14px'><img title='Youtube' src='https://yscnzh.stripocdn.email/content/assets/img/social-icons/rounded-gray/youtube-rounded-gray.png' alt='Yt' width='24' height='24' style='display:block;font-size:14px;border:0;outline:none;text-decoration:none'></a></td>
                          <td valign='top' align='center' style='padding:0;Margin:0;padding-right:10px'><a href='https://t.me/s/hollaex' style='mso-line-height-rule:exactly;text-decoration:underline;color:#0D4259;font-size:14px'><img title='Telegram' src='https://yscnzh.stripocdn.email/content/assets/img/messenger-icons/rounded-gray/telegram-rounded-gray.png' alt='Telegram' width='24' height='24' style='display:block;font-size:14px;border:0;outline:none;text-decoration:none'></a></td>
                         </tr>
                       </table></td>
                     </tr>
                   </table></td>
                 </tr>
               </table><!--[if mso]></td></tr></table><![endif]--></td>
             </tr>
           </table></td>
         </tr>
       </table></td>
     </tr>
   </table>
  </div>
 </body>
</html>
]]>
https://forum.hollaex.com/t/customize-email-templates/1953#post_3 Thu, 08 May 2025 00:11:00 +0000 forum.hollaex.com-post-3582
Customize email templates this may not solve ur direct hollaex email directly but i’ve been using grok ai to create simple HTML emails with decent amount of success

]]>
https://forum.hollaex.com/t/customize-email-templates/1953#post_2 Tue, 06 May 2025 02:42:45 +0000 forum.hollaex.com-post-3581
Customize email templates Hi, I am wondering how I can customize emails template to the users from my exchange.

Can I also update the html template and make something of my own?

]]>
https://forum.hollaex.com/t/customize-email-templates/1953#post_1 Tue, 22 Apr 2025 20:10:23 +0000 forum.hollaex.com-post-3568
Temporary maintenance page You can use Cloudflare’s Maintenance Mode. Simply stop your exchange, and then enable Maintenance Mode via Cloudflare. You can customize the CSS and include your own announcement post on Cloudflare. Here’s a guide to get started: Cloudflare Maintenance Mode Documentation."

In case you don’t have cloudflare setup already checkout this doc.

]]>
https://forum.hollaex.com/t/temporary-maintenance-page/1934#post_2 Fri, 28 Mar 2025 05:15:00 +0000 forum.hollaex.com-post-3549
Custom quote for OTC broker Its quite easy to achieve this with the Dynamic OTC Broker on HollaEx.

You simply go to the OTC broker and create a new one. Then you select the Assets as BTC and ARS

You then select your spread. Its a percentage added to the quote the broker gives the user and it can have your profit margin includes. So 1 would be 1%. I put 0.1% here which is. pretty small spread margin to be very competitive.

You then click Advanced and set the formula for it to be binance_btc-usdt*binance_usdt-ars

This means to calculate the price it should take the BTC-USDT price from Binance then multiply that by the USDT-ARS price from Binance. Note that you can set this to anything you want. You can even set USDT-ARS price to be static like you requested here by putting a static value so for example binance_btc-usdt*1070. and 1070 here is the exchange rate between USDT-ARS I put here statically. I just checked and alternatively I could even get BTC-ARS exchange rate directly from Binance since Binance has that market listed.

Once that is all set, you then proceed and create the broker. Now each time a user gets the price it would automatically get the prices dynamically and display the correct value with the spread you selected as you can see in the image below.

Helpful Resources:

HollaEx Crypto OTC Broker: Dynamic Pricing and Hedging

]]>
https://forum.hollaex.com/t/custom-quote-for-otc-broker/1735#post_2 Fri, 28 Mar 2025 05:10:36 +0000 forum.hollaex.com-post-3548
Get total volume traded by a user Thanks a lot. I put this as a plugin endpoint with a few tweaks and it works like a charm.

Can you also give me a sample code using the HollaEx Admin APIs?

]]>
https://forum.hollaex.com/t/get-total-volume-traded-by-a-user/1928#post_3 Fri, 28 Mar 2025 00:52:03 +0000 forum.hollaex.com-post-3546
Temporary maintenance page I would like to take my exchange down and display a temporary maintenance page with my own custom announcement post. How can I achieve that on HollaEx?

]]>
https://forum.hollaex.com/t/temporary-maintenance-page/1934#post_1 Fri, 28 Mar 2025 00:50:09 +0000 forum.hollaex.com-post-3545