UNPKG

@zebec-network/evm-card-sdk

Version:
628 lines (627 loc) 27.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ZebecCardService = void 0; const bignumber_js_1 = __importDefault(require("bignumber.js")); const ethers_1 = require("ethers"); const core_utils_1 = require("@zebec-network/core-utils"); const artifacts_1 = require("./artifacts"); const constants_1 = require("./constants"); /** * A class which holds methods and properties to interact with Zebec Instanct Card evm contracts. * @example * * const signer = <ethers.Signer Instance> // most wallet provider have way to create signer * const chainId = 11155111 // sepolia; * const service = new ZebecCardService(signer, chainId); * */ class ZebecCardService { /** * Create instance of ZebecCardService. * @param signer ethers signer * @param chainId chain ID supported by sdk */ constructor(signer, chainId) { this.signer = signer; this.chainId = chainId; const chain = (0, constants_1.parseSupportedChain)(chainId); const zebecCardAddress = constants_1.ZEBEC_CARD_ADDRESS[chain]; const usdcAddress = constants_1.USDC_ADDRESS[chain]; const wethAddress = constants_1.WETH_ADDRESS[chain]; this.zebecCard = constants_1.ODYSSEY_CHAIN_IDS.includes(chainId) ? artifacts_1.OdysseyZebecCard__factory.connect(zebecCardAddress, signer) : artifacts_1.ZebecCard__factory.connect(zebecCardAddress, signer); this.usdcToken = artifacts_1.Token__factory.connect(usdcAddress, signer); this.weth = artifacts_1.Weth__factory.connect(wethAddress, signer); } /** * Sets Native Fee in card config. * * Can only be invoked admin. * * @param params * @returns */ async setNativeFee(params) { const feeInBps = BigInt((0, core_utils_1.percentToBps)(params.feeInPercent)); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.setNativeFee(feeInBps, overrides); } /** * Sets NonNative Fee in card config * * Can only be invoked admin. * * @param params * @returns */ async setNonNativeFee(params) { const feeInBps = BigInt((0, core_utils_1.percentToBps)(params.feeInPercent)); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.setNonNativeFee(feeInBps, overrides); } /** * Sets Revenue Fee in card config * * Can only be invoked admin. * * @param params * @returns */ async setRevenueFee(params) { const feeInBps = BigInt((0, core_utils_1.percentToBps)(params.feeInPercent)); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.setRevenueFee(feeInBps, overrides); } /** * Sets Revenue vault address in card config * * Can only be invoked admin. * * @param params * @returns */ async setRevenueVault(params) { const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.setRevenueVault(params.vaultAddress, overrides); } /** * Sets commission vault address in card config * * Can only be invoked admin. * * @param params * @returns */ async setCommissionVault(params) { const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, }; return this.zebecCard.setComissionVault(params.vaultAddress, overrides); } /** * Sets card vault address in card config * * Can only be invoked admin. * */ async setCardVault(params) { const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.setCardVault(params.vaultAddress, overrides); } /** * Sets usdc address in card config * Can only be invoked by admin */ async setUsdcAddress(params) { const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.setUsdcAddress(params.tokenAddress, overrides); } /** * Sets minimum card amount for purchasing card in card config */ async setMinCardAmount(params) { const decimals = await this.usdcToken.decimals(); const minCardAmount = ethers_1.ethers.parseUnits(params.minCardAmount, decimals); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.setMinCardAmount(minCardAmount, overrides); } /** * Sets maximum card amount for purchasing card in card config */ async setMaxCardAmount(params) { const decimals = await this.usdcToken.decimals(); const maxCardAmount = ethers_1.ethers.parseUnits(params.maxCardAmount, decimals); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.setMaxCardAmount(maxCardAmount, overrides); } /** * Sets daily card purchase limit in card config */ async setDailyCardPurchaseLimit(params) { const decimals = await this.usdcToken.decimals(); const dailyCardPurchaseLimit = ethers_1.ethers.parseUnits(params.dailyCardPurchaseLimit, decimals); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.setDailyCardBuyLimit(dailyCardPurchaseLimit, overrides); } /** * Updates fee for given min - max (range) amount and inserts if range in not found. */ async setFee(params) { const decimals = await this.usdcToken.decimals(); const minAmount = ethers_1.ethers.parseUnits(params.minAmount, decimals); const maxAmount = ethers_1.ethers.parseUnits(params.maxAmount, decimals); const fee = (0, core_utils_1.percentToBps)(params.feePercent); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.setFee(minAmount, maxAmount, fee, overrides); } /** * Sets fee tiers only be invoked by admin */ async setFeeTiers(params) { const parsedFeeTiers = await this._parseFeeTiers(params.feeTiers); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.setFeeArray(parsedFeeTiers, overrides); } async _parseFeeTiers(feeTiers) { const decimals = await this.usdcToken.decimals(); return feeTiers.map((feeTier) => { return { fee: (0, core_utils_1.percentToBps)(feeTier.feePercent), minAmount: ethers_1.ethers.parseUnits(feeTier.minAmount, decimals), maxAmount: ethers_1.ethers.parseUnits(feeTier.maxAmount, decimals), }; }); } async setCustomFee(params) { const fee = (0, core_utils_1.percentToBps)(params.fee.toString()); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.setCustomTokenFee(params.tokenAddress, fee, overrides); } async getCustomFee(params) { const fee = await this.zebecCard.getCustomTokenFee(params.tokenAddress); return (0, core_utils_1.bpsToPercent)(fee.toString()); } async setReloadableFee(params) { const fee = (0, core_utils_1.percentToBps)(params.fee.toString()); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.setReloadableFee(fee, overrides); } /** * Deposits usdc to user vault * @param params * @returns */ async depositUsdc(params) { if (constants_1.ODYSSEY_CHAIN_IDS.includes(this.chainId)) { throw new Error("Method not supported for this chain"); } const decimals = await this.usdcToken.decimals(); const parsedAmount = ethers_1.ethers.parseUnits(params.amount, decimals); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.depositUsdc(parsedAmount, overrides); } /** * Withdraw usdc from user vault * @param params * @returns */ async withdraw(params) { if (constants_1.ODYSSEY_CHAIN_IDS.includes(this.chainId)) { throw new Error("Method not supported for this chain"); } const decimals = await this.usdcToken.decimals(); const parsedAmount = ethers_1.ethers.parseUnits(params.amount, decimals); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.withdraw(parsedAmount, overrides); } /** * Transfer specified amount from user's vault balance to card vault with some fee amount for card purchase. * @param params * @returns */ async buyCard(params) { if (constants_1.ODYSSEY_CHAIN_IDS.includes(this.chainId)) { throw new Error("Method not supported for this chain"); } const decimals = await this.usdcToken.decimals(); const parsedAmount = ethers_1.ethers.parseUnits(params.amount, decimals); if (!(0, core_utils_1.isEmailValid)(params.buyerEmail)) { throw new Error("Invalid email: " + params.buyerEmail); } const vaultBalance = await this.zebecCard.cardBalances(this.signer); if (parsedAmount > vaultBalance) { throw new Error("Not enough balance. Vault balance: " + ethers_1.ethers.formatUnits(vaultBalance, decimals) + " Requested amount: " + params.amount); } const cardConfig = await this.zebecCard.cardConfig(); const minRange = cardConfig.minCardAmount; const maxRange = cardConfig.maxCardAmount; if (parsedAmount < minRange || parsedAmount > maxRange) { throw new Error("Amount must be with range: " + ethers_1.ethers.formatUnits(minRange, decimals) + " - " + ethers_1.ethers.formatUnits(maxRange, decimals)); } const cardPurchaseInfo = await this.zebecCard.cardPurchases(this.signer); const lastCardPurchaseDate = new Date(Number(cardPurchaseInfo.unixInRecord * 1000n)); const today = new Date(); let cardPurchaseOfDay = 0n; if ((0, core_utils_1.areDatesOfSameDay)(today, lastCardPurchaseDate)) { cardPurchaseOfDay = cardPurchaseInfo.totalCardBoughtPerDay + parsedAmount; } else { cardPurchaseOfDay = parsedAmount; } if (cardPurchaseOfDay > cardConfig.dailyCardBuyLimit) { throw new Error("Requested card purchase amount exceeds daily purchase limit. Daily limit: " + ethers_1.ethers.formatUnits(cardConfig.dailyCardBuyLimit, decimals) + " Today's purchase amount: " + ethers_1.ethers.formatUnits(cardPurchaseInfo.totalCardBoughtPerDay, decimals)); } const emailHash = await (0, core_utils_1.hashSHA256)(params.buyerEmail); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.buyCard(parsedAmount, params.cardType, emailHash, overrides); } /** * Swaps given src token to usdc and transfers to user's vault * @param params * @param overrides * @returns */ async swapAndDeposit(params) { if (constants_1.ODYSSEY_CHAIN_IDS.includes(this.chainId)) { throw new Error("Method not supported for this chain"); } const { swapParams, ether } = params.swapData; const srcToken = artifacts_1.Token__factory.connect(swapParams.description.srcToken, this.signer); const dstToken = artifacts_1.Token__factory.connect(swapParams.description.dstToken, this.signer); const srcTokenDecimals = await srcToken.decimals(); const dstTokenDecimals = await dstToken.decimals(); const executor = swapParams.executor; const description = { srcToken: swapParams.description.srcToken, dstToken: swapParams.description.dstToken, srcReceiver: swapParams.description.srcReceiver, dstReceiver: swapParams.description.dstReceiver, amount: ethers_1.ethers.parseUnits(swapParams.description.srcAmount, srcTokenDecimals), minReturnAmount: ethers_1.ethers.parseUnits(swapParams.description.minReturnAmount, dstTokenDecimals), flags: BigInt(swapParams.description.flags), }; const routeData = swapParams.routeData; const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.swapAndDeposit(executor, description, routeData, { value: ethers_1.ethers.parseEther(ether), ...overrides, }); } async buyCardDirect(params) { const decimals = await this.usdcToken.decimals(); const parsedAmount = ethers_1.ethers.parseUnits(params.amount, decimals); if (!(0, core_utils_1.isEmailValid)(params.buyerEmail)) { throw new Error("Invalid email: " + params.buyerEmail); } const cardConfig = await this.zebecCard.cardConfig(); const minRange = cardConfig.minCardAmount; const maxRange = cardConfig.maxCardAmount; if (parsedAmount < minRange || parsedAmount > maxRange) { throw new Error("Amount must be with range: " + ethers_1.ethers.formatUnits(minRange, decimals) + " - " + ethers_1.ethers.formatUnits(maxRange, decimals)); } const cardPurchaseInfo = await this.zebecCard.cardPurchases(this.signer); const lastCardPurchaseDate = new Date(Number(cardPurchaseInfo.unixInRecord * 1000n)); const today = new Date(); let cardPurchaseOfDay = 0n; if ((0, core_utils_1.areDatesOfSameDay)(today, lastCardPurchaseDate)) { cardPurchaseOfDay = cardPurchaseInfo.totalCardBoughtPerDay + parsedAmount; } else { cardPurchaseOfDay = parsedAmount; } if (cardPurchaseOfDay > cardConfig.dailyCardBuyLimit) { throw new Error("Requested card purchase amount exceeds daily purchase limit. Daily limit: " + ethers_1.ethers.formatUnits(cardConfig.dailyCardBuyLimit, decimals) + " Today's purchase amount: " + ethers_1.ethers.formatUnits(cardPurchaseInfo.totalCardBoughtPerDay, decimals)); } const emailHash = await (0, core_utils_1.hashSHA256)(params.buyerEmail); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; if (constants_1.ODYSSEY_CHAIN_IDS.includes(this.chainId)) { return this.zebecCard.buyCardDirect(parsedAmount, params.cardType === "carbon" ? "reloadable" : "non_reloadable", emailHash, overrides); } else { return this.zebecCard.buyCardDirect(parsedAmount, params.cardType === "carbon" ? "reloadable" : "non_reloadable", emailHash, overrides); } } async swapAndBuyCardDirect(params) { if (constants_1.ODYSSEY_CHAIN_IDS.includes(this.chainId)) { throw new Error("Method not supported for this chain"); } const { buyerEmail, cardType, swapData: { swapParams, ether }, } = params; const srcToken = artifacts_1.Token__factory.connect(swapParams.description.srcToken, this.signer); const dstToken = artifacts_1.Token__factory.connect(swapParams.description.dstToken, this.signer); const srcTokenDecimals = await srcToken.decimals(); const dstTokenDecimals = await dstToken.decimals(); const executor = swapParams.executor; const amount = ethers_1.ethers.parseUnits(swapParams.description.srcAmount, srcTokenDecimals); const minReturnAmount = ethers_1.ethers.parseUnits(swapParams.description.minReturnAmount, dstTokenDecimals); const description = { srcToken: swapParams.description.srcToken, dstToken: swapParams.description.dstToken, srcReceiver: swapParams.description.srcReceiver, dstReceiver: swapParams.description.dstReceiver, amount, minReturnAmount, flags: BigInt(swapParams.description.flags), }; const routeData = swapParams.routeData; const cardConfig = await this.zebecCard.cardConfig(); const minRange = cardConfig.minCardAmount; const maxRange = cardConfig.maxCardAmount; const fee = await this.zebecCard.getCustomTokenFee(swapParams.description.srcToken); const feeAmount = (0, bignumber_js_1.default)(minReturnAmount.toString()).times((0, bignumber_js_1.default)(fee.toString()).div(10000)); const amountAfterFeeDeduction = BigInt((0, bignumber_js_1.default)(minReturnAmount.toString()).minus(feeAmount).toFixed(0, bignumber_js_1.default.ROUND_DOWN)); if (amountAfterFeeDeduction < minRange || amountAfterFeeDeduction > maxRange) { throw new Error("Amount must be with range: " + ethers_1.ethers.formatUnits(minRange, dstTokenDecimals) + " - " + ethers_1.ethers.formatUnits(maxRange, dstTokenDecimals)); } const cardPurchaseInfo = await this.zebecCard.cardPurchases(this.signer); const lastCardPurchaseDate = new Date(Number(cardPurchaseInfo.unixInRecord * 1000n)); const today = new Date(); let cardPurchaseOfDay = 0n; if ((0, core_utils_1.areDatesOfSameDay)(today, lastCardPurchaseDate)) { cardPurchaseOfDay = cardPurchaseInfo.totalCardBoughtPerDay + amountAfterFeeDeduction; } else { cardPurchaseOfDay = amountAfterFeeDeduction; } if (cardPurchaseOfDay > cardConfig.dailyCardBuyLimit) { throw new Error("Requested card purchase amount exceeds daily purchase limit. Daily limit: " + ethers_1.ethers.formatUnits(cardConfig.dailyCardBuyLimit, dstTokenDecimals) + " Today's purchase amount will be: " + ethers_1.ethers.formatUnits(cardPurchaseOfDay, dstTokenDecimals)); } const emailHash = await (0, core_utils_1.hashSHA256)(buyerEmail); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.swapAndBuy(executor, description, routeData, cardType === "carbon" ? "reloadable" : "non_reloadable", emailHash, { value: ethers_1.ethers.parseEther(ether), ...overrides, }); } async swapAndBuyCardOdyssey(params) { const swapEtherAmount = ethers_1.ethers.parseEther(params.ether); const minAmount = await this.zebecCard.getMinimumUSDCAmount(swapEtherAmount, params.slippage); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.swapAndBuy(params.cardType === "carbon" ? "reloadable" : "non_reloadable", params.buyerEmail, minAmount, { value: swapEtherAmount, ...overrides, }); } async getReloadableFee() { const fee = await this.zebecCard.getReloadableFee(); return (0, core_utils_1.bpsToPercent)(fee.toString()); } /** * Deposit usdc from user's vault to yield provider * @param params * @returns */ async generateYield(params) { if (constants_1.ODYSSEY_CHAIN_IDS.includes(this.chainId)) { throw new Error("Method not supported for this chain"); } const decimals = await this.usdcToken.decimals(); const parsedAmount = ethers_1.ethers.parseUnits(params.amount, decimals); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.generateYield(parsedAmount, overrides); } /** * Gets minimum usdc amount for given ether amount * @param etherAmount * @param slippage * @returns */ async getMinimumUsdcAmount(etherAmount, slippage) { const parsedEtherAmount = ethers_1.ethers.parseEther(etherAmount); const minAmount = await this.zebecCard.getMinimumUSDCAmount(parsedEtherAmount, slippage); return ethers_1.ethers.formatUnits(minAmount, BigInt(6)); } /** * Withdaw deposits and yield from yield provider * @param params * @returns */ async withdrawYield(params) { if (constants_1.ODYSSEY_CHAIN_IDS.includes(this.chainId)) { throw new Error("Method not supported for this chain"); } const decimals = await this.usdcToken.decimals(); const parsedAmount = ethers_1.ethers.parseUnits(params.amount, decimals); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.zebecCard.withdrawYield(parsedAmount, overrides); } /** * Gets user's vault balance * @param params * @returns */ async getUserBalance(params) { const decimals = await this.usdcToken.decimals(); const cardBalance = await this.zebecCard.cardBalances(params.userAddress); const formattedBalance = ethers_1.ethers.formatUnits(cardBalance, decimals); return formattedBalance; } /** * Gets user's card purchase * @param params * @returns */ async getCardPurhcaseOfDay(params) { const decimals = await this.usdcToken.decimals(); const cardPurchase = await this.zebecCard.cardPurchases(params.userAddress); const totalCardPurchased = ethers_1.ethers.formatUnits(cardPurchase.totalCardBoughtPerDay, decimals); const cardPurchasedTimestamp = Number(cardPurchase.unixInRecord.toString()); return { totalCardPurchased, cardPurchasedTimestamp, }; } /** * Gets Zebec Instant Card contract configs * @returns */ async getCardConfig() { const cardConfig = await this.zebecCard.cardConfig(); const nativeFeePercent = (0, core_utils_1.bpsToPercent)(cardConfig.nativeFee.toString()); const nonNativeFeePercent = (0, core_utils_1.bpsToPercent)(cardConfig.nonNativeFee.toString()); const revenueFeePercent = (0, core_utils_1.bpsToPercent)(cardConfig.revenueFee.toString()); const decimals = await this.usdcToken.decimals(); const minCardAmount = ethers_1.ethers.formatUnits(cardConfig.minCardAmount, decimals); const maxCardAmount = ethers_1.ethers.formatUnits(cardConfig.maxCardAmount, decimals); const dailyCardPurchaseLimit = ethers_1.ethers.formatUnits(cardConfig.dailyCardBuyLimit, decimals); return { cardVault: cardConfig.cardVault, commissionVault: cardConfig.commissionVault, revenueVault: cardConfig.revenueVault, nativeFeePercent, nonNativeFeePercent, revenueFeePercent, totalCardSold: cardConfig.counter, usdcAddress: cardConfig.usdcAddress, maxCardAmount, minCardAmount, dailyCardPurchaseLimit, }; } /** * Gets fee tiers * @returns Array of fee tier */ async getFeeTiers() { const decimals = await this.usdcToken.decimals(); const feeTiers = await this.zebecCard.getFeeTiers(); return feeTiers.map((feeTier) => { return { feePercent: (0, core_utils_1.bpsToPercent)(feeTier.fee.toString()), maxAmount: ethers_1.ethers.formatUnits(feeTier.maxAmount, decimals), minAmount: ethers_1.ethers.formatUnits(feeTier.minAmount, decimals), }; }); } /** * Gets admin adddress * @returns */ async getAdmin() { return this.zebecCard.owner(); } /** * add allowance of given amount of given token to given spender * @param params * @returns */ async approve(params) { const token = artifacts_1.Token__factory.connect(params.token, this.signer); const decimals = await token.decimals(); const parsedAmount = ethers_1.ethers.parseUnits(params.amount, decimals); const allowance = await token.allowance(this.signer, params.spender); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; if (allowance < parsedAmount) { return await token.approve(params.spender, parsedAmount, overrides); } return null; } /** * Wrap ETH to Wrapped ETH * @param param * @returns */ async wrapEth(params) { const parsedAmount = ethers_1.ethers.parseEther(params.amount); const overrides = { ...params.overrides, gasLimit: params.overrides?.gasLimit || constants_1.DEFAULT_GAS_LIMIT, // Default }; return this.weth.deposit({ value: parsedAmount, ...overrides }); } } exports.ZebecCardService = ZebecCardService;