@molecularlabs/nucleus-frontend
Version:
Nucleus BoringVault Frontend SDK
180 lines • 6.11 kB
JavaScript
import { erc20Abi, parseUnits } from "viem";
import { getRateInQuoteWithAssetDecimals } from "../../api/accountant";
import { getErc20Decimals } from "../../api/erc20";
import { toChainId } from "../../api/vault-config";
import {
DEFAULT_APPROVAL_AMOUNT,
DEFAULT_DEPOSIT_SLIPPAGE
} from "../../constants";
import { TellerAbi } from "../../contracts/teller-abi";
import { tryCatch } from "../../utils/try-catch";
import { prepareBridgeContractArg } from "../bridge";
import { getVaultByKey } from "../index";
import { calculateMinimumMint } from "./utils";
const prepareDepositTransactionData = async ({
vaultKey,
depositTokenSymbol,
depositAmount,
chainId,
slippage = DEFAULT_DEPOSIT_SLIPPAGE
}) => {
try {
const normalizedChainId = toChainId(chainId);
const vault = await getVaultByKey(vaultKey);
const depositAssetAddress = vault.deposit.sourceChains[normalizedChainId].depositTokens[depositTokenSymbol].address;
if (!vault) {
throw new Error(`Invalid vault key: ${vaultKey}`);
}
if (!depositAssetAddress) {
throw new Error(
`Couldn't find address for ${depositTokenSymbol} on ${chainId}`
);
}
if (!vault.contracts) {
throw new Error(`Contracts not configured for vault ${vaultKey}`);
}
if (!vault.contracts.teller) {
throw new Error(`Teller contract not configured for vault ${vaultKey}`);
}
const [depositAssetDecimals, rate] = await getRateInQuoteWithAssetDecimals({
assetAddress: depositAssetAddress,
accountantAddress: vault.contracts.accountant,
chainId: normalizedChainId
});
if (depositAssetDecimals.status === "failure") {
throw new Error(depositAssetDecimals.error.message);
}
if (rate.status === "failure") {
throw new Error(rate.error.message);
}
const depositAmountAsBitInt = parseUnits(
depositAmount,
depositAssetDecimals.result
);
const minimumMint = calculateMinimumMint(
depositAmountAsBitInt,
rate.result,
slippage
);
return {
abi: TellerAbi,
address: vault.contracts.teller,
functionName: "deposit",
args: [depositAssetAddress, depositAmountAsBitInt, minimumMint],
chainId: normalizedChainId
};
} catch (error) {
console.error(error);
throw new Error(`Failed to get rate in quote for vault ${vaultKey}`);
}
};
const prepareDepositAndBridgeTransactionData = async ({
depositAmount,
depositTokenSymbol,
destinationChainId,
slippage = DEFAULT_DEPOSIT_SLIPPAGE,
sourceChainId,
userAddress,
vaultKey
}) => {
const normalizedSourceChainId = toChainId(sourceChainId);
const normalizedDestinationChainId = toChainId(destinationChainId);
const vault = await getVaultByKey(vaultKey);
const depositAssetAddress = vault.deposit.sourceChains[normalizedSourceChainId].depositTokens[depositTokenSymbol].address;
if (!vault) {
throw new Error(`Invalid vault key: ${vaultKey}`);
}
if (!vault.contracts) {
throw new Error(`Contracts not configured for vault ${vaultKey}`);
}
if (!vault.contracts.accountant) {
throw new Error(`Accountant contract not configured for vault ${vaultKey}`);
}
const bridgeIdentifier = vault.deposit.sourceChains[normalizedSourceChainId].destinationChains[normalizedDestinationChainId].bridge.chainIdentifier;
const [depositAssetDecimals, rate] = await getRateInQuoteWithAssetDecimals({
assetAddress: depositAssetAddress,
accountantAddress: vault.contracts.accountant,
chainId: normalizedSourceChainId
});
if (depositAssetDecimals.status === "failure") {
throw new Error(depositAssetDecimals.error.message);
}
if (rate.status === "failure") {
throw new Error(rate.error.message);
}
const depositAmountAsBitInt = parseUnits(
depositAmount,
depositAssetDecimals.result
);
const minimumMint = calculateMinimumMint(
depositAmountAsBitInt,
rate.result,
slippage
);
const bridgeData = prepareBridgeContractArg({
bridgeChainIdentifier: bridgeIdentifier,
userAddress
});
return {
abi: TellerAbi,
address: vault.contracts.teller,
functionName: "depositAndBridge",
args: [depositAssetAddress, depositAmountAsBitInt, minimumMint, bridgeData],
chainId: normalizedSourceChainId,
value: BigInt(0)
// This will be updated with actual bridge fee when executing
};
};
const prepareApproveDepositToken = async ({
vaultKey,
depositTokenSymbol,
depositAmount,
chainId
}) => {
const normalizedChainId = toChainId(chainId);
const vault = await getVaultByKey(vaultKey);
if (!vault) {
throw new Error(`Invalid vault key: ${vaultKey}`);
}
if (!vault.contracts) {
throw new Error(`Contracts not configured for vault ${vaultKey}`);
}
if (!vault.contracts.boringVault) {
throw new Error(`Teller contract not configured for vault ${vaultKey}`);
}
const depositAssetAddress = vault.deposit.sourceChains[normalizedChainId].depositTokens[depositTokenSymbol].address;
if (!depositAssetAddress) {
throw new Error(`Invalid deposit token symbol: ${depositTokenSymbol}`);
}
const {
data: depositAssetDecimals,
error: depositAssetDecimalsError,
success: depositAssetDecimalsSuccess
} = await tryCatch(
getErc20Decimals({
chainId: normalizedChainId,
tokenAddress: depositAssetAddress
})
);
if (depositAssetDecimalsSuccess === false) {
throw new Error(
`Error getting deposit asset decimals. ${depositAssetDecimalsError.name}: ${depositAssetDecimalsError.message}`
);
}
if (!depositAssetDecimals) {
throw new Error(`Invalid deposit token symbol: ${depositTokenSymbol}`);
}
const depositAmountAsBitInt = depositAmount ? parseUnits(depositAmount, depositAssetDecimals) : DEFAULT_APPROVAL_AMOUNT;
return {
abi: erc20Abi,
address: depositAssetAddress,
functionName: "approve",
args: [vault.contracts.boringVault, depositAmountAsBitInt]
};
};
export {
prepareApproveDepositToken,
prepareDepositAndBridgeTransactionData,
prepareDepositTransactionData
};
//# sourceMappingURL=deposit.mjs.map