import { z } from 'zod'; import { Token } from './token.js'; import type { Currency } from './currency-type.js'; import { formatUnits, parseUnits } from 'viem'; import { SerializableErc20TokenTypeSchema } from './base-currency.js'; export type TokenOrCurrency = Token | Currency; /** * Serializable currency amount schema */ export const SerializableCurrencyAmountTypeSchema = z.object({ amount: z.object({ raw: z.bigint(), humanReadable: z.number(), }), currency: SerializableErc20TokenTypeSchema, }); /** * A serializable currency amount */ export type SerializableCurrencyAmountType = z.infer; export class Amount { public readonly currency: T; public readonly rawAmount: bigint; private constructor(currency: T, rawAmount: bigint) { this.currency = currency; this.rawAmount = rawAmount; } public static fromRawAmount(currency: T, rawAmount: bigint) { return new Amount(currency, rawAmount); } /** * Create an amount from a human readable amount * @param currency - The currency to create the amount for * @param humanReadableAmount - The human readable amount, can be a number or a string * @returns The amount */ public static fromHumanReadableAmount(currency: T, humanReadableAmount: number | string) { return new Amount(currency, parseUnits(humanReadableAmount.toString(), currency.decimals)); } public toRawAmount() { return this.rawAmount; } /** * Convert the amount to a human readable format * @returns Human readable amount */ public toHumanReadableAmountString() { return formatUnits(this.rawAmount, this.currency.decimals); } /** * Convert the amount to a human readable format * @returns Human readable amount */ public toHumanReadableAmount() { return Number(this.toHumanReadableAmountString()); } public get humanAmount() { return this.toHumanReadableAmount(); } public toObject(): SerializableCurrencyAmountType { return { amount: { raw: this.rawAmount, humanReadable: this.toHumanReadableAmount(), }, currency: this.currency.toObject(), }; } public static fromObject(object: SerializableCurrencyAmountType) { // validate the object const validatedObject = SerializableCurrencyAmountTypeSchema.parse(object); return new Amount(Token.fromObject(validatedObject.currency) as T, validatedObject.amount.raw); } }