Files
237-combo/examples/ts/compound3-supply-borrow.ts
2026-02-09 21:51:30 -08:00

177 lines
5.4 KiB
TypeScript

/**
* Compound III: Supply collateral and borrow base asset
*
* This example demonstrates how to:
* 1. Supply collateral to Compound III
* 2. Borrow the base asset (e.g., USDC)
*
* Note: In Compound III, you "borrow" by withdrawing the base asset
* after supplying collateral. There's one base asset per market.
*/
import { createWalletRpcClient } from '../../src/utils/chain-config.js';
import { getCompound3Comet } from '../../src/utils/addresses.js';
import { getTokenMetadata, parseTokenAmount } from '../../src/utils/tokens.js';
import { waitForTransaction } from '../../src/utils/rpc.js';
const CHAIN_ID = 1; // Mainnet
const PRIVATE_KEY = process.env.PRIVATE_KEY as `0x${string}`;
// Compound III Comet ABI
const COMET_ABI = [
{
name: 'supply',
type: 'function',
stateMutability: 'nonpayable',
inputs: [
{ name: 'asset', type: 'address' },
{ name: 'amount', type: 'uint256' },
],
outputs: [],
},
{
name: 'withdraw',
type: 'function',
stateMutability: 'nonpayable',
inputs: [
{ name: 'asset', type: 'address' },
{ name: 'amount', type: 'uint256' },
],
outputs: [],
},
{
name: 'baseToken',
type: 'function',
stateMutability: 'view',
inputs: [],
outputs: [{ name: '', type: 'address' }],
},
{
name: 'getBorrowBalance',
type: 'function',
stateMutability: 'view',
inputs: [{ name: 'account', type: 'address' }],
outputs: [{ name: '', type: 'uint256' }],
},
{
name: 'getCollateralBalance',
type: 'function',
stateMutability: 'view',
inputs: [
{ name: 'account', type: 'address' },
{ name: 'asset', type: 'address' },
],
outputs: [{ name: '', type: 'uint256' }],
},
] as const;
// ERC20 ABI for approvals
const ERC20_ABI = [
{
name: 'approve',
type: 'function',
stateMutability: 'nonpayable',
inputs: [
{ name: 'spender', type: 'address' },
{ name: 'amount', type: 'uint256' },
],
outputs: [{ name: '', type: 'bool' }],
},
] as const;
async function supplyAndBorrow() {
const walletClient = createWalletRpcClient(CHAIN_ID, PRIVATE_KEY);
const publicClient = walletClient as any;
const account = walletClient.account?.address;
if (!account) {
throw new Error('No account available');
}
const cometAddress = getCompound3Comet(CHAIN_ID);
// Get base token (USDC for USDC market)
console.log('Querying Comet contract...');
const baseToken = await publicClient.readContract({
address: cometAddress,
abi: COMET_ABI,
functionName: 'baseToken',
}) as `0x${string}`;
console.log(`Comet: ${cometAddress}`);
console.log(`Base token: ${baseToken}`);
// Use WETH as collateral (adjust based on market)
const collateralToken = getTokenMetadata(CHAIN_ID, 'WETH');
const baseTokenMetadata = getTokenMetadata(CHAIN_ID, 'USDC'); // Assuming USDC market
const collateralAmount = parseTokenAmount('1', collateralToken.decimals); // 1 WETH
const borrowAmount = parseTokenAmount('2000', baseTokenMetadata.decimals); // 2000 USDC
console.log(`\nSupplying ${collateralAmount} ${collateralToken.symbol} as collateral`);
console.log(`Borrowing ${borrowAmount} ${baseTokenMetadata.symbol} (base asset)`);
// Step 1: Approve collateral token
console.log('\n1. Approving collateral token...');
const approveTx = await walletClient.writeContract({
address: collateralToken.address,
abi: ERC20_ABI,
functionName: 'approve',
args: [cometAddress, collateralAmount],
});
await waitForTransaction(publicClient, approveTx);
console.log(`Approved: ${approveTx}`);
// Step 2: Supply collateral
console.log('\n2. Supplying collateral...');
const supplyTx = await walletClient.writeContract({
address: cometAddress,
abi: COMET_ABI,
functionName: 'supply',
args: [collateralToken.address, collateralAmount],
});
await waitForTransaction(publicClient, supplyTx);
console.log(`Supplied: ${supplyTx}`);
// Step 3: "Borrow" by withdrawing base asset
// In Compound III, borrowing is done by withdrawing the base asset
console.log('\n3. Borrowing base asset (withdrawing)...');
const borrowTx = await walletClient.writeContract({
address: cometAddress,
abi: COMET_ABI,
functionName: 'withdraw',
args: [baseToken, borrowAmount],
});
await waitForTransaction(publicClient, borrowTx);
console.log(`Borrowed: ${borrowTx}`);
// Step 4: Check balances
console.log('\n4. Checking positions...');
const borrowBalance = await publicClient.readContract({
address: cometAddress,
abi: COMET_ABI,
functionName: 'getBorrowBalance',
args: [account],
}) as bigint;
const collateralBalance = await publicClient.readContract({
address: cometAddress,
abi: COMET_ABI,
functionName: 'getCollateralBalance',
args: [account, collateralToken.address],
}) as bigint;
console.log(`Borrow balance: ${borrowBalance} ${baseTokenMetadata.symbol}`);
console.log(`Collateral balance: ${collateralBalance} ${collateralToken.symbol}`);
console.log('\n✅ Supply and borrow completed successfully!');
}
// Run if executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
supplyAndBorrow().catch(console.error);
}
export { supplyAndBorrow };