177 lines
5.4 KiB
TypeScript
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 };
|
|
|