From 6a234caaac0fb0043ec91d83407c7b427f34dd86 Mon Sep 17 00:00:00 2001 From: manoahLinks Date: Sat, 18 Jul 2026 03:53:39 +0100 Subject: [PATCH] fix(crypto): route settlement through USDT fee slot (testnet workaround) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The deployed Base Sepolia Diamond has the real USDC token registered under the USDT (4) FeeType slot; USDC (5) is unset, so mintTicket(…, USDC, …) reverts TokenAddressZero() and Circle never submits the mint (approve lands, allowance untouched, nothing settles). Route crypto publish + settlement through `SETTLEMENT_FEE_TYPE_NAME` (now 'USDT' = slot 4), which resolves to the USDC token on-chain, so approve + mintTicket succeed. Publish sets the fee under the same slot, keeping getAllFees/feeEnabled consistent. TEMPORARY: revert `SETTLEMENT_FEE_TYPE_NAME` to 'USDC' once the Diamond is redeployed with USDC (5) mapped to the USDC address. Requires re-publishing events (existing ones have the fee under slot 5). Tracked in #96. --- src/blockchain/mint-ticket.processor.spec.ts | 11 ++++++++--- src/blockchain/onchain-fees.ts | 17 +++++++++++++++-- src/events/events.service.ts | 14 +++++++++----- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/blockchain/mint-ticket.processor.spec.ts b/src/blockchain/mint-ticket.processor.spec.ts index 519de92..fffb94f 100644 --- a/src/blockchain/mint-ticket.processor.spec.ts +++ b/src/blockchain/mint-ticket.processor.spec.ts @@ -1,6 +1,7 @@ import { BlockchainTxType, WalletCreationStatus } from '@prisma/client'; import type { Job } from 'bullmq'; import { MintTicketProcessor } from './mint-ticket.processor'; +import { FEE_TYPE_USDC } from './onchain-fees'; import { MINT_TICKET_JOB, MintTicketJobData } from './mint-queue.service'; // getChain is env-driven; stub the USDC + Diamond addresses. @@ -83,8 +84,12 @@ describe('MintTicketProcessor', () => { await m.proc.process(job()); - // Authoritative on-chain fee read for the USDC feeType (5). - expect(m.getAllFees).toHaveBeenCalledWith('BASE-SEPOLIA', 7n, 5); + // Authoritative on-chain fee read for the crypto settlement feeType. + expect(m.getAllFees).toHaveBeenCalledWith( + 'BASE-SEPOLIA', + 7n, + FEE_TYPE_USDC, + ); // Approve the Diamond to pull exactly totalFee from the buyer wallet. expect(m.approveErc20).toHaveBeenCalledWith( expect.objectContaining({ @@ -98,7 +103,7 @@ describe('MintTicketProcessor', () => { expect(m.executeContract).toHaveBeenCalledWith( expect.objectContaining({ method: 'mintTicket', - args: [7n, 5, '0xBUYER'], + args: [7n, FEE_TYPE_USDC, '0xBUYER'], walletId: 'cw-buyer', txType: BlockchainTxType.MINT, existingBlockchainTransactionId: 'bt-1', diff --git a/src/blockchain/onchain-fees.ts b/src/blockchain/onchain-fees.ts index 7d02c13..9df818c 100644 --- a/src/blockchain/onchain-fees.ts +++ b/src/blockchain/onchain-fees.ts @@ -19,8 +19,21 @@ export const FEE_TYPE_BY_NAME: Record = { LSK: 10, }; -/** On-chain FeeType code for USDC — HostIT's crypto settlement token. */ -export const FEE_TYPE_USDC = FEE_TYPE_BY_NAME.USDC; +/** + * ⚠️ TEMPORARY TESTNET WORKAROUND — revert after the Diamond is redeployed. + * + * The deployed Base Sepolia Diamond has the real USDC token address + * registered under the **USDT (4)** slot; `FeeType.USDC (5)` is UNSET, so + * `mintTicket(…, USDC, …)` reverts `TokenAddressZero()`. Until a redeploy + * maps USDC (5) → 0x036CbD5…, we route crypto settlement (publish fee + + * approve + mintTicket) through the USDT slot, which resolves to the USDC + * token on-chain. Flip `SETTLEMENT_FEE_TYPE_NAME` back to `'USDC'` once the + * contract is fixed. Tracked in epic #96. + */ +export const SETTLEMENT_FEE_TYPE_NAME = 'USDT'; + +/** On-chain FeeType code used for crypto (USDC) settlement. */ +export const FEE_TYPE_USDC = FEE_TYPE_BY_NAME[SETTLEMENT_FEE_TYPE_NAME]; /** USDC is 6-decimal everywhere Circle issues it. */ export const USDC_DECIMALS = 6; diff --git a/src/events/events.service.ts b/src/events/events.service.ts index 0967c67..1045e2b 100644 --- a/src/events/events.service.ts +++ b/src/events/events.service.ts @@ -20,7 +20,10 @@ import { Prisma, } from '@prisma/client'; import * as crypto from 'crypto'; -import { computeUsdcFees } from '../blockchain/onchain-fees'; +import { + computeUsdcFees, + SETTLEMENT_FEE_TYPE_NAME, +} from '../blockchain/onchain-fees'; @Injectable() export class EventsService { @@ -536,10 +539,11 @@ export class EventsService { symbol: `${eventSymbol}-${tt.name.replace(/\s+/g, '').slice(0, 4).toUpperCase()}`, uri: `https://api.hostit.ng/events/${event.slug}/${tt.id}/metadata`, }, - // Crypto checkout settles in USDC via `mintTicket`. Free events - // ignore fees on-chain (createTicket skips setTicketFees when - // isFree), so the converted value is harmless there. - feeTypes: ['USDC'], + // Crypto checkout settles in USDC via `mintTicket`. The on-chain fee + // slot is `SETTLEMENT_FEE_TYPE_NAME` (temporarily USDT — see + // onchain-fees.ts). Free events ignore fees on-chain (createTicket + // skips setTicketFees when isFree), so the value is harmless there. + feeTypes: [SETTLEMENT_FEE_TYPE_NAME], prices: [computeUsdcFees(tt.price, usdcNgnRate).ticketFee], }));