UNPKG

@funkit/connect

Version:

Funkit Connect SDK elevates DeFi apps via web2 sign-ins and one-click checkouts.

188 lines (184 loc) 6.17 kB
"use client"; // src/clients/aave.tsx import { encodeFunctionData, erc20Abi, getAddress, maxUint256 } from "viem"; import { mainnet as mainnet2 } from "viem/chains"; // src/utils/isMainnetUsdt.ts import { isTokenEquivalent } from "@funkit/utils"; import { mainnet } from "viem/chains"; var USDT_MAINNET_ADDRESS = "0xdAC17F958D2ee523a2206206994597C13D831ec7"; function isMainnetUsdt(chainId, address) { return isTokenEquivalent({ firstTokenAddress: address, firstTokenChainId: chainId.toString(), secondTokenAddress: USDT_MAINNET_ADDRESS, secondTokenChainId: mainnet.id.toString() }); } // src/clients/aave.tsx var VAULT_DEPOSITOR_BY_CHAIN_ID = { [mainnet2.id]: getAddress("0x40b72bB73B1E9380629B205e7880Fa409ae7fcc9") }; var AAVE_SUPPLY_ACTION_TYPE = "AAVE_SUPPLY"; function isAaveSupplySupported(chainId) { return chainId in VAULT_DEPOSITOR_BY_CHAIN_ID; } var AMOUNT_PLACEHOLDER = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffdeadbeefn; var AAVE_POOL_ABI = [ { name: "supply", type: "function", stateMutability: "nonpayable", inputs: [ { name: "asset", type: "address" }, { name: "amount", type: "uint256" }, { name: "onBehalfOf", type: "address" }, { name: "referralCode", type: "uint16" } ], outputs: [] } ]; var VAULT_DEPOSITOR_ABI = [ { name: "deposit", type: "function", stateMutability: "nonpayable", inputs: [ { name: "token", type: "address" }, { name: "vault", type: "address" }, { name: "callData", type: "bytes" }, { name: "minAmountOut", type: "uint256" } ], outputs: [{ name: "returnData", type: "bytes" }] } ]; function createAaveSupplyActions(config) { const { onBehalfOf, underlyingAsset, poolAddress, chainId, referralCode = 0 } = config; const vaultDepositor = VAULT_DEPOSITOR_BY_CHAIN_ID[chainId]; return async () => { if (!vaultDepositor) { throw new Error( `Aave supply is not yet supported on chain ${chainId}. Supported chain IDs: ${Object.keys(VAULT_DEPOSITOR_BY_CHAIN_ID).join(", ")}` ); } if (!onBehalfOf) { throw new Error( "Please connect your wallet before starting an Aave supply" ); } const asset = getAddress(underlyingAsset); const supplyCalldata = encodeFunctionData({ abi: AAVE_POOL_ABI, functionName: "supply", args: [asset, AMOUNT_PLACEHOLDER, onBehalfOf, referralCode] }); const needsApprovalReset = isMainnetUsdt(chainId, asset); const resetApproval = { contractAbi: erc20Abi, contractAddress: asset, functionName: "approve", functionArgs: [vaultDepositor, 0n] }; const maxApproval = { contractAbi: erc20Abi, contractAddress: asset, functionName: "approve", functionArgs: [vaultDepositor, maxUint256] }; const vaultDeposit = { contractAbi: VAULT_DEPOSITOR_ABI, contractAddress: vaultDepositor, functionName: "deposit", functionArgs: [asset, poolAddress, supplyCalldata, 0n] }; return needsApprovalReset ? [resetApproval, maxApproval, vaultDeposit] : [maxApproval, vaultDeposit]; }; } function buildSupplyModalTitleMeta(display) { const parts = []; if (display?.supplyAPY !== void 0) { parts.push(`${display.supplyAPY}% APY`); } if (display?.collateralizationEnabled !== void 0) { parts.push( `Collateralization ${display.collateralizationEnabled ? "enabled" : "disabled"}` ); } return parts.length > 0 ? parts.join(" \xB7 ") : void 0; } function createAaveSupplyCheckoutConfig(input) { const { underlyingAsset, poolAddress, chainId, walletAddress, display, referralCode, receiptToken, resolveHealthFactor } = input; if (!isAaveSupplySupported(chainId)) { return void 0; } const symbol = display?.symbol ?? "asset"; const receiptTicker = receiptToken?.symbol ?? `a${symbol}`; return { modalTitle: `Supply ${symbol}`, modalTitleMeta: buildSupplyModalTitleMeta(display), // Same integrator-provided signals as the subtitle, but structured so the // confirmation screen renders them as rows (DestinationYieldRows). No extra // fetch — one resolved snapshot, two surfaces. Left undefined when neither // signal is present so the field stays falsy (no empty-but-truthy object). destinationYieldInfo: display?.supplyAPY !== void 0 || display?.collateralizationEnabled !== void 0 ? { supplyApy: display?.supplyAPY, collateralizationEnabled: display?.collateralizationEnabled } : void 0, targetChain: chainId.toString(), targetAsset: underlyingAsset, qrcodeActionType: AAVE_SUPPLY_ACTION_TYPE, // Integrator-owned HF math (live position data); the SDK only renders it. resolveHealthFactor, targetAssetTicker: receiptTicker, checkoutItemTitle: receiptTicker, // Prefer the aToken's icon (e.g. Aave's aEthUSDC artwork) when known so // the You-receive row / modal title show the receipt token's branding, // not the underlying's. Falls back to the integrator-supplied underlying // icon when reserve metadata isn't available. iconSrc: receiptToken?.iconSrc ?? display?.iconSrc, generateActionsParams: createAaveSupplyActions({ onBehalfOf: walletAddress, underlyingAsset, poolAddress, chainId, referralCode }), // The checkout delivers the underlying (USDT); the supply mints the aToken // (aEthUSDT) to the wallet. Offer adding the aToken — not `targetAsset` — // so the wallet tracks what the user actually holds. All fields come // straight from Aave reserve data so the wallet label / icon / decimals // match what users see on-chain and in explorers. addToWalletToken: receiptToken ? { tokenAddress: receiptToken.address, tokenChainId: chainId.toString(), tokenSymbol: receiptToken.symbol, decimals: receiptToken.decimals, iconSrc: receiptToken.iconSrc } : void 0 }; } export { AAVE_SUPPLY_ACTION_TYPE, createAaveSupplyActions, createAaveSupplyCheckoutConfig, isAaveSupplySupported };