diff --git a/.gitignore b/.gitignore index 256abbb..055addd 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,6 @@ coverage/ # TypeScript *.tsbuildinfo -target \ No newline at end of file +target + +issue.md \ No newline at end of file diff --git a/package.json b/package.json index a85cc22..8c0dba3 100644 --- a/package.json +++ b/package.json @@ -38,5 +38,6 @@ "turbo": "^1.13.4", "typescript": "^5.9.3", "typescript-eslint": "^8.56.1" - } + }, + "packageManager": "pnpm@10.30.2+sha512.36cdc707e7b7940a988c9c1ecf88d084f8514b5c3f085f53a2e244c2921d3b2545bc20dd4ebe1fc245feec463bb298aecea7a63ed1f7680b877dc6379d8d0cb4" } diff --git a/packages/anchor-service/dist/index.js b/packages/anchor-service/dist/index.js index 3918c74..73b9ec4 100644 --- a/packages/anchor-service/dist/index.js +++ b/packages/anchor-service/dist/index.js @@ -1 +1,77 @@ "use strict"; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// src/index.ts +var index_exports = {}; +__export(index_exports, { + TransactionType: () => TransactionType, + calculateAnchorFee: () => calculateAnchorFee +}); +module.exports = __toCommonJS(index_exports); +var TransactionType = /* @__PURE__ */ ((TransactionType2) => { + TransactionType2["DEPOSIT"] = "deposit"; + TransactionType2["WITHDRAWAL"] = "withdrawal"; + TransactionType2["TRANSFER"] = "transfer"; + return TransactionType2; +})(TransactionType || {}); +var FEE_SCHEDULES = { + USDC: { + ["deposit" /* DEPOSIT */]: { flatFee: 0.5, percentageFee: 1e-3 }, + ["withdrawal" /* WITHDRAWAL */]: { flatFee: 1, percentageFee: 2e-3 }, + ["transfer" /* TRANSFER */]: { flatFee: 0.25, percentageFee: 5e-4 } + }, + XLM: { + ["deposit" /* DEPOSIT */]: { flatFee: 0.01, percentageFee: 5e-4 }, + ["withdrawal" /* WITHDRAWAL */]: { flatFee: 0.05, percentageFee: 1e-3 }, + ["transfer" /* TRANSFER */]: { flatFee: 0.01, percentageFee: 5e-4 } + } +}; +var DEFAULT_FEE_SCHEDULE = { + flatFee: 1, + percentageFee: 5e-3 +}; +function toFixed(value, decimals = 7) { + return value.toFixed(decimals); +} +async function calculateAnchorFee(amount, asset, type) { + const parsedAmount = parseFloat(amount); + if (isNaN(parsedAmount) || parsedAmount < 0) { + throw new Error(`Invalid amount: ${amount}`); + } + const assetSchedules = FEE_SCHEDULES[asset.toUpperCase()]; + const schedule = (assetSchedules && assetSchedules[type]) ?? DEFAULT_FEE_SCHEDULE; + const flatFee = schedule.flatFee; + const percentageFee = parsedAmount * schedule.percentageFee; + const totalFee = flatFee + percentageFee; + const netAmount = Math.max(0, parsedAmount - totalFee); + return { + asset, + transactionType: type, + inputAmount: toFixed(parsedAmount), + flatFee: toFixed(flatFee), + percentageFee: toFixed(percentageFee), + totalFee: toFixed(totalFee), + netAmount: toFixed(netAmount) + }; +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + TransactionType, + calculateAnchorFee +}); diff --git a/packages/anchor-service/dist/index.mjs b/packages/anchor-service/dist/index.mjs index e69de29..17e51be 100644 --- a/packages/anchor-service/dist/index.mjs +++ b/packages/anchor-service/dist/index.mjs @@ -0,0 +1,51 @@ +// src/index.ts +var TransactionType = /* @__PURE__ */ ((TransactionType2) => { + TransactionType2["DEPOSIT"] = "deposit"; + TransactionType2["WITHDRAWAL"] = "withdrawal"; + TransactionType2["TRANSFER"] = "transfer"; + return TransactionType2; +})(TransactionType || {}); +var FEE_SCHEDULES = { + USDC: { + ["deposit" /* DEPOSIT */]: { flatFee: 0.5, percentageFee: 1e-3 }, + ["withdrawal" /* WITHDRAWAL */]: { flatFee: 1, percentageFee: 2e-3 }, + ["transfer" /* TRANSFER */]: { flatFee: 0.25, percentageFee: 5e-4 } + }, + XLM: { + ["deposit" /* DEPOSIT */]: { flatFee: 0.01, percentageFee: 5e-4 }, + ["withdrawal" /* WITHDRAWAL */]: { flatFee: 0.05, percentageFee: 1e-3 }, + ["transfer" /* TRANSFER */]: { flatFee: 0.01, percentageFee: 5e-4 } + } +}; +var DEFAULT_FEE_SCHEDULE = { + flatFee: 1, + percentageFee: 5e-3 +}; +function toFixed(value, decimals = 7) { + return value.toFixed(decimals); +} +async function calculateAnchorFee(amount, asset, type) { + const parsedAmount = parseFloat(amount); + if (isNaN(parsedAmount) || parsedAmount < 0) { + throw new Error(`Invalid amount: ${amount}`); + } + const assetSchedules = FEE_SCHEDULES[asset.toUpperCase()]; + const schedule = (assetSchedules && assetSchedules[type]) ?? DEFAULT_FEE_SCHEDULE; + const flatFee = schedule.flatFee; + const percentageFee = parsedAmount * schedule.percentageFee; + const totalFee = flatFee + percentageFee; + const netAmount = Math.max(0, parsedAmount - totalFee); + return { + asset, + transactionType: type, + inputAmount: toFixed(parsedAmount), + flatFee: toFixed(flatFee), + percentageFee: toFixed(percentageFee), + totalFee: toFixed(totalFee), + netAmount: toFixed(netAmount) + }; +} +export { + TransactionType, + calculateAnchorFee +}; diff --git a/packages/anchor-service/src/index.ts b/packages/anchor-service/src/index.ts index e69de29..38e92f0 100644 --- a/packages/anchor-service/src/index.ts +++ b/packages/anchor-service/src/index.ts @@ -0,0 +1,73 @@ +export enum TransactionType { + DEPOSIT = 'deposit', + WITHDRAWAL = 'withdrawal', + TRANSFER = 'transfer', +} + +export interface FeeQuote { + asset: string; + transactionType: TransactionType; + inputAmount: string; + flatFee: string; + percentageFee: string; + totalFee: string; + netAmount: string; +} + +interface FeeSchedule { + flatFee: number; + percentageFee: number; // e.g. 0.01 = 1% +} + +type AssetFeeSchedules = Record>>; + +const FEE_SCHEDULES: AssetFeeSchedules = { + USDC: { + [TransactionType.DEPOSIT]: { flatFee: 0.5, percentageFee: 0.001 }, + [TransactionType.WITHDRAWAL]: { flatFee: 1.0, percentageFee: 0.002 }, + [TransactionType.TRANSFER]: { flatFee: 0.25, percentageFee: 0.0005 }, + }, + XLM: { + [TransactionType.DEPOSIT]: { flatFee: 0.01, percentageFee: 0.0005 }, + [TransactionType.WITHDRAWAL]: { flatFee: 0.05, percentageFee: 0.001 }, + [TransactionType.TRANSFER]: { flatFee: 0.01, percentageFee: 0.0005 }, + }, +}; + +const DEFAULT_FEE_SCHEDULE: FeeSchedule = { + flatFee: 1.0, + percentageFee: 0.005, +}; + +function toFixed(value: number, decimals = 7): string { + return value.toFixed(decimals); +} + +export async function calculateAnchorFee( + amount: string, + asset: string, + type: TransactionType, +): Promise { + const parsedAmount = parseFloat(amount); + if (isNaN(parsedAmount) || parsedAmount < 0) { + throw new Error(`Invalid amount: ${amount}`); + } + + const assetSchedules = FEE_SCHEDULES[asset.toUpperCase()]; + const schedule: FeeSchedule = (assetSchedules && assetSchedules[type]) ?? DEFAULT_FEE_SCHEDULE; + + const flatFee = schedule.flatFee; + const percentageFee = parsedAmount * schedule.percentageFee; + const totalFee = flatFee + percentageFee; + const netAmount = Math.max(0, parsedAmount - totalFee); + + return { + asset, + transactionType: type, + inputAmount: toFixed(parsedAmount), + flatFee: toFixed(flatFee), + percentageFee: toFixed(percentageFee), + totalFee: toFixed(totalFee), + netAmount: toFixed(netAmount), + }; +}