fix: Implement Associated Token Account for USDC withdrawals
- Fixed PublicKey undefined error (derive from DRIFT_WALLET_PRIVATE_KEY) - Implemented ATA resolution using @solana/spl-token - Added comprehensive debug logging for withdrawal flow - Fixed AccountOwnedByWrongProgram error (need ATA not wallet address) - Successfully tested .58 withdrawal with on-chain confirmation - Updated .env with TOTAL_WITHDRAWN and LAST_WITHDRAWAL_TIME tracking Key changes: - lib/drift/withdraw.ts: Added getAssociatedTokenAddress() for USDC ATA - tsconfig.json: Excluded archive folders from compilation - package.json: Added bn.js as direct dependency Transaction: 4drNfMR1xBosGCQtfJ2a4r6oEawUByrT6L7Thyqu6QQWz555hX3QshFuJqiLZreL7KrheSgTdCEqMcXP26fi54JF Wallet: 3dG7wayp7b9NBMo92D2qL2sy1curSC4TTmskFpaGDrtA USDC ATA: 8ZEMwErnwxPNNNHJigUcMfrkBG14LCREDdKbqKm49YY7
This commit is contained in:
4
.env
4
.env
@@ -418,5 +418,5 @@ WITHDRAWAL_INTERVAL_HOURS=168
|
||||
WITHDRAWAL_PROFIT_PERCENT=10
|
||||
MIN_WITHDRAWAL_AMOUNT=5
|
||||
MIN_ACCOUNT_BALANCE=500
|
||||
LAST_WITHDRAWAL_TIME=
|
||||
TOTAL_WITHDRAWN=0
|
||||
LAST_WITHDRAWAL_TIME=2025-11-19T19:34:47.185Z
|
||||
TOTAL_WITHDRAWN=6.58
|
||||
@@ -5,8 +5,10 @@
|
||||
*/
|
||||
|
||||
import BN from 'bn.js'
|
||||
import { PublicKey } from '@solana/web3.js'
|
||||
import { PublicKey, Keypair } from '@solana/web3.js'
|
||||
import { getAssociatedTokenAddress, TOKEN_PROGRAM_ID } from '@solana/spl-token'
|
||||
import { initializeDriftService } from './client'
|
||||
import bs58 from 'bs58'
|
||||
|
||||
export interface WithdrawalResult {
|
||||
success: boolean
|
||||
@@ -29,17 +31,62 @@ export async function withdrawFromDrift(
|
||||
|
||||
// Convert USD amount to token amount (USDC has 6 decimals)
|
||||
// $50.25 → 50,250,000 (raw token amount with 6 decimals)
|
||||
const tokenAmount = new BN(Math.floor(amountUSD * 1_000_000))
|
||||
const rawAmount = Math.floor(amountUSD * 1_000_000)
|
||||
console.log(`📊 Raw amount before BN: ${rawAmount} (type: ${typeof rawAmount})`)
|
||||
const tokenAmount = new BN(rawAmount.toString())
|
||||
|
||||
console.log(`📊 Withdrawal details:`)
|
||||
console.log(` Amount: $${amountUSD.toFixed(2)} USDC`)
|
||||
console.log(` Token amount: ${tokenAmount.toString()} (raw with 6 decimals)`)
|
||||
console.log(` Market index: ${usdcMarketIndex}`)
|
||||
|
||||
// Get destination address (default to wallet public key if not specified)
|
||||
const destination = destinationWallet
|
||||
? new PublicKey(destinationWallet)
|
||||
: new PublicKey(process.env.WALLET_PUBLIC_KEY!)
|
||||
// Get destination address
|
||||
// Need to get the Associated Token Account (ATA) for USDC, not just the wallet address
|
||||
let walletPublicKey: PublicKey
|
||||
let destination: PublicKey
|
||||
try {
|
||||
if (destinationWallet) {
|
||||
console.log(`🔑 Using provided destination wallet`)
|
||||
walletPublicKey = new PublicKey(destinationWallet)
|
||||
} else {
|
||||
console.log(`🔑 Deriving destination from private key`)
|
||||
// Derive public key from private key (same wallet as trader)
|
||||
const privateKeyStr = process.env.DRIFT_WALLET_PRIVATE_KEY
|
||||
if (!privateKeyStr) {
|
||||
throw new Error('DRIFT_WALLET_PRIVATE_KEY environment variable not set')
|
||||
}
|
||||
console.log(`🔑 Private key length: ${privateKeyStr.length}`)
|
||||
const privateKeyBytes = privateKeyStr.startsWith('[')
|
||||
? Uint8Array.from(JSON.parse(privateKeyStr))
|
||||
: bs58.decode(privateKeyStr)
|
||||
console.log(`🔑 Private key bytes length: ${privateKeyBytes.length}`)
|
||||
const keypair = Keypair.fromSecretKey(privateKeyBytes)
|
||||
walletPublicKey = keypair.publicKey
|
||||
console.log(`🔑 Derived wallet public key: ${walletPublicKey.toString()}`)
|
||||
}
|
||||
|
||||
// USDC mint address on Solana mainnet
|
||||
const usdcMint = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v')
|
||||
console.log(`🔑 USDC Mint: ${usdcMint.toString()}`)
|
||||
console.log(`🔑 Wallet public key: ${walletPublicKey.toString()}`)
|
||||
console.log(`🔑 About to call getAssociatedTokenAddress...`)
|
||||
|
||||
// Get the Associated Token Account for USDC
|
||||
destination = await getAssociatedTokenAddress(
|
||||
usdcMint,
|
||||
walletPublicKey,
|
||||
false, // allowOwnerOffCurve
|
||||
TOKEN_PROGRAM_ID
|
||||
)
|
||||
|
||||
console.log(`✅ Got ATA successfully!`)
|
||||
console.log(` Wallet: ${walletPublicKey.toString()}`)
|
||||
console.log(` USDC ATA: ${destination.toString()}`)
|
||||
|
||||
} catch (keyError: any) {
|
||||
console.error(`❌ Failed to get destination address:`, keyError)
|
||||
throw new Error(`Failed to derive destination address: ${keyError?.message || 'Unknown error'}`)
|
||||
}
|
||||
|
||||
console.log(` Destination: ${destination.toString()}`)
|
||||
|
||||
|
||||
1
package-lock.json
generated
1
package-lock.json
generated
@@ -14,6 +14,7 @@
|
||||
"@pythnetwork/price-service-client": "^1.3.0",
|
||||
"@solana/web3.js": "^1.91.1",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"bn.js": "^5.2.2",
|
||||
"bs58": "^5.0.0",
|
||||
"next": "^15.0.0",
|
||||
"postcss": "^8.5.6",
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"@pythnetwork/price-service-client": "^1.3.0",
|
||||
"@solana/web3.js": "^1.91.1",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"bn.js": "^5.2.2",
|
||||
"bs58": "^5.0.0",
|
||||
"next": "^15.0.0",
|
||||
"postcss": "^8.5.6",
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
"node_modules",
|
||||
"archive",
|
||||
".archive"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user