From f717f89d478fb83d133b99b40dbe4ccc04ae9fd8 Mon Sep 17 00:00:00 2001
From: ben888
Date: Mon, 20 Oct 2025 23:43:06 +0700
Subject: [PATCH 1/6] Add useAllowance and useSend hooks; update tailwind
config with safelist
---
src/lib/massa-react/hooks/index.ts | 2 +
src/lib/massa-react/hooks/useAllowance.tsx | 80 +++++++++++
src/lib/massa-react/hooks/useSend.ts | 133 ++++++++++++++++++
src/lib/massa-react/utils/operationHandler.ts | 1 +
src/lib/massa-react/utils/sendTransaction.ts | 66 +++++++++
tailwind.config.js | 14 ++
6 files changed, 296 insertions(+)
create mode 100644 src/lib/massa-react/hooks/useAllowance.tsx
create mode 100644 src/lib/massa-react/hooks/useSend.ts
create mode 100644 src/lib/massa-react/utils/sendTransaction.ts
diff --git a/src/lib/massa-react/hooks/index.ts b/src/lib/massa-react/hooks/index.ts
index 300d7fad..428a8c72 100644
--- a/src/lib/massa-react/hooks/index.ts
+++ b/src/lib/massa-react/hooks/index.ts
@@ -4,3 +4,5 @@ export * from './useDisclaimer';
export * from './useResolveDeweb';
export * from './types';
export * from './const';
+export * from './useSend';
+export * from './useAllowance';
diff --git a/src/lib/massa-react/hooks/useAllowance.tsx b/src/lib/massa-react/hooks/useAllowance.tsx
new file mode 100644
index 00000000..a5215e0b
--- /dev/null
+++ b/src/lib/massa-react/hooks/useAllowance.tsx
@@ -0,0 +1,80 @@
+import { useCallback, useMemo, useState } from 'react';
+import { MRC20, Provider } from '@massalabs/massa-web3';
+import { useHandleOperation } from './useHandleOperation';
+import toast from 'react-hot-toast';
+import { Asset } from './useSend';
+
+export interface AllowanceParams {
+ spender: string;
+ amount: bigint;
+ token: Asset;
+}
+
+export interface UseAllowanceOptions {
+ provider: Provider | null;
+}
+
+export function useAllowance(options: UseAllowanceOptions) {
+ const { provider } = options;
+ const [isProcessing, setIsProcessing] = useState(false);
+ const { handleOperation } = useHandleOperation();
+
+ const increaseAllowance = useCallback(
+ async ({ spender, amount, token }: AllowanceParams): Promise => {
+ if (!provider) throw new Error('No provider');
+ setIsProcessing(true);
+ if (!token.address) throw new Error('Token address required');
+ const mrc20 = new MRC20(provider, token.address);
+ try {
+ const current = await mrc20.allowance(provider.address, spender);
+ if (current >= amount) {
+ toast.error('Already sufficient allowance');
+ setIsProcessing(false);
+ return;
+ }
+ const op = await mrc20.increaseAllowance(spender, amount - current);
+ await handleOperation(op, {
+ pending: `Increasing allowance ${amount} ${token.symbol}`,
+ success: `Increased allowance ${amount} ${token.symbol}`,
+ error: `Error increasing allowance`,
+ timeout: `Timeout increasing allowance`,
+ });
+ } finally {
+ setIsProcessing(false);
+ }
+ },
+ [provider, handleOperation],
+ );
+
+ const decreaseAllowance = useCallback(
+ async ({ spender, amount, token }: AllowanceParams): Promise => {
+ if (!provider) throw new Error('No provider');
+ setIsProcessing(true);
+ if (!token.address) throw new Error('Token address required');
+ const mrc20 = new MRC20(provider, token.address);
+ try {
+ const current = await mrc20.allowance(provider.address, spender);
+ if (current < amount) {
+ toast.error('Cannot decrease below current allowance');
+ setIsProcessing(false);
+ return;
+ }
+ const op = await mrc20.decreaseAllowance(spender, amount);
+ await handleOperation(op, {
+ pending: `Decreasing allowance ${amount} ${token.symbol}`,
+ success: `Decreased allowance ${amount} ${token.symbol}`,
+ error: `Error decreasing allowance`,
+ timeout: `Timeout decreasing allowance`,
+ });
+ } finally {
+ setIsProcessing(false);
+ }
+ },
+ [provider, handleOperation],
+ );
+
+ return useMemo(
+ () => ({ isProcessing, increaseAllowance, decreaseAllowance }),
+ [isProcessing, increaseAllowance, decreaseAllowance],
+ );
+}
diff --git a/src/lib/massa-react/hooks/useSend.ts b/src/lib/massa-react/hooks/useSend.ts
new file mode 100644
index 00000000..037d3be1
--- /dev/null
+++ b/src/lib/massa-react/hooks/useSend.ts
@@ -0,0 +1,133 @@
+import { useCallback, useMemo, useState } from 'react';
+import { Address, MRC20, Operation, Provider } from '@massalabs/massa-web3';
+import { validateAmount } from '../utils/sendTransaction';
+import { useHandleOperation } from './useHandleOperation';
+import toast from 'react-hot-toast';
+
+export interface Asset {
+ decimals: number;
+ balance: bigint;
+ symbol: string;
+ address?: string;
+ isNative?: boolean;
+ allowance?: bigint;
+}
+
+export interface SendParams {
+ recipient: string;
+ amount: bigint;
+ asset: Asset;
+}
+
+export interface UseSendOptions {
+ provider: Provider | null;
+}
+
+export function useSend(options: UseSendOptions) {
+ const { provider } = options;
+ const [isProcessing, setIsProcessing] = useState(false);
+ const { handleOperation } = useHandleOperation();
+
+ const execute = useCallback(
+ async (
+ sendFn: () => Promise,
+ asset: Asset,
+ amount: bigint,
+ recipient: string,
+ ): Promise => {
+ console.log('execute', sendFn, asset, amount, recipient);
+ console.log('provider', provider);
+ if (!provider) throw new Error('No provider');
+ console.log('provider', provider);
+ setIsProcessing(true);
+
+ const validation = validateAmount(amount, asset.balance, asset.decimals);
+ console.log('validation', validation);
+ if (!validation.valid) {
+ toast.error(validation.error ?? 'Invalid amount');
+ setIsProcessing(false);
+ return;
+ }
+
+ console.log('validation passed');
+
+ try {
+ Address.fromString(recipient);
+ } catch {
+ toast.error('Invalid address');
+ setIsProcessing(false);
+ return;
+ }
+
+ console.log('recipient', recipient);
+ try {
+ const op = await sendFn();
+ console.log('op', op);
+ await handleOperation(op, {
+ pending: `Sending ${amount} ${asset.symbol}`,
+ success: `Sent ${amount} ${asset.symbol}`,
+ error: `Error sending`,
+ timeout: `Timeout sending`,
+ });
+ } finally {
+ setIsProcessing(false);
+ }
+ },
+ [provider, handleOperation],
+ );
+
+ const sendMassa = useCallback(
+ async ({ recipient, amount, asset }: SendParams): Promise => {
+ if (!provider) throw new Error('No provider');
+ await execute(
+ () => provider.transfer(recipient, amount),
+ asset,
+ amount,
+ recipient,
+ );
+ },
+ [provider, execute],
+ );
+
+ const sendToken = useCallback(
+ async ({ recipient, amount, asset }: SendParams): Promise => {
+ if (!provider) throw new Error('No provider');
+ if (!asset.address) throw new Error('Token address required');
+ const mrc20 = new MRC20(provider, asset.address);
+
+ const allowance = await mrc20.allowance(provider.address, recipient);
+ if (allowance < amount) {
+ toast.error('Insufficient allowance');
+ return;
+ }
+
+ await execute(
+ () => mrc20.transfer(recipient, amount),
+ asset,
+ amount,
+ recipient,
+ );
+ },
+ [provider, execute],
+ );
+
+ const sendAsset = useCallback(
+ async ({ recipient, amount, asset }: SendParams): Promise => {
+ if (asset.isNative) {
+ console.log('sendMassa', recipient, amount, asset);
+ return sendMassa({ recipient, amount, asset });
+ }
+
+ return sendToken({ recipient, amount, asset });
+ },
+ [sendMassa, sendToken],
+ );
+
+ return useMemo(
+ () => ({
+ isProcessing,
+ sendAsset,
+ }),
+ [isProcessing, sendAsset],
+ );
+}
diff --git a/src/lib/massa-react/utils/operationHandler.ts b/src/lib/massa-react/utils/operationHandler.ts
index 449a3fd3..d3523383 100644
--- a/src/lib/massa-react/utils/operationHandler.ts
+++ b/src/lib/massa-react/utils/operationHandler.ts
@@ -20,6 +20,7 @@ export async function processOperation(
setState: React.Dispatch>,
): Promise {
try {
+ console.log('processOperation', operation.id);
updateOpState(setState, { opId: operation.id });
const loadingToastId = showToast(
diff --git a/src/lib/massa-react/utils/sendTransaction.ts b/src/lib/massa-react/utils/sendTransaction.ts
new file mode 100644
index 00000000..88d3ca8e
--- /dev/null
+++ b/src/lib/massa-react/utils/sendTransaction.ts
@@ -0,0 +1,66 @@
+export interface TransactionValidationResult {
+ valid: boolean;
+ error?: string;
+}
+
+export interface AmountValidationResult {
+ valid: boolean;
+ error?: string;
+ amount?: bigint;
+}
+
+/**
+ * Validates and parses an amount string
+ */
+export function validateAmount(
+ amount: bigint,
+ availableBalance: bigint,
+ decimals: number,
+ minAmount = 0n,
+): AmountValidationResult {
+ console.log('validateAmount', amount, availableBalance, decimals, minAmount);
+ if (!amount || amount === 0n) {
+ return { valid: false, error: 'Amount is required' };
+ }
+
+ if (amount <= 0) {
+ return { valid: false, error: 'Amount must be greater than 0' };
+ }
+
+ if (amount < minAmount) {
+ const minAmountFormatted = (Number(minAmount) / 10 ** decimals).toFixed(
+ decimals,
+ );
+ return {
+ valid: false,
+ error: `Minimum amount is ${minAmountFormatted}`,
+ };
+ }
+
+ if (amount > availableBalance) {
+ return { valid: false, error: 'Insufficient balance' };
+ }
+
+ return {
+ valid: true,
+ amount,
+ };
+}
+
+/**
+ * Calculates the total cost of a transaction (amount + fees)
+ */
+export function calculateTotalCost(amount: bigint, fee: bigint): bigint {
+ return amount + fee;
+}
+
+/**
+ * Checks if the user has sufficient balance for the transaction
+ */
+export function hasSufficientBalance(
+ availableBalance: bigint,
+ amount: bigint,
+ fee: bigint,
+): boolean {
+ return availableBalance >= amount + fee;
+}
diff --git a/tailwind.config.js b/tailwind.config.js
index db33731b..6d6613c7 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,4 +1,18 @@
/** @type {import('tailwindcss').Config} */
export default {
presets: [require('./presets/massa-station-preset.js')],
+ safelist: [
+ 'mas-banner',
+ 'mas-title',
+ 'mas-subtitle',
+ 'mas-h2',
+ 'mas-h3',
+ 'mas-buttons',
+ 'mas-menu-active',
+ 'mas-menu-default',
+ 'mas-menu-underline',
+ 'mas-body',
+ 'mas-body2',
+ 'mas-caption',
+ ],
};
From f04aeae5eaa0447d433c2d9403d0315cbdf07138 Mon Sep 17 00:00:00 2001
From: ben888
Date: Tue, 21 Oct 2025 00:00:08 +0700
Subject: [PATCH 2/6] Refactor error messages and remove debug logs in
useAllowance and useSend hooks; streamline validation in sendTransaction
---
src/lib/massa-react/hooks/useAllowance.tsx | 2 +-
src/lib/massa-react/hooks/useSend.ts | 17 +----------------
src/lib/massa-react/utils/operationHandler.ts | 1 -
src/lib/massa-react/utils/sendTransaction.ts | 7 +------
4 files changed, 3 insertions(+), 24 deletions(-)
diff --git a/src/lib/massa-react/hooks/useAllowance.tsx b/src/lib/massa-react/hooks/useAllowance.tsx
index a5215e0b..ecc14aaa 100644
--- a/src/lib/massa-react/hooks/useAllowance.tsx
+++ b/src/lib/massa-react/hooks/useAllowance.tsx
@@ -55,7 +55,7 @@ export function useAllowance(options: UseAllowanceOptions) {
try {
const current = await mrc20.allowance(provider.address, spender);
if (current < amount) {
- toast.error('Cannot decrease below current allowance');
+ toast.error('Insufficient allowance to decrease by requested amount');
setIsProcessing(false);
return;
}
diff --git a/src/lib/massa-react/hooks/useSend.ts b/src/lib/massa-react/hooks/useSend.ts
index 037d3be1..c3308bbb 100644
--- a/src/lib/massa-react/hooks/useSend.ts
+++ b/src/lib/massa-react/hooks/useSend.ts
@@ -10,7 +10,6 @@ export interface Asset {
symbol: string;
address?: string;
isNative?: boolean;
- allowance?: bigint;
}
export interface SendParams {
@@ -35,22 +34,17 @@ export function useSend(options: UseSendOptions) {
amount: bigint,
recipient: string,
): Promise => {
- console.log('execute', sendFn, asset, amount, recipient);
- console.log('provider', provider);
if (!provider) throw new Error('No provider');
- console.log('provider', provider);
setIsProcessing(true);
const validation = validateAmount(amount, asset.balance, asset.decimals);
- console.log('validation', validation);
+
if (!validation.valid) {
toast.error(validation.error ?? 'Invalid amount');
setIsProcessing(false);
return;
}
- console.log('validation passed');
-
try {
Address.fromString(recipient);
} catch {
@@ -59,10 +53,8 @@ export function useSend(options: UseSendOptions) {
return;
}
- console.log('recipient', recipient);
try {
const op = await sendFn();
- console.log('op', op);
await handleOperation(op, {
pending: `Sending ${amount} ${asset.symbol}`,
success: `Sent ${amount} ${asset.symbol}`,
@@ -95,12 +87,6 @@ export function useSend(options: UseSendOptions) {
if (!asset.address) throw new Error('Token address required');
const mrc20 = new MRC20(provider, asset.address);
- const allowance = await mrc20.allowance(provider.address, recipient);
- if (allowance < amount) {
- toast.error('Insufficient allowance');
- return;
- }
-
await execute(
() => mrc20.transfer(recipient, amount),
asset,
@@ -114,7 +100,6 @@ export function useSend(options: UseSendOptions) {
const sendAsset = useCallback(
async ({ recipient, amount, asset }: SendParams): Promise => {
if (asset.isNative) {
- console.log('sendMassa', recipient, amount, asset);
return sendMassa({ recipient, amount, asset });
}
diff --git a/src/lib/massa-react/utils/operationHandler.ts b/src/lib/massa-react/utils/operationHandler.ts
index d3523383..449a3fd3 100644
--- a/src/lib/massa-react/utils/operationHandler.ts
+++ b/src/lib/massa-react/utils/operationHandler.ts
@@ -20,7 +20,6 @@ export async function processOperation(
setState: React.Dispatch>,
): Promise {
try {
- console.log('processOperation', operation.id);
updateOpState(setState, { opId: operation.id });
const loadingToastId = showToast(
diff --git a/src/lib/massa-react/utils/sendTransaction.ts b/src/lib/massa-react/utils/sendTransaction.ts
index 88d3ca8e..0891d1f3 100644
--- a/src/lib/massa-react/utils/sendTransaction.ts
+++ b/src/lib/massa-react/utils/sendTransaction.ts
@@ -18,15 +18,10 @@ export function validateAmount(
decimals: number,
minAmount = 0n,
): AmountValidationResult {
- console.log('validateAmount', amount, availableBalance, decimals, minAmount);
- if (!amount || amount === 0n) {
+ if (!amount) {
return { valid: false, error: 'Amount is required' };
}
- if (amount <= 0) {
- return { valid: false, error: 'Amount must be greater than 0' };
- }
-
if (amount < minAmount) {
const minAmountFormatted = (Number(minAmount) / 10 ** decimals).toFixed(
decimals,
From f5e42816ea3dd251ba007214307b5c8701072a28 Mon Sep 17 00:00:00 2001
From: ben888
Date: Tue, 21 Oct 2025 08:27:06 +0700
Subject: [PATCH 3/6] Refactor useAllowance and useSend hooks to format amount
display; remove safelist from tailwind config
---
src/lib/massa-react/hooks/useAllowance.tsx | 21 +++++++++++++++++----
src/lib/massa-react/hooks/useSend.ts | 9 +++++++--
tailwind.config.js | 14 --------------
3 files changed, 24 insertions(+), 20 deletions(-)
diff --git a/src/lib/massa-react/hooks/useAllowance.tsx b/src/lib/massa-react/hooks/useAllowance.tsx
index ecc14aaa..f5281974 100644
--- a/src/lib/massa-react/hooks/useAllowance.tsx
+++ b/src/lib/massa-react/hooks/useAllowance.tsx
@@ -3,6 +3,7 @@ import { MRC20, Provider } from '@massalabs/massa-web3';
import { useHandleOperation } from './useHandleOperation';
import toast from 'react-hot-toast';
import { Asset } from './useSend';
+import { formatAmount } from '../../util';
export interface AllowanceParams {
spender: string;
@@ -34,8 +35,14 @@ export function useAllowance(options: UseAllowanceOptions) {
}
const op = await mrc20.increaseAllowance(spender, amount - current);
await handleOperation(op, {
- pending: `Increasing allowance ${amount} ${token.symbol}`,
- success: `Increased allowance ${amount} ${token.symbol}`,
+ pending: `Increasing allowance ${formatAmount(
+ amount.toString(),
+ token.decimals,
+ )} ${token.symbol}`,
+ success: `Increased allowance ${formatAmount(
+ amount.toString(),
+ token.decimals,
+ )} ${token.symbol}`,
error: `Error increasing allowance`,
timeout: `Timeout increasing allowance`,
});
@@ -61,8 +68,14 @@ export function useAllowance(options: UseAllowanceOptions) {
}
const op = await mrc20.decreaseAllowance(spender, amount);
await handleOperation(op, {
- pending: `Decreasing allowance ${amount} ${token.symbol}`,
- success: `Decreased allowance ${amount} ${token.symbol}`,
+ pending: `Decreasing allowance ${formatAmount(
+ amount.toString(),
+ token.decimals,
+ )} ${token.symbol}`,
+ success: `Decreased allowance ${formatAmount(
+ amount.toString(),
+ token.decimals,
+ )} ${token.symbol}`,
error: `Error decreasing allowance`,
timeout: `Timeout decreasing allowance`,
});
diff --git a/src/lib/massa-react/hooks/useSend.ts b/src/lib/massa-react/hooks/useSend.ts
index c3308bbb..94be41b2 100644
--- a/src/lib/massa-react/hooks/useSend.ts
+++ b/src/lib/massa-react/hooks/useSend.ts
@@ -3,6 +3,7 @@ import { Address, MRC20, Operation, Provider } from '@massalabs/massa-web3';
import { validateAmount } from '../utils/sendTransaction';
import { useHandleOperation } from './useHandleOperation';
import toast from 'react-hot-toast';
+import { formatAmount } from '../../util';
export interface Asset {
decimals: number;
@@ -56,8 +57,12 @@ export function useSend(options: UseSendOptions) {
try {
const op = await sendFn();
await handleOperation(op, {
- pending: `Sending ${amount} ${asset.symbol}`,
- success: `Sent ${amount} ${asset.symbol}`,
+ pending: `Sending ${
+ formatAmount(amount.toString(), asset.decimals).preview
+ } ${asset.symbol}`,
+ success: `Sent ${
+ formatAmount(amount.toString(), asset.decimals).preview
+ } ${asset.symbol}`,
error: `Error sending`,
timeout: `Timeout sending`,
});
diff --git a/tailwind.config.js b/tailwind.config.js
index 6d6613c7..db33731b 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,18 +1,4 @@
/** @type {import('tailwindcss').Config} */
export default {
presets: [require('./presets/massa-station-preset.js')],
- safelist: [
- 'mas-banner',
- 'mas-title',
- 'mas-subtitle',
- 'mas-h2',
- 'mas-h3',
- 'mas-buttons',
- 'mas-menu-active',
- 'mas-menu-default',
- 'mas-menu-underline',
- 'mas-body',
- 'mas-body2',
- 'mas-caption',
- ],
};
From c1bc0ec1379215f8c31d55da898400b14085133f Mon Sep 17 00:00:00 2001
From: ben888
Date: Tue, 21 Oct 2025 08:39:37 +0700
Subject: [PATCH 4/6] Refactor allowance messages in useAllowance hook to
utilize formatted amount previews for better clarity
---
src/lib/massa-react/hooks/useAllowance.tsx | 28 ++++++++++------------
1 file changed, 12 insertions(+), 16 deletions(-)
diff --git a/src/lib/massa-react/hooks/useAllowance.tsx b/src/lib/massa-react/hooks/useAllowance.tsx
index f5281974..9fbd3c67 100644
--- a/src/lib/massa-react/hooks/useAllowance.tsx
+++ b/src/lib/massa-react/hooks/useAllowance.tsx
@@ -35,14 +35,12 @@ export function useAllowance(options: UseAllowanceOptions) {
}
const op = await mrc20.increaseAllowance(spender, amount - current);
await handleOperation(op, {
- pending: `Increasing allowance ${formatAmount(
- amount.toString(),
- token.decimals,
- )} ${token.symbol}`,
- success: `Increased allowance ${formatAmount(
- amount.toString(),
- token.decimals,
- )} ${token.symbol}`,
+ pending: `Increasing allowance ${
+ formatAmount(amount.toString(), token.decimals).preview
+ } ${token.symbol}`,
+ success: `Increased allowance ${
+ formatAmount(amount.toString(), token.decimals).preview
+ } ${token.symbol}`,
error: `Error increasing allowance`,
timeout: `Timeout increasing allowance`,
});
@@ -68,14 +66,12 @@ export function useAllowance(options: UseAllowanceOptions) {
}
const op = await mrc20.decreaseAllowance(spender, amount);
await handleOperation(op, {
- pending: `Decreasing allowance ${formatAmount(
- amount.toString(),
- token.decimals,
- )} ${token.symbol}`,
- success: `Decreased allowance ${formatAmount(
- amount.toString(),
- token.decimals,
- )} ${token.symbol}`,
+ pending: `Decreasing allowance ${
+ formatAmount(amount.toString(), token.decimals).preview
+ } ${token.symbol}`,
+ success: `Decreased allowance ${
+ formatAmount(amount.toString(), token.decimals).preview
+ } ${token.symbol}`,
error: `Error decreasing allowance`,
timeout: `Timeout decreasing allowance`,
});
From de8d84cae450d71e382123d1b73edda8172e9ba7 Mon Sep 17 00:00:00 2001
From: ben888
Date: Tue, 21 Oct 2025 10:02:43 +0700
Subject: [PATCH 5/6] Update toast messages in useAllowance hook for improved
clarity and accuracy
---
src/lib/massa-react/hooks/useAllowance.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/lib/massa-react/hooks/useAllowance.tsx b/src/lib/massa-react/hooks/useAllowance.tsx
index 9fbd3c67..8d645b31 100644
--- a/src/lib/massa-react/hooks/useAllowance.tsx
+++ b/src/lib/massa-react/hooks/useAllowance.tsx
@@ -29,7 +29,7 @@ export function useAllowance(options: UseAllowanceOptions) {
try {
const current = await mrc20.allowance(provider.address, spender);
if (current >= amount) {
- toast.error('Already sufficient allowance');
+ toast('Already sufficient allowance');
setIsProcessing(false);
return;
}
@@ -60,7 +60,7 @@ export function useAllowance(options: UseAllowanceOptions) {
try {
const current = await mrc20.allowance(provider.address, spender);
if (current < amount) {
- toast.error('Insufficient allowance to decrease by requested amount');
+ toast.error('Decrease amount is greater than current allowance');
setIsProcessing(false);
return;
}
From 6fe813a5175fdd824e2f618f80d1c40de2167969 Mon Sep 17 00:00:00 2001
From: ben888
Date: Tue, 21 Oct 2025 15:00:48 +0700
Subject: [PATCH 6/6] Refactor asset type definition and update useAllowance
and useSend hooks to improve clarity and remove unused validation logic
---
src/lib/massa-react/hooks/types.ts | 8 +++
src/lib/massa-react/hooks/useAllowance.tsx | 36 +++---------
src/lib/massa-react/hooks/useSend.ts | 60 +++++++++++++------
src/lib/massa-react/utils/sendTransaction.ts | 61 --------------------
4 files changed, 57 insertions(+), 108 deletions(-)
delete mode 100644 src/lib/massa-react/utils/sendTransaction.ts
diff --git a/src/lib/massa-react/hooks/types.ts b/src/lib/massa-react/hooks/types.ts
index 51f021ea..cb7cdbd9 100644
--- a/src/lib/massa-react/hooks/types.ts
+++ b/src/lib/massa-react/hooks/types.ts
@@ -4,3 +4,11 @@ export type ToasterMessage = {
error: string;
timeout?: string;
};
+
+export interface Asset {
+ decimals: number;
+ balance: bigint;
+ symbol: string;
+ address?: string;
+ isNative?: boolean;
+}
diff --git a/src/lib/massa-react/hooks/useAllowance.tsx b/src/lib/massa-react/hooks/useAllowance.tsx
index 8d645b31..7cd3e62f 100644
--- a/src/lib/massa-react/hooks/useAllowance.tsx
+++ b/src/lib/massa-react/hooks/useAllowance.tsx
@@ -1,9 +1,7 @@
import { useCallback, useMemo, useState } from 'react';
import { MRC20, Provider } from '@massalabs/massa-web3';
import { useHandleOperation } from './useHandleOperation';
-import toast from 'react-hot-toast';
-import { Asset } from './useSend';
-import { formatAmount } from '../../util';
+import { Asset } from './types';
export interface AllowanceParams {
spender: string;
@@ -24,23 +22,15 @@ export function useAllowance(options: UseAllowanceOptions) {
async ({ spender, amount, token }: AllowanceParams): Promise => {
if (!provider) throw new Error('No provider');
setIsProcessing(true);
+
if (!token.address) throw new Error('Token address required');
const mrc20 = new MRC20(provider, token.address);
try {
- const current = await mrc20.allowance(provider.address, spender);
- if (current >= amount) {
- toast('Already sufficient allowance');
- setIsProcessing(false);
- return;
- }
- const op = await mrc20.increaseAllowance(spender, amount - current);
+ const op = await mrc20.increaseAllowance(spender, amount);
+
await handleOperation(op, {
- pending: `Increasing allowance ${
- formatAmount(amount.toString(), token.decimals).preview
- } ${token.symbol}`,
- success: `Increased allowance ${
- formatAmount(amount.toString(), token.decimals).preview
- } ${token.symbol}`,
+ pending: `Increasing allowance ${amount} ${token.symbol}`,
+ success: `Increased allowance ${amount} ${token.symbol}`,
error: `Error increasing allowance`,
timeout: `Timeout increasing allowance`,
});
@@ -58,20 +48,10 @@ export function useAllowance(options: UseAllowanceOptions) {
if (!token.address) throw new Error('Token address required');
const mrc20 = new MRC20(provider, token.address);
try {
- const current = await mrc20.allowance(provider.address, spender);
- if (current < amount) {
- toast.error('Decrease amount is greater than current allowance');
- setIsProcessing(false);
- return;
- }
const op = await mrc20.decreaseAllowance(spender, amount);
await handleOperation(op, {
- pending: `Decreasing allowance ${
- formatAmount(amount.toString(), token.decimals).preview
- } ${token.symbol}`,
- success: `Decreased allowance ${
- formatAmount(amount.toString(), token.decimals).preview
- } ${token.symbol}`,
+ pending: `Decreasing allowance ${amount} ${token.symbol}`,
+ success: `Decreased allowance ${amount} ${token.symbol}`,
error: `Error decreasing allowance`,
timeout: `Timeout decreasing allowance`,
});
diff --git a/src/lib/massa-react/hooks/useSend.ts b/src/lib/massa-react/hooks/useSend.ts
index 94be41b2..f8a46a01 100644
--- a/src/lib/massa-react/hooks/useSend.ts
+++ b/src/lib/massa-react/hooks/useSend.ts
@@ -1,17 +1,9 @@
import { useCallback, useMemo, useState } from 'react';
import { Address, MRC20, Operation, Provider } from '@massalabs/massa-web3';
-import { validateAmount } from '../utils/sendTransaction';
import { useHandleOperation } from './useHandleOperation';
import toast from 'react-hot-toast';
import { formatAmount } from '../../util';
-
-export interface Asset {
- decimals: number;
- balance: bigint;
- symbol: string;
- address?: string;
- isNative?: boolean;
-}
+import { Asset } from './types';
export interface SendParams {
recipient: string;
@@ -28,6 +20,14 @@ export function useSend(options: UseSendOptions) {
const [isProcessing, setIsProcessing] = useState(false);
const { handleOperation } = useHandleOperation();
+ /**
+ * Executes a send operation
+ * @param sendFn - The function to send the asset
+ * @param asset - The asset to send
+ * @param amount - The amount to send
+ * @param recipient - The recipient address
+ * @returns void
+ */
const execute = useCallback(
async (
sendFn: () => Promise,
@@ -35,27 +35,25 @@ export function useSend(options: UseSendOptions) {
amount: bigint,
recipient: string,
): Promise => {
- if (!provider) throw new Error('No provider');
setIsProcessing(true);
- const validation = validateAmount(amount, asset.balance, asset.decimals);
-
- if (!validation.valid) {
- toast.error(validation.error ?? 'Invalid amount');
- setIsProcessing(false);
- return;
- }
+ if (!provider) throw new Error('No provider');
try {
Address.fromString(recipient);
} catch {
toast.error('Invalid address');
- setIsProcessing(false);
+ return;
+ }
+
+ if (amount > asset.balance) {
+ toast.error('Insufficient balance');
return;
}
try {
const op = await sendFn();
+
await handleOperation(op, {
pending: `Sending ${
formatAmount(amount.toString(), asset.decimals).preview
@@ -73,6 +71,13 @@ export function useSend(options: UseSendOptions) {
[provider, handleOperation],
);
+ /**
+ * Sends a native Massa coin to a recipient
+ * @param recipient - The recipient address
+ * @param amount - The amount to send
+ * @param asset - The asset to send
+ * @returns void
+ */
const sendMassa = useCallback(
async ({ recipient, amount, asset }: SendParams): Promise => {
if (!provider) throw new Error('No provider');
@@ -86,6 +91,13 @@ export function useSend(options: UseSendOptions) {
[provider, execute],
);
+ /**
+ * Sends a mrc20 token to a recipient
+ * @param recipient - The recipient address
+ * @param amount - The amount to send
+ * @param asset - The token to send
+ * @returns void
+ */
const sendToken = useCallback(
async ({ recipient, amount, asset }: SendParams): Promise => {
if (!provider) throw new Error('No provider');
@@ -102,6 +114,14 @@ export function useSend(options: UseSendOptions) {
[provider, execute],
);
+ /**
+ * Sends an asset to a recipient
+ * The Asset can be a native Massa coin or a mrc20 token
+ * @param recipient - The recipient address
+ * @param amount - The amount to send
+ * @param asset - The asset to send
+ * @returns void
+ */
const sendAsset = useCallback(
async ({ recipient, amount, asset }: SendParams): Promise => {
if (asset.isNative) {
@@ -117,7 +137,9 @@ export function useSend(options: UseSendOptions) {
() => ({
isProcessing,
sendAsset,
+ sendMassa,
+ sendToken,
}),
- [isProcessing, sendAsset],
+ [isProcessing, sendAsset, sendMassa, sendToken],
);
}
diff --git a/src/lib/massa-react/utils/sendTransaction.ts b/src/lib/massa-react/utils/sendTransaction.ts
deleted file mode 100644
index 0891d1f3..00000000
--- a/src/lib/massa-react/utils/sendTransaction.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-export interface TransactionValidationResult {
- valid: boolean;
- error?: string;
-}
-
-export interface AmountValidationResult {
- valid: boolean;
- error?: string;
- amount?: bigint;
-}
-
-/**
- * Validates and parses an amount string
- */
-export function validateAmount(
- amount: bigint,
- availableBalance: bigint,
- decimals: number,
- minAmount = 0n,
-): AmountValidationResult {
- if (!amount) {
- return { valid: false, error: 'Amount is required' };
- }
-
- if (amount < minAmount) {
- const minAmountFormatted = (Number(minAmount) / 10 ** decimals).toFixed(
- decimals,
- );
- return {
- valid: false,
- error: `Minimum amount is ${minAmountFormatted}`,
- };
- }
-
- if (amount > availableBalance) {
- return { valid: false, error: 'Insufficient balance' };
- }
-
- return {
- valid: true,
- amount,
- };
-}
-
-/**
- * Calculates the total cost of a transaction (amount + fees)
- */
-export function calculateTotalCost(amount: bigint, fee: bigint): bigint {
- return amount + fee;
-}
-
-/**
- * Checks if the user has sufficient balance for the transaction
- */
-export function hasSufficientBalance(
- availableBalance: bigint,
- amount: bigint,
- fee: bigint,
-): boolean {
- return availableBalance >= amount + fee;
-}