Open your favorite code editor (e.g., VSCode) and open the index.js file. We’ll break down the code in chunks to clarify each step.
4.1 Import Libraries & Load Environment Variables
index.js
require('dotenv').config();
const { ethers } = require('ethers');
// Load RPC URL and private key from .env
const RPC_URL = process.env.SEPOLIA_RPC_URL;
const PRIVATE_KEY = process.env.PRIVATE_KEY;
// Create a provider & signer for Sepolia
const provider = new ethers.providers.JsonRpcProvider(RPC_URL);
const signer = new ethers.Wallet(PRIVATE_KEY, provider);
Explanation:
• require('dotenv').config() loads environment variables from your .env file.
• ethers.providers.JsonRpcProvider connects to the Ethereum network (Sepolia in this case).
• new ethers.Wallet(...) creates a signer capable of sending transactions, referencing your private key and the given provider.
4.2 Define Contract Addresses & ABIs
// Sepolia USDC Comet instance
const cometAddress = "0xAec1F48e02Cfb822Be958B68C7957156EB3F0b6e";
// Tokens
const wethAddress = "0x2D5ee574e710219a521449679A4A7f2B43f046ad"; // WETH on Sepolia
const usdcAddress = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"; // USDC on Sepolia
// Minimal ABIs (only the functions we need)
const cometAbi = [
"function supply(address asset, uint256 amount) external",
"function withdraw(address asset, uint256 amount) external",
"function borrowBalanceOf(address account) external view returns (uint256)"
];
const erc20Abi = [
"function approve(address spender, uint256 amount) external returns (bool)",
"function balanceOf(address account) external view returns (uint256)",
"function decimals() external view returns (uint8)"
];
Explanation:
• Addresses are specific to the Sepolia USDC market.
• We only include the smart contract functions needed for this tutorial (supply, withdraw, borrowBalanceOf, approve, balanceOf, decimals).
• If you need additional functionality, add the relevant pieces of ABI or use the full ABI from the Comet documentation.
4.3 Create Contract Instances
// Create contract objects for Comet, WETH, and USDC
const comet = new ethers.Contract(cometAddress, cometAbi, signer);
const weth = new ethers.Contract(wethAddress, erc20Abi, signer);
const usdc = new ethers.Contract(usdcAddress, erc20Abi, signer);
Explanation:
• Each ethers.Contract instance requires an address, ABI, and signer.
• comet: The main Compound V3 (Comet) contract for USDC base.
• weth: The WETH contract. We’ll deposit this as collateral.
• usdc: The base asset contract (USDC), which we’ll borrow.
4.4 Approve & Supply WETH as Collateral
async function supplyWethAsCollateral(amount) {
console.log(`Approving ${amount.toString()} WETH for Comet...`);
const approveTx = await weth.approve(cometAddress, amount);
await approveTx.wait();
console.log(`Supplying ${amount.toString()} WETH to Comet...`);
const supplyTx = await comet.supply(wethAddress, amount);
await supplyTx.wait();
console.log("WETH supplied as collateral.");
}
Explanation:
• First, you approve comet to move your WETH.
• Then you call supply(...) on the comet contract, which effectively deposits WETH as your collateral.
• amount should be in the correct decimal format (we’ll handle that soon).
4.5 Borrow USDC (Base Asset)
async function borrowUsdc(amount) {
console.log(`Borrowing ${amount.toString()} USDC from Comet...`);
const borrowTx = await comet.withdraw(usdcAddress, amount);
await borrowTx.wait();
console.log("USDC borrowed successfully.");
}
Explanation:
• In Compound V3, “borrowing” is done by withdrawing the base asset from the contract.
• This adds to your negative “base” balance, meaning you owe that amount plus interest over time.
4.6 Putting It All Together
Finally, we wrap these functions in a main execution block:
(async () => {
try {
// 1. Fetch decimals for WETH
const wethDecimals = await weth.decimals();
// Convert 0.2 WETH to correct decimal format
const wethSupplyAmount = ethers.utils.parseUnits("0.2", wethDecimals);
// Supply 0.2 WETH as collateral
await supplyWethAsCollateral(wethSupplyAmount);
// 2. Borrow 50 USDC
const usdcDecimals = await usdc.decimals();
const borrowAmount = ethers.utils.parseUnits("50", usdcDecimals);
await borrowUsdc(borrowAmount);
// 3. Check your new borrow balance
const debt = await comet.borrowBalanceOf(signer.address);
console.log(
`Your USDC debt is: ${ethers.utils.formatUnits(debt, usdcDecimals)}`
);
console.log("All steps completed successfully!");
} catch (err) {
console.error("Error in script:", err);
}
})();
Explanation:
We get WETH’s decimals and parse 0.2 WETH into the correct big integer format.
Supply that WETH to Comet, thereby increasing our borrowing capacity.
Get USDC’s decimals, parse 50 USDC, then borrow it.
Check your current USDC debt with borrowBalanceOf(...).
Log everything out for clarity.