feat: thorchain solana lp integration#12037
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
getThorTxData, getUnsignedSolanaTransaction, getSolanaTransactionFees. Follows tron/ pattern: vault lookup + SPL Memo Program instruction for fee estimation, hdwallet SolanaTxInstruction for buildSendApiTransaction. SPL token support forward-compat via tokenId passthrough. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the hard-reject stub with a full Memo Program fee estimation case. Uses TransactionInstruction (web3.js) for getFeeData, returns ThorUtxoOrCosmosTradeRateOrQuote routes. Also exports solana from thorchain-utils/index.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds getUnsignedSolanaTransaction, getSolanaTransactionFees to endpoints.ts and executeSolanaTransaction to ThorchainSwapper.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Detects SPL Memo Program instruction, base58-decodes data to UTF-8, delegates to shared thormaya.Parser. Adds bs58 dependency. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds solanaChainId to getThorchainTransactionType (returns 'Send') so the LP correctly routes SOL through the Send tx path. Adds SPL Memo Program instruction handling in Send/utils.ts: - estimateFees: builds TransactionInstruction (web3.js) when memo present, includes in getFeeData for accurate compute budget - handleSend: builds SolanaTxInstruction (hdwallet) when memo present, includes in buildSendTransaction chainSpecific Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThe PR adds Solana native token support to THORChain LP operations by implementing memo-based transaction instructions, extends transaction type detection to include Solana chains, refines asset lookups with case-insensitive mapping, and adds test identifiers to LP UI components. Changes
Sequence DiagramsequenceDiagram
participant User as User/Client
participant FeeEst as Fee Estimator
participant TxBuilder as Solana Tx Builder
participant MemoProg as Memo Program
participant Vault as THORChain Vault
User->>FeeEst: Request LP fee estimate with memo
alt Memo present
FeeEst->>TxBuilder: Build memoInstruction from memo
TxBuilder->>TxBuilder: Create Memo Program instruction
end
FeeEst->>FeeEst: Adjust estimationInstructions with memo
FeeEst-->>User: Return fee estimate
User->>TxBuilder: Send LP transaction (SOL + memo)
TxBuilder->>TxBuilder: Build memoInstruction
TxBuilder->>TxBuilder: Determine compute budget need
alt Should add compute budget
TxBuilder->>TxBuilder: Set computeUnitLimit & computeUnitPrice
TxBuilder->>TxBuilder: Add memo to chainSpecific instructions
end
TxBuilder->>MemoProg: Include Memo Program instruction
MemoProg-->>Vault: Memo data (+:SOL.SOL for add liquidity)
TxBuilder-->>Vault: Send native SOL
Vault-->>User: LP position confirmed
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…develop # Conflicts: # packages/swapper/src/thorchain-utils/getL1RateOrQuote.ts # packages/swapper/src/thorchain-utils/solana/getSolanaTransactionFees.ts # packages/swapper/src/thorchain-utils/solana/getUnsignedSolanaTransaction.ts # packages/swapper/src/thorchain-utils/solana/index.ts # packages/unchained-client/src/solana/parser/thorchain.ts # yarn.lock
NeOMakinG
left a comment
There was a problem hiding this comment.
Code Review ✅
Reviewed by: QABot (automated)
Summary
Clean, focused PR adding THORChain Solana LP support. Changes are minimal and well-targeted.
Changes Reviewed:
poolAssetHelpers.ts- Case-insensitive asset ID mapping for Solana base58 addresses ✅solana/constants.ts- New Memo Program ID constant, well-documented ✅Send/utils.ts- Memo instruction support for fee estimation and transactions ✅thorchain/index.ts- Adds Solana to Send transaction type ✅
Assessment:
- Type safety: ✅ Proper imports and usage (
SolanaTxInstruction,PublicKey, etc.) - Error handling: ✅ Follows existing patterns (optional memo, conditional creation)
- Code patterns: ✅ Consistent with codebase conventions
- No obvious bugs: ✅
Minor Note:
SOLANA_MEMO_PROGRAM_ID is defined in both swapper/solana/constants.ts and Send/utils.ts. This appears intentional to avoid cross-package dependencies, which is acceptable.
QABot testing skipped due to RAM constraints - code review only
The assetIdToThorPoolAssetIdMap was lowercasing its keys (AssetIds) which broke Solana's base58 chain reference (case-sensitive). constants.ts iterated these lowercased keys through fromAssetId() which threw, crashing the entire app. Keep original-case keys in the exported map (used by constants.ts for chainId extraction) and use a separate lowercased map for case-insensitive lookups. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
QA TestingTested with agent-browser (no qabot run - agent-browser session directly): What was tested:
Key fix in this PR:
Also added:
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/swapper/src/thorchain-utils/solana/constants.ts (1)
1-3: Update dependent files to import from the new constants file.This constant is defined in six locations across the codebase. The new
packages/swapper/src/thorchain-utils/solana/constants.tsfile exportsMEMO_PROGRAM_ID, but the other files define their own local copies instead of importing it:
packages/swapper/src/thorchain-utils/solana/getUnsignedSolanaTransaction.ts(line 10)packages/swapper/src/thorchain-utils/solana/getSolanaTransactionFees.ts(line 9)packages/swapper/src/thorchain-utils/getL1RateOrQuote.ts(line 62, asSOLANA_MEMO_PROGRAM_ID)src/components/Modals/Send/utils.ts(line 63, asSOLANA_MEMO_PROGRAM_ID)packages/unchained-client/src/solana/parser/thorchain.ts(line 6)Consider updating these files to import from the new constants file to reduce duplication and improve maintainability.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/swapper/src/thorchain-utils/solana/constants.ts` around lines 1 - 3, Multiple copies of the Solana memo program ID are defined locally; replace those local constants (e.g. SOLANA_MEMO_PROGRAM_ID or hardcoded 'MemoSq4gq...') with a single import of MEMO_PROGRAM_ID from the new constants file. Update callers in getUnsignedSolanaTransaction, getSolanaTransactionFees, getL1RateOrQuote, the Send modal utils, and the Solana parser (thorchain) to import MEMO_PROGRAM_ID and remove the duplicated local constant definitions so all modules use the exported MEMO_PROGRAM_ID.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/swapper/src/thorchain-utils/solana/constants.ts`:
- Around line 1-3: Multiple copies of the Solana memo program ID are defined
locally; replace those local constants (e.g. SOLANA_MEMO_PROGRAM_ID or hardcoded
'MemoSq4gq...') with a single import of MEMO_PROGRAM_ID from the new constants
file. Update callers in getUnsignedSolanaTransaction, getSolanaTransactionFees,
getL1RateOrQuote, the Send modal utils, and the Solana parser (thorchain) to
import MEMO_PROGRAM_ID and remove the duplicated local constant definitions so
all modules use the exported MEMO_PROGRAM_ID.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 3f41a7ec-42f4-47c5-8967-852405c6b98b
📒 Files selected for processing (6)
packages/swapper/src/swappers/ThorchainSwapper/utils/poolAssetHelpers/poolAssetHelpers.tspackages/swapper/src/thorchain-utils/solana/constants.tssrc/components/Modals/Send/utils.tssrc/lib/utils/thorchain/index.tssrc/pages/ThorChainLP/components/AddLiquidity/AddLiquidityInput.tsxsrc/pages/ThorChainLP/components/LpType.tsx
* fix: copy patches dir in public-api Dockerfile for pnpm install pnpm requires the patches directory during install (not just scripts) because patched dependencies are referenced in the lockfile. The --ignore-scripts flag alone doesn't prevent pnpm from reading patch files during dependency resolution. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add .railwayignore to reduce snapshot size for public-api deploys Railway's "Failed to snapshot repository" error is caused by the repo being too large (~74MB tracked files). This excludes frontend source, images, tests, and other files not needed for the public-api Dockerfile build from Railway's pre-build snapshot. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Revert "fix: add .railwayignore to reduce snapshot size for public-api deploys" This reverts commit 473f2d3. * Revert "fix: copy patches dir in public-api Dockerfile for pnpm install" This reverts commit a0618c1. * fix: unrug Railway CI - copy patches dir and add .railwayignore (#12099) * fix: unrug public-api Railway CI - copy patches dir and add .railwayignore Two fixes for Railway deployment failures: 1. Copy patches/ directory in Dockerfile before pnpm install - pnpm requires patch files during install even with --ignore-scripts because patched dependencies are referenced in the lockfile. 2. Add .railwayignore to reduce repo snapshot size - Railway's "Failed to snapshot repository" error was caused by the repo being ~74MB of tracked files. Excludes frontend source, images, tests, and other files not needed for the public-api Docker build. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add patches dir to swap-widget Dockerfile and update .railwayignore The swap-widget Dockerfile had the same missing patches/ dir bug as public-api — pnpm install fails with ENOENT for patched dependencies. Also add swap-widget *.md exception to .railwayignore. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: use copy package-import-method in Docker to avoid pnpm ENOENT (#12100) * fix: use copy package-import-method in Docker to avoid pnpm ENOENT pnpm's default hard-link strategy fails intermittently on Docker's overlay filesystem with "ENOENT: rename _tmp -> secp256k1". Setting package-import-method=copy via env var (Docker-only, doesn't affect local dev .npmrc) fixes the atomic rename race condition. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add retry loop for pnpm install in Docker builds The ENOENT rename failure persists even with package-import-method=copy because pnpm's hoisting/linking phase still does atomic renames that race on Docker's overlay filesystem. Since it's intermittent and all packages are cached in the store after the first attempt, a retry with clean node_modules is fast and reliable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: restrict swap-widget tsconfig types to prevent auto-discovery Without an explicit `types` field, TypeScript auto-discovers all @types/* packages hoisted to root node_modules. The deprecated stub @types/ethereumjs-util (from hdwallet-ledger devDeps) has no .d.ts files, causing TS2688 during Docker builds. Restricting to ["vite/client"] matches the pattern used by the root tsconfig. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: speed up stuck btc transactions via rbf (#11885) * fix: railway build with pnpm (#12107) * feat: thorchain solana lp integration (#12037) * fix: narrow YieldExplainers action prop type to remove unused claim variant (#12073) * fix: always refresh account balances after swap completion (#12106) * chore: unify claude and codex instruction entrypoints (#12119) * feat: idempotent release script state machine (#12110) * feat: bebop solana swapper take 2 (#12111) * chore: remove unused @chainflip/rpc and @chainflip/extrinsics deps (#12109) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: gomes-bot <contact@0xgom.es> Co-authored-by: kevin <35275952+kaladinlight@users.noreply.github.com> Co-authored-by: gomes <17035424+gomesalexandre@users.noreply.github.com> Co-authored-by: NeOMakinG <14963751+NeOMakinG@users.noreply.github.com>
* chore: prerelease v1.1016.0 (#12127) * fix: copy patches dir in public-api Dockerfile for pnpm install pnpm requires the patches directory during install (not just scripts) because patched dependencies are referenced in the lockfile. The --ignore-scripts flag alone doesn't prevent pnpm from reading patch files during dependency resolution. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add .railwayignore to reduce snapshot size for public-api deploys Railway's "Failed to snapshot repository" error is caused by the repo being too large (~74MB tracked files). This excludes frontend source, images, tests, and other files not needed for the public-api Dockerfile build from Railway's pre-build snapshot. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Revert "fix: add .railwayignore to reduce snapshot size for public-api deploys" This reverts commit 473f2d3. * Revert "fix: copy patches dir in public-api Dockerfile for pnpm install" This reverts commit a0618c1. * fix: unrug Railway CI - copy patches dir and add .railwayignore (#12099) * fix: unrug public-api Railway CI - copy patches dir and add .railwayignore Two fixes for Railway deployment failures: 1. Copy patches/ directory in Dockerfile before pnpm install - pnpm requires patch files during install even with --ignore-scripts because patched dependencies are referenced in the lockfile. 2. Add .railwayignore to reduce repo snapshot size - Railway's "Failed to snapshot repository" error was caused by the repo being ~74MB of tracked files. Excludes frontend source, images, tests, and other files not needed for the public-api Docker build. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add patches dir to swap-widget Dockerfile and update .railwayignore The swap-widget Dockerfile had the same missing patches/ dir bug as public-api — pnpm install fails with ENOENT for patched dependencies. Also add swap-widget *.md exception to .railwayignore. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: use copy package-import-method in Docker to avoid pnpm ENOENT (#12100) * fix: use copy package-import-method in Docker to avoid pnpm ENOENT pnpm's default hard-link strategy fails intermittently on Docker's overlay filesystem with "ENOENT: rename _tmp -> secp256k1". Setting package-import-method=copy via env var (Docker-only, doesn't affect local dev .npmrc) fixes the atomic rename race condition. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add retry loop for pnpm install in Docker builds The ENOENT rename failure persists even with package-import-method=copy because pnpm's hoisting/linking phase still does atomic renames that race on Docker's overlay filesystem. Since it's intermittent and all packages are cached in the store after the first attempt, a retry with clean node_modules is fast and reliable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: restrict swap-widget tsconfig types to prevent auto-discovery Without an explicit `types` field, TypeScript auto-discovers all @types/* packages hoisted to root node_modules. The deprecated stub @types/ethereumjs-util (from hdwallet-ledger devDeps) has no .d.ts files, causing TS2688 during Docker builds. Restricting to ["vite/client"] matches the pattern used by the root tsconfig. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: speed up stuck btc transactions via rbf (#11885) * fix: railway build with pnpm (#12107) * feat: thorchain solana lp integration (#12037) * fix: narrow YieldExplainers action prop type to remove unused claim variant (#12073) * fix: always refresh account balances after swap completion (#12106) * chore: unify claude and codex instruction entrypoints (#12119) * feat: idempotent release script state machine (#12110) * feat: bebop solana swapper take 2 (#12111) * chore: remove unused @chainflip/rpc and @chainflip/extrinsics deps (#12109) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: gomes-bot <contact@0xgom.es> Co-authored-by: kevin <35275952+kaladinlight@users.noreply.github.com> Co-authored-by: gomes <17035424+gomesalexandre@users.noreply.github.com> Co-authored-by: NeOMakinG <14963751+NeOMakinG@users.noreply.github.com> * fix: bebop solana signing + thorchain solana lp compute budget (#12132) * fix: bebop solana signing + reject amm-routed quotes (#12147) * fix: cherry-pick #12148 - bebop solana ghost tx + malformed amm routes (#12151) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: gomes-bot <contact@0xgom.es> Co-authored-by: kevin <35275952+kaladinlight@users.noreply.github.com> Co-authored-by: gomes <17035424+gomesalexandre@users.noreply.github.com> Co-authored-by: NeOMakinG <14963751+NeOMakinG@users.noreply.github.com>
chore: release v1.1016.0 (#12128) * chore: prerelease v1.1016.0 (#12127) * fix: copy patches dir in public-api Dockerfile for pnpm install pnpm requires the patches directory during install (not just scripts) because patched dependencies are referenced in the lockfile. The --ignore-scripts flag alone doesn't prevent pnpm from reading patch files during dependency resolution. * fix: add .railwayignore to reduce snapshot size for public-api deploys Railway's "Failed to snapshot repository" error is caused by the repo being too large (~74MB tracked files). This excludes frontend source, images, tests, and other files not needed for the public-api Dockerfile build from Railway's pre-build snapshot. * Revert "fix: add .railwayignore to reduce snapshot size for public-api deploys" This reverts commit 473f2d3. * Revert "fix: copy patches dir in public-api Dockerfile for pnpm install" This reverts commit a0618c1. * fix: unrug Railway CI - copy patches dir and add .railwayignore (#12099) * fix: unrug public-api Railway CI - copy patches dir and add .railwayignore Two fixes for Railway deployment failures: 1. Copy patches/ directory in Dockerfile before pnpm install - pnpm requires patch files during install even with --ignore-scripts because patched dependencies are referenced in the lockfile. 2. Add .railwayignore to reduce repo snapshot size - Railway's "Failed to snapshot repository" error was caused by the repo being ~74MB of tracked files. Excludes frontend source, images, tests, and other files not needed for the public-api Docker build. * fix: add patches dir to swap-widget Dockerfile and update .railwayignore The swap-widget Dockerfile had the same missing patches/ dir bug as public-api — pnpm install fails with ENOENT for patched dependencies. Also add swap-widget *.md exception to .railwayignore. --------- * fix: use copy package-import-method in Docker to avoid pnpm ENOENT (#12100) * fix: use copy package-import-method in Docker to avoid pnpm ENOENT pnpm's default hard-link strategy fails intermittently on Docker's overlay filesystem with "ENOENT: rename _tmp -> secp256k1". Setting package-import-method=copy via env var (Docker-only, doesn't affect local dev .npmrc) fixes the atomic rename race condition. * fix: add retry loop for pnpm install in Docker builds The ENOENT rename failure persists even with package-import-method=copy because pnpm's hoisting/linking phase still does atomic renames that race on Docker's overlay filesystem. Since it's intermittent and all packages are cached in the store after the first attempt, a retry with clean node_modules is fast and reliable. * fix: restrict swap-widget tsconfig types to prevent auto-discovery Without an explicit `types` field, TypeScript auto-discovers all @types/* packages hoisted to root node_modules. The deprecated stub @types/ethereumjs-util (from hdwallet-ledger devDeps) has no .d.ts files, causing TS2688 during Docker builds. Restricting to ["vite/client"] matches the pattern used by the root tsconfig. --------- * feat: speed up stuck btc transactions via rbf (#11885) * fix: railway build with pnpm (#12107) * feat: thorchain solana lp integration (#12037) * fix: narrow YieldExplainers action prop type to remove unused claim variant (#12073) * fix: always refresh account balances after swap completion (#12106) * chore: unify claude and codex instruction entrypoints (#12119) * feat: idempotent release script state machine (#12110) * feat: bebop solana swapper take 2 (#12111) * chore: remove unused @chainflip/rpc and @chainflip/extrinsics deps (#12109) --------- * fix: bebop solana signing + thorchain solana lp compute budget (#12132) * fix: bebop solana signing + reject amm-routed quotes (#12147) * fix: cherry-pick #12148 - bebop solana ghost tx + malformed amm routes (#12151) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: gomes-bot <contact@0xgom.es> Co-authored-by: kevin <35275952+kaladinlight@users.noreply.github.com> Co-authored-by: gomes <17035424+gomesalexandre@users.noreply.github.com> Co-authored-by: NeOMakinG <14963751+NeOMakinG@users.noreply.github.com>
Description
Adds SOL.SOL LP (add/remove liquidity) support to the THORChain LP page. Builds on #12036 (swapper integration).
What this enables:
How it works:
THORChain LP transactions are native SOL sends to vault + SPL Memo Program instruction. The
useSendThorTxhook handles all LP tx execution via the'Send'path. Two surgical changes:getThorchainTransactionType— addsolanaChainIdto the'Send'return condition (Solana routes the same way as UTXO/Tron: direct vault send)Send/utils.ts— add Memo Program instruction support to both:estimateFeesSolana case: whenmemois present, builds aTransactionInstruction(web3.js) and includes it ingetFeeDataso compute budget reflects the memo instructionhandleSendSolana case: whenmemois present, builds aSolanaTxInstruction(hdwallet) and includes it inbuildSendTransaction.chainSpecific.instructionsNo UI changes needed — Solana already appears in the pool list,
walletSupportsChainalready handles it.Issue (if applicable)
closes #12035
Risk
Low — Solana LP path is additive; only changes are in well-contained Send utils and one helper function. Existing Solana send flows (Jupiter, direct SOL/SPL sends) unaffected since memo instruction is only added when
memois non-null.THORChain SOL LP add/remove transactions. Inbound vault:
GWYXY7c6SVMkuhmDq2LT1Hj6qGkDFCqmdZWJdCeHUgEN.Testing
Engineering
Must merge #12036 first (this PR targets that branch).
Manual test checklist:
Operations
SOL.SOL pool is live. Operations can test add/remove liquidity with a small SOL amount.
Screenshots (if applicable)
Summary by CodeRabbit
New Features
Tests