@zebec-network/exchange-card-sdk
Version:
An sdk for purchasing silver card in zebec
219 lines (218 loc) • 9.86 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AlgorandService = void 0;
const algosdk_1 = __importDefault(require("algosdk"));
const algokit_utils_1 = require("@algorandfoundation/algokit-utils");
const client_manager_1 = require("@algorandfoundation/algokit-utils/types/client-manager");
const apiHelpers_1 = require("../helpers/apiHelpers");
const utils_1 = require("../utils");
class AlgorandService {
wallet;
apiConfig;
algodClient;
algorandClient;
apiService;
network;
constructor(wallet, apiConfig, sdkOptions) {
this.wallet = wallet;
this.apiConfig = apiConfig;
this.network = sdkOptions?.sandbox ? "testnet" : "mainnet";
this.algodClient = client_manager_1.ClientManager.getAlgodClient(client_manager_1.ClientManager.getAlgoNodeConfig(this.network, "algod"));
this.algorandClient = algokit_utils_1.AlgorandClient.fromClients({
algod: this.algodClient,
});
this.apiService = new apiHelpers_1.ZebecCardAPIService(apiConfig, sdkOptions?.sandbox || false);
}
/**
* Fetches a quote for Bitcoin transfer.
*
* @returns {Promise<Quote>} A promise that resolves to a Quote object.
*/
async fetchQuote(symbol = "ALGO") {
const res = await this.apiService.fetchQuote(symbol);
return res;
}
/**
* Fetches the Bitcoin vault address.
*
* @returns {Promise<{ address: string }>} A promise that resolves to the vault address.
*/
async fetchVault(symbol = "ALGO") {
const data = await this.apiService.fetchVault(symbol);
return data;
}
/**
* Transfer Algorand currency from one wallet to another
* @param config Transfer configuration
* @returns Transaction ID if successful
*/
async transferAlgo(config) {
try {
const parsedAmount = (0, utils_1.parseAlgo)(config.amount);
// Check if sender has sufficient balance
const senderBalance = await this.getAccountBalanceInMicroAlgo(this.wallet.address);
const minBalance = (0, utils_1.parseAlgo)(0.1); // Minimum account balance
if (senderBalance < parsedAmount + minBalance) {
throw new Error(`Insufficient balance. Need ${(0, utils_1.formatAlgo)(parsedAmount + minBalance)} ALGO, have ${(0, utils_1.formatAlgo)(senderBalance)} ALGO`);
}
const vault = await this.fetchVault("ALGO");
const recipientAddress = vault.address;
// Validate recipient address
if (!algosdk_1.default.isValidAddress(recipientAddress)) {
throw new Error("Invalid recipient address");
}
// Get suggested transaction parameters
const suggestedParams = await this.algodClient.getTransactionParams().do();
// Create payment transaction
const paymentTxn = algosdk_1.default.makePaymentTxnWithSuggestedParamsFromObject({
sender: this.wallet.address,
receiver: recipientAddress,
amount: parsedAmount,
note: config.note ? new Uint8Array(Buffer.from(config.note)) : undefined,
suggestedParams: suggestedParams,
});
// Sign the transaction
const txId = await this.wallet.signAndSendTransaction(paymentTxn);
return txId;
}
catch (error) {
console.error("Transfer failed:", error);
throw error;
}
}
/**
* Transfer USDC (ASA token) from wallet to vault
* @param config USDC transfer configuration
* @returns Transaction ID if successful
*/
async transferAsset(config) {
try {
const assetDecimals = await (0, utils_1.getAssetDecimals)(this.algodClient, config.assetId);
// const usdcConfig = USDC_ASSET_CONFIG[this.network];
const parsedAmount = (0, utils_1.parseAlgorandAsset)(config.amount, assetDecimals);
// Check if sender has sufficient USDC balance
const senderAssetBalance = await this.getAssetBalanceInMicroUnit(this.wallet.address, config.assetId);
if (senderAssetBalance < parsedAmount) {
throw new Error(`Insufficient Asset balance. Need ${(0, utils_1.formatAlgorandAsset)(parsedAmount, assetDecimals)} Asset, have ${(0, utils_1.formatAlgorandAsset)(senderAssetBalance, assetDecimals)} Asset`);
}
// Check if sender has sufficient ALGO for transaction fees
const senderAlgoBalance = await this.getAccountBalanceInMicroAlgo(this.wallet.address);
const minAlgoForFees = (0, utils_1.parseAlgo)(0.002); // Minimum ALGO for transaction fees
if (senderAlgoBalance < minAlgoForFees) {
throw new Error(`Insufficient ALGO for transaction fees. Need at least ${(0, utils_1.formatAlgo)(minAlgoForFees)} ALGO for fees`);
}
const vault = await this.fetchVault("ALGO-USDC");
const recipientAddress = vault.address;
// Validate recipient address
if (!algosdk_1.default.isValidAddress(recipientAddress)) {
throw new Error("Invalid recipient address");
}
// // Check if recipient is opted into USDC asset
const recipientOptedIn = await this.isOptedIntoAsset(recipientAddress, config.assetId);
if (!recipientOptedIn) {
throw new Error("Recipient address is not opted into USDC asset");
}
// Get suggested transaction parameters
const suggestedParams = await this.algodClient.getTransactionParams().do();
// Create asset transfer transaction
const assetTransferTxn = algosdk_1.default.makeAssetTransferTxnWithSuggestedParamsFromObject({
sender: this.wallet.address,
receiver: recipientAddress,
amount: parsedAmount,
assetIndex: config.assetId,
note: config.note ? new Uint8Array(Buffer.from(config.note)) : undefined,
suggestedParams: suggestedParams,
});
// Sign and send the transaction
const txId = await this.wallet.signAndSendTransaction(assetTransferTxn);
return txId;
}
catch (error) {
console.error("Asset transfer failed:", error);
throw error;
}
}
/**
* Check if an account is opted into a specific asset
* @param address Account address
* @param assetId Asset ID to check
* @returns Whether the account is opted into the asset
*/
async isOptedIntoAsset(address, assetId) {
try {
const accountInfo = await this.algodClient.accountInformation(address).do();
return accountInfo.assets?.some((asset) => asset.assetId === BigInt(assetId)) || false;
}
catch (error) {
console.error("Error checking asset opt-in status:", error);
return false;
}
}
/**
* Get asset balance for a specific account in microAsset (base units)
* @param address Account address
* @param assetId Asset ID
* @returns Asset balance in base units
*/
async getAssetBalanceInMicroUnit(walletAddress, assetId) {
try {
const accountInfo = await this.algodClient.accountInformation(walletAddress).do();
const asset = accountInfo.assets?.find((asset) => asset.assetId === BigInt(assetId));
return asset ? BigInt(asset.amount) : BigInt(0);
}
catch (error) {
console.error("Error fetching asset balance:", error);
return BigInt(0);
}
}
async getAssetBalance(walletAddress, assetId) {
const balance = await this.getAssetBalanceInMicroUnit(walletAddress, assetId);
const decimals = await (0, utils_1.getAssetDecimals)(this.algodClient, assetId);
return (0, utils_1.formatAlgorandAsset)(balance, decimals);
}
async getAssetsBalance(walletAddress, assetIds) {
const map = new Map(Array.from(assetIds.map((id) => [id, "0"])));
try {
const accountInfo = await this.algodClient.accountInformation(walletAddress).do();
const assets = accountInfo.assets;
if (!assets) {
return map;
}
await Promise.all(assetIds.map(async (id) => {
const asset = assets.find((asset) => asset.assetId === BigInt(id));
if (asset) {
const decimals = await (0, utils_1.getAssetDecimals)(this.algodClient, id);
const amount = (0, utils_1.formatAlgorandAsset)(asset.amount, decimals);
map.set(id, amount);
}
}));
return map;
}
catch (error) {
console.error("Error fetching asset balance:", error);
}
return map;
}
/**
* Get account balance in Algos
* @param address Account address
* @returns Balance in ALGO
*/
async getAccountBalance(address) {
const amount = await this.getAccountBalanceInMicroAlgo(address);
return (0, utils_1.formatAlgo)(amount);
}
/**
* Get account balance in microAlgos (for internal calculations)
* @param address Account address
* @returns Balance in microAlgos
*/
async getAccountBalanceInMicroAlgo(address) {
const accountInfo = await this.algodClient.accountInformation(address).do();
return accountInfo.amount;
}
}
exports.AlgorandService = AlgorandService;