Skip to content

feat(swapper): add Panora swapper for Aptos swaps#12492

Open
swdiscordia wants to merge 16 commits into
shapeshift:developfrom
swdiscordia:feat/panora-swapper
Open

feat(swapper): add Panora swapper for Aptos swaps#12492
swdiscordia wants to merge 16 commits into
shapeshift:developfrom
swdiscordia:feat/panora-swapper

Conversation

@swdiscordia

@swdiscordia swdiscordia commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Description

Adds Panora, the Aptos DEX aggregator, as a swapper for intra-Aptos swaps (APT and Aptos coins).

Stacked on #12349 (Aptos chain integration): this branch contains all of its commits plus two new ones. Only review the last two commits here; the rest is reviewed in #12349.

Implementation notes:

  • PanoraSwapper queries the Panora /swap API for rates and quotes. The API deals in human readable token amounts, so amounts are converted from and to base units at the boundary (verified against the live API).
  • Transactions are built through a new generic AptosChainAdapter.buildEntryFunctionApiTransaction, which produces properly BCS serialized SimpleTransaction bytes via the Aptos SDK (gas simulation included). buildSendApiTransaction now delegates to it.
  • Trade status is checked on chain via the existing checkAptosSwapStatus helper, same pattern as the Cetus (Sui) swapper.
  • Behind the PanoraSwap feature flag (VITE_FEATURE_PANORA_SWAP, off in production), with a CSP entry for api.panora.exchange.

Affiliate fees: supported natively by Panora and verified against the live /swap API (integratorFeePercentage + integratorFeeAddress, with the fee recipient embedded in the on-chain router call). Important caveat also verified live: if the percentage is sent without an address, the fee is still deducted from the user but kept by Panora. Fee sending is therefore gated behind PANORA_INTEGRATOR_FEE_ADDRESS, which stays unset until the DAO has an Aptos treasury address (the placeholder DAO_TREASURY_APTOS was removed during #12349 review for the same reason). Until then quotes charge no affiliate fee rather than losing it.

Issue (if applicable)

closes #

Risk

Low. New swapper entirely behind the VITE_FEATURE_PANORA_SWAP feature flag (off in production), and the Aptos chain itself is also feature flagged (#12349). No changes to existing swap flows.

What protocols, transaction types, wallets or contract interactions might be affected by this PR?

Panora router contract on Aptos only (panora_swap::router_entry). Aptos entry function transactions are new, introduced by the #12349 stack. No existing swappers or chains are touched.

Testing

Engineering

  1. Check out the branch. VITE_FEATURE_APTOS and VITE_FEATURE_PANORA_SWAP are already enabled in .env.development.
  2. Aptos assets are not yet in the committed generated asset data (they will land with the next weekly regen after feat(chain-adapters): add Aptos chain integration with NEAR Intents support #12349 merges). For local testing run pnpm run generate:asset-data, or wait for the regen.
  3. Navigate to Trade and test the following pairs, all on Aptos:
    • APT -> USDC
    • USDC -> APT
    • APT -> amAPT
  4. Verify Panora appears as Protocol with sane quotes and rates (see screenshots).
  5. Execute a small swap end to end and verify the status goes from pending to complete (verified on mainnet, see execution screenshots below).

Operations

  • 🏁 My feature is behind a flag and doesn't require operations testing (yet)

Screenshots (if applicable)

Screenshots taken on a local build with the flags enabled:

APT -> USDC

USDC -> APT

Execution: Confirm Details (0.1 APT -> USDC via Panora, mainnet)

Execution: swap complete (received exactly the quoted amount)

APT -> amAPT (liquid staking token route)

Summary by CodeRabbit

  • New Features
    • Added Aptos mainnet support for wallet connection, account discovery, balances, asset browsing, sending, fee estimation, and transaction tracking.
    • Added Aptos token and native APT asset support, including market data and portfolio display.
    • Added Panora swap support for Aptos, including quotes, rates, transaction execution, fees, and status tracking.
    • Added feature flags to enable or disable Aptos and Panora swaps by environment.
  • Bug Fixes
    • Improved Ledger app checks to avoid unsupported-chain errors for non-Ledger wallets.
  • Tests
    • Added end-to-end coverage for Aptos accounts, assets, filtering, and balances.

Discostu and others added 14 commits July 9, 2026 09:53
- Add hdwallet-core/src/aptos.ts with AptosWallet interfaces
- Add SLIP-44 637 for Aptos in utils.ts
- Add supportsAptos/infoAptos in wallet.ts
- Add hdwallet-native AptosAdapter (Ed25519 + SHA3-256)
- Add MixinNativeAptosWallet/MixinNativeAptosWalletInfo
- Wire into native.ts (initialize, wipe, describePath, mixins)

Local only - no PR
Wires the Aptos chain adapter, HDWallet, and types (added in prior
commits) into the full app: asset generation via Panora token list,
CoinGecko adapter, plugin indexer URL, NEAR Intents Aptos support
(web-xeq.3), RFOX bridge, send modal, trade execution dispatch,
state migrations bump (v334), e2e fixtures, and ButterSwap test
mock updates for the AptosSwapperDeps ripple.

Also fixes audit findings:
- getRpcUrl() on AptosChainAdapter to replace unsafe protected cast
- VITE_APTOS_INDEXER_URL validation + type declaration
- Record<AssetId, ...> typing on test fixture marketDataByAssetIdUsd

Refs: web-xeq.1 (chain adapter), web-xeq.3 (NEAR Intents Aptos),
web-xeq.4 (qabot fixtures). PanoraSwapper (web-xeq.2) intentionally
deferred to a separate PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Aptos node, when called with estimate_max_gas_amount=true,
overwrites max_gas_amount in the response with the sender's
AFFORDABILITY ceiling (balance / gas_unit_price), NOT a tight
recommendation. Reading that field as the gas estimate caused
fees to be inflated by 100-300x.

For a wallet holding 1.08 APT at gas_unit_price=100, the node
returned max_gas_amount=1,084,352. Multiplied by the prioritized
gas estimate (150 octas), the displayed network fee came out to
1.62 APT (~\$1.54) for what should be a ~0.01 APT transfer.

Fix: prefer sim.gas_used (real simulated consumption) with the
Aptos CLI's 1.5x safety factor (gas_used * 3 / 2). Cap at the
affordability ceiling defensively. Bump MIN_MAX_GAS_AMOUNT from
12,000 to 20,000 to safely cover real transfer_coins consumption
(historical on-chain: 5,500-10,500 units) when simulation fails
(e.g., dummy pubkey rejected by INVALID_AUTH_KEY).

Refs:
- https://aptos.dev/build/guides/system-integrators-guide
  ("estimate uses min(max_gas_amount, gas_used * safety_factor)",
   CLI safety_factor = 1.5)
- https://aptos.dev/network/blockchain/gas-txn-fee
- Direct fullnode simulation confirmed max_gas_amount echoed
  as account_balance / gas_unit_price when the flag is set.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolves all 9 actionable comments from the CodeRabbit review on the
Aptos chain integration PR.

Chain adapter (packages/chain-adapters/src/aptos/AptosChainAdapter.ts):
- validateAddress now uses AccountAddress.fromString() from the SDK,
  which correctly accepts both short-form (0x1) and full-form Aptos
  addresses, instead of a rigid regex that rejected 0x1.
- parseTx status logic now handles all three cases explicitly: success
  === true → Confirmed, false → Failed, undefined (pending tx) →
  Pending. Previously undefined was incorrectly treated as Confirmed.
- Sender/recipient equality now goes through AccountAddress.equals via
  a normalized eq() helper so casing/length variants of the same Aptos
  address compare correctly.
- buildSendApiTransaction now honors chainSpecific.coinType so non-APT
  CoinStore coins on Aptos can be transferred via NEAR Intents (or any
  future swapper).

Aptos types (packages/chain-adapters/src/aptos/types.ts):
- BuildTxInput gains coinType?: string (Aptos CoinStore type, defaults
  to APT).

NEAR Intents Aptos route
(packages/swapper/src/swappers/NearIntentsSwapper/endpoints.ts):
- getUnsignedAptosTransaction detects non-native Aptos coins via
  assetNamespace (slip44 = native APT, otherwise assetReference is the
  Move CoinStore type) and forwards coinType to the chain adapter.

Aptos swap status check (packages/swapper/src/utils.ts):
- checkAptosSwapStatus normalizes recipient addresses via
  AccountAddress before comparing, replacing the substring-style
  t.to.includes(address) check.

Aptos util (src/lib/utils/aptos.ts):
- isAptosChainAdapter type guard now checks that getChainId is a
  function and wraps the call in try/catch so plain objects can't
  throw.

Native HDWallet (packages/hdwallet-native/src/aptos.ts):
- aptosNextAccountPath now delegates to core.aptosNextAccountPath
  instead of throwing.

Treasury (packages/utils/src/treasury.ts):
- Drop KnownChainIds.AptosMainnet from treasuryChainIds and remove the
  placeholder DAO_TREASURY_APTOS constant. The Aptos treasury entry
  will be added when the real DAO multisig address is available.

Treasury helpers
(packages/swapper/src/swappers/utils/helpers/helpers.ts):
- Drop the AptosMainnet entry from DAO_TREASURY_BY_CHAIN_ID.

Ledger constants (src/context/WalletProvider/Ledger/constants.ts):
- Remove conditional inclusion of aptosAssetId from
  availableLedgerAppAssetIds. LedgerHDWallet does not implement
  AptosWallet; Aptos Ledger support will land in a focused follow-up
  PR with physical-device testing.

Tests (packages/chain-adapters/src/aptos/AptosChainAdapter.test.ts):
- vi.mock now keeps the real exports of @aptos-labs/ts-sdk
  (AccountAddress, Ed25519PublicKey, etc.) and only mocks the
  network-using Aptos client, AptosConfig, and Network. Without this,
  the new AccountAddress.equals comparisons would throw silently.
- validateAddress test cases updated to reflect the SDK's behavior:
  short-form (0x1) and unprefixed full-form are now accepted; only
  truly malformed inputs are rejected.

Refs: CodeRabbit review on PR shapeshift#12349

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…first

verifyLedgerAppOpen() previously called getCoin() and getLedgerAppName()
unconditionally before checking the wallet type. Both switches throw
"Unsupported chainId" for any chain not enumerated (e.g. Aptos in this
PR, since the Aptos Ledger commit was intentionally deferred). Result:
AptosChainAdapter.getAddress() threw for Native wallets too because the
chain adapter calls verifyLedgerAppOpen() in its address path.

Move the isLedger(wallet) early-return to the top of the function so
the chain lookups only happen for actual Ledger wallets. Native and
other non-Ledger wallets bypass the gate entirely.

Side benefit: future chain additions to the app don't need a
simultaneous ledgerAppGate.ts update unless they actually ship Ledger
support.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the bespoke Panora-based fetcher with the same CoinGecko
tokenlist pattern used by every other non-EVM chain (Solana, Sui,
Near, Ton, Tron). Removes the VITE_PANORA_API_KEY requirement from
the asset generation pipeline.

CoinGecko exposes two different platform slugs for Aptos: their
/api/v3 endpoints (and our CoinGecko adapter) use 'aptos-network',
but the static tokenlist at tokens.coingecko.com only responds to
'aptos' ('aptos-network' returns 403 there). Hardcoded the right
slug in scripts/generateAssetData/coingecko.ts to keep the existing
'aptos-network' adapter value untouched for API consumers.

Verified `pnpm run generate:chain aptos` returns 70 assets from
CoinGecko without any API key.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@swdiscordia
swdiscordia requested a review from a team as a code owner July 14, 2026 08:50
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds Aptos mainnet support across chain identifiers, wallets, native signing, chain adapters, assets, portfolio, sends, swaps, feature flags, and transaction status handling. Adds Panora as an Aptos swapper and extends NEAR Intents with Aptos transaction and fee flows.

Changes

Aptos foundation and wallet support

Layer / File(s) Summary
Chain contracts and assets
.env*, packages/caip/..., packages/types/..., packages/utils/..., scripts/generateAssetData/..., headers/csps/...
Defines Aptos CAIP identifiers, assets, CoinGecko mappings, generated asset support, CSP endpoints, and environment configuration.
Wallet derivation and signing
packages/hdwallet-core/src/aptos.ts, packages/hdwallet-native/src/aptos.ts, packages/hdwallet-native/src/crypto/isolation/adapters/aptos.ts, packages/hdwallet-native/src/native.ts
Adds Aptos BIP44 paths, wallet capability guards, Ed25519 address derivation, transaction signing, and native wallet lifecycle integration.
Aptos chain adapter
packages/chain-adapters/src/aptos/*, packages/chain-adapters/src/types.ts
Implements Aptos account retrieval, token parsing, transaction construction, fee estimation, signing, broadcasting, validation, and transaction parsing, with Vitest coverage.
Application integration
src/plugins/aptos/*, src/lib/account/*, src/state/slices/portfolioSlice/*, src/components/Modals/Send/*, src/lib/utils/aptos.ts
Registers the Aptos adapter, gates it behind feature flags, derives accounts, displays portfolio assets, supports sends, and polls Aptos transaction status.

Panora and Aptos swap routing

Layer / File(s) Summary
Panora swapper
packages/swapper/src/swappers/PanoraSwapper/*, packages/swapper/src/constants.ts, src/state/helpers.ts
Adds Panora API types, service requests, quote/rate construction, Aptos transaction generation, fee/status endpoints, registration, slippage defaults, feature gating, and icon support.
NEAR Intents Aptos flow
packages/swapper/src/swappers/NearIntentsSwapper/*, packages/swapper/src/types.ts, src/lib/tradeExecution.ts, src/components/MultiHopTrade/*
Adds Aptos chain mapping, fee estimation, unsigned transaction construction, signing/broadcast execution, and trade status handling for NEAR Intents.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related issues

Poem

A bunny hops where Aptos flows,
Through wallets, swaps, and coins it goes.
Panora quotes twinkle bright,
NEAR Intents guide trades just right.
Flags bloom green, transactions hum—
“Hop hop hooray, the chain has come!”

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding the Panora swapper for Aptos swaps.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (6)
packages/swapper/src/swappers/PanoraSwapper/utils/helpers.ts (1)

6-26: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Deduplicate logic and apply verb prefix naming convention.

getTokenAddress and aptosAddressFromAssetId contain identical address resolution logic. Additionally, as per coding guidelines, functions should use verb prefixes for actions.

Consider renaming aptosAddressFromAssetId to getAptosAddressFromAssetId and updating getTokenAddress to call it, eliminating the duplicate code.

♻️ Proposed refactor
-export const getTokenAddress = (asset: Asset): string => {
-  const { assetNamespace, assetReference } = fromAssetId(asset.assetId)
-
-  // For native APT (slip44 namespace), return the Panora native token address
-  if (assetNamespace === 'slip44') {
-    return PANORA_NATIVE_TOKEN_ADDRESS
-  }
-
-  // For tokens, the assetReference is the Aptos token address
-  return assetReference
-}
-
-export const aptosAddressFromAssetId = (assetId: string): string => {
+export const getAptosAddressFromAssetId = (assetId: string): string => {
   const { assetReference, assetNamespace } = fromAssetId(assetId)
 
   if (assetNamespace === 'slip44') {
     return PANORA_NATIVE_TOKEN_ADDRESS
   }
 
   return assetReference
 }
+
+export const getTokenAddress = (asset: Asset): string => {
+  return getAptosAddressFromAssetId(asset.assetId)
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/swapper/src/swappers/PanoraSwapper/utils/helpers.ts` around lines 6
- 26, Rename aptosAddressFromAssetId to getAptosAddressFromAssetId and update
all references to the new verb-prefixed name. Refactor getTokenAddress to
delegate address resolution to getAptosAddressFromAssetId, removing its
duplicated fromAssetId and slip44 handling while preserving the existing native
and token address results.

Source: Coding guidelines

packages/swapper/src/swappers/PanoraSwapper/utils/constants.ts (1)

13-13: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove unused constant.

PANORA_DEFAULT_SLIPPAGE_DECIMAL_PERCENTAGE is never used. The actual default slippage used by the Panora swapper is defined centrally as DEFAULT_PANORA_SLIPPAGE_DECIMAL_PERCENTAGE in packages/swapper/src/constants.ts.

♻️ Proposed refactor
-export const PANORA_DEFAULT_SLIPPAGE_DECIMAL_PERCENTAGE = '0.005'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/swapper/src/swappers/PanoraSwapper/utils/constants.ts` at line 13,
Remove the unused PANORA_DEFAULT_SLIPPAGE_DECIMAL_PERCENTAGE export from the
constants module, and retain DEFAULT_PANORA_SLIPPAGE_DECIMAL_PERCENTAGE in the
central swapper constants as the sole default slippage definition.
packages/chain-adapters/src/aptos/AptosChainAdapter.test.ts (1)

10-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Mocked client omits transaction.build/transaction.simulate/transaction.submit, so send/build/broadcast/fee paths are untested.

buildSendApiTransaction, buildEntryFunctionApiTransaction, estimateMaxGasAmount, broadcastTransaction, and getFeeData have no test coverage here. That gap is directly why the FA-vs-Coin token-transfer branch mismatch flagged in AptosChainAdapter.ts (buildSendApiTransaction) wasn't caught. Consider extending the mock with transaction.build.simple, transaction.simulate.simple, transaction.submit.simple, and getSigningMessage to add coverage for these send-critical paths.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/chain-adapters/src/aptos/AptosChainAdapter.test.ts` around lines 10
- 25, The Aptos SDK mock in the test setup omits transaction send and fee APIs,
leaving build, simulation, submission, and signing paths uncovered. Extend the
mock returned by the Aptos constructor to provide transaction.build.simple,
transaction.simulate.simple, transaction.submit.simple, and getSigningMessage,
then add tests covering buildSendApiTransaction,
buildEntryFunctionApiTransaction, estimateMaxGasAmount, broadcastTransaction,
and getFeeData, including both FA and Coin transfer branches.
src/plugins/aptos/index.tsx (1)

1-31: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Rename this file to use the .ts extension.

Since this file does not contain any JSX, it should use the .ts extension instead of .tsx.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/plugins/aptos/index.tsx` around lines 1 - 31, Rename the file from
index.tsx to index.ts without changing the register function or its plugin
configuration, since the implementation contains no JSX.
src/config.ts (1)

310-312: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a default value for the Aptos node URL.

Without a default, developers will encounter configuration validation errors on startup if their .env file lacks VITE_APTOS_NODE_URL, even if the Aptos feature flag is disabled. Providing a public fallback avoids breaking the local development environment.

♻️ Proposed refactor
   VITE_FEATURE_APTOS: bool({ default: false }),
-  VITE_APTOS_NODE_URL: url(),
+  VITE_APTOS_NODE_URL: url({ default: 'https://api.mainnet.aptoslabs.com/v1' }),
   VITE_APTOS_INDEXER_URL: url({ default: 'https://api.mainnet.aptoslabs.com/v1/graphql' }),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/config.ts` around lines 310 - 312, Update the VITE_APTOS_NODE_URL
configuration entry in the config schema to include a suitable public default
URL, matching the existing default behavior of VITE_APTOS_INDEXER_URL, so
startup validation succeeds when the Aptos feature is disabled and the
environment variable is absent.
src/components/Modals/Send/utils.ts (1)

557-570: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Support skipDeviceDerivation by passing pubKey for transaction building.

To ensure proper functionality and future-proof hardware wallet support (preventing the wallet adapter from needing a physical device interaction just to fetch the sending address), consider passing pubKey down to buildSendTransaction, aligning with the convention used for EVM, UTXO, NEAR, and Sui networks in this file.

🛠️ Proposed fix
     if (fromChainId(asset.chainId).chainNamespace === CHAIN_NAMESPACE.Aptos) {
       const { accountNumber } = bip44Params
       const adapter = assertGetAptosChainAdapter(chainId)
+      const pubKey = skipDeviceDerivation ? fromAccountId(sendInput.accountId).account : undefined
 
       return adapter.buildSendTransaction({
         to,
         value,
         wallet,
         accountNumber,
+        pubKey,
         sendMax: sendInput.sendMax,
         chainSpecific: { memo },
       } as BuildSendTxInput<KnownChainIds.AptosMainnet>)
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Modals/Send/utils.ts` around lines 557 - 570, Update the Aptos
branch in the transaction-building flow to pass the available pubKey into
adapter.buildSendTransaction, matching the existing EVM, UTXO, NEAR, and Sui
call conventions. Preserve the current Aptos parameters and ensure the pubKey
supports skipDeviceDerivation without requiring device address derivation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/caip/src/adapters/coingecko/index.ts`:
- Line 101: Update the Aptos CoinGecko platform identifier in the relevant
adapter enum or mapping from aptos-network to aptos, preserving the existing
lookup flow for other platforms.

In `@packages/chain-adapters/src/aptos/AptosChainAdapter.ts`:
- Around line 268-281: Update buildSendApiTransaction to distinguish FA-only
assets from CoinStore-backed coin types: retain the existing
aptos_account::transfer_coins payload for standard coins, but route bare FA
metadata addresses through the appropriate fungible-asset transfer entry
function with its expected arguments. Use the existing chainSpecific information
and established FA transaction-building symbols where available.
- Around line 207-209: Update AptosChainAdapter.getTxHistory() to return a
rejected Promise for the unimplemented operation instead of throwing
synchronously, preserving the existing error message and Promise<never> contract
so callers can handle failures with catch().
- Around line 211-235: In estimateMaxGasAmount, check sim.success immediately
after simulation and before reading gas_used or max_gas_amount; when false,
throw an error containing sim.vm_status. Preserve the existing gas calculation
only for successful simulations.

In `@packages/hdwallet-native/src/aptos.ts`:
- Around line 38-40: Update the aptosWipe method to declare an explicit void
return type while preserving its existing behavior of clearing aptosAdapter.

In `@packages/swapper/src/swappers/ButterSwap/swapperApi/getTradeQuote.test.ts`:
- Line 46: Replace the any assertions used for mocked assertGetAptosChainAdapter
dependencies with unknown-based assertions typed as
ReturnType<SwapperDeps['assertGetAptosChainAdapter']> or ReturnType<typeof
vi.fn>. Apply this change at
packages/swapper/src/swappers/ButterSwap/swapperApi/getTradeQuote.test.ts:46 and
both locations at
packages/swapper/src/swappers/ButterSwap/swapperApi/getTradeRate.test.ts:35 and
80.

In `@packages/swapper/src/swappers/PanoraSwapper/utils/panoraService.ts`:
- Line 4: Replace the hardcoded value in PANORA_API_KEY with configuration
sourced from an environment variable or injected SwapperDeps config. Update
callers of the Panora service as needed to pass and reuse the configured key,
while preserving existing API request behavior and ensuring no secret remains in
source control.

In `@scripts/generateAssetData/generateTrustWalletUrl/generateTrustWalletUrl.ts`:
- Line 18: Update the Aptos entry in the Trust Wallet URL generation logic to
append the assetReference for both native and token assets, producing the
blockchains/aptos/assets/<asset_address>/info.json path instead of the base
assets/info.json path. Add focused tests covering Aptos native and token
AssetIds and verify other chain URL behavior remains unchanged.

In `@src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx`:
- Around line 215-220: Update the AptosMainnet branch in the transaction-status
handling to invoke the existing failAction callback when
getAptosTransactionStatus returns TxStatus.Failed, rather than treating the
failure as successful confirmation. Preserve isConfirmed for TxStatus.Confirmed
and keep the existing behavior for other statuses, matching the TON and Starknet
failure handling.

In `@src/lib/utils/aptos.ts`:
- Line 5: Update the TxStatus import in aptos.ts to use the standard
`@shapeshiftoss` package namespace instead of the direct
packages/unchained-client/src/types path, preserving the existing symbol usage.

---

Nitpick comments:
In `@packages/chain-adapters/src/aptos/AptosChainAdapter.test.ts`:
- Around line 10-25: The Aptos SDK mock in the test setup omits transaction send
and fee APIs, leaving build, simulation, submission, and signing paths
uncovered. Extend the mock returned by the Aptos constructor to provide
transaction.build.simple, transaction.simulate.simple,
transaction.submit.simple, and getSigningMessage, then add tests covering
buildSendApiTransaction, buildEntryFunctionApiTransaction, estimateMaxGasAmount,
broadcastTransaction, and getFeeData, including both FA and Coin transfer
branches.

In `@packages/swapper/src/swappers/PanoraSwapper/utils/constants.ts`:
- Line 13: Remove the unused PANORA_DEFAULT_SLIPPAGE_DECIMAL_PERCENTAGE export
from the constants module, and retain DEFAULT_PANORA_SLIPPAGE_DECIMAL_PERCENTAGE
in the central swapper constants as the sole default slippage definition.

In `@packages/swapper/src/swappers/PanoraSwapper/utils/helpers.ts`:
- Around line 6-26: Rename aptosAddressFromAssetId to getAptosAddressFromAssetId
and update all references to the new verb-prefixed name. Refactor
getTokenAddress to delegate address resolution to getAptosAddressFromAssetId,
removing its duplicated fromAssetId and slip44 handling while preserving the
existing native and token address results.

In `@src/components/Modals/Send/utils.ts`:
- Around line 557-570: Update the Aptos branch in the transaction-building flow
to pass the available pubKey into adapter.buildSendTransaction, matching the
existing EVM, UTXO, NEAR, and Sui call conventions. Preserve the current Aptos
parameters and ensure the pubKey supports skipDeviceDerivation without requiring
device address derivation.

In `@src/config.ts`:
- Around line 310-312: Update the VITE_APTOS_NODE_URL configuration entry in the
config schema to include a suitable public default URL, matching the existing
default behavior of VITE_APTOS_INDEXER_URL, so startup validation succeeds when
the Aptos feature is disabled and the environment variable is absent.

In `@src/plugins/aptos/index.tsx`:
- Around line 1-31: Rename the file from index.tsx to index.ts without changing
the register function or its plugin configuration, since the implementation
contains no JSX.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 86f6e5ba-4df3-45c3-8dad-4d8f05aa4bb1

📥 Commits

Reviewing files that changed from the base of the PR and between 473418a and 468ec7f.

⛔ Files ignored due to path filters (4)
  • packages/caip/src/adapters/coingecko/generated/aptos_861fb8e6/adapter.json is excluded by !**/generated/**
  • packages/caip/src/adapters/coingecko/generated/index.ts is excluded by !**/generated/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • src/components/MultiHopTrade/components/TradeInput/components/SwapperIcon/panora-icon.jpg is excluded by !**/*.jpg
📒 Files selected for processing (94)
  • .env
  • .env.development
  • .env.production
  • e2e/fixtures/aptos-chain-integration.yaml
  • headers/csps/chains/aptos.ts
  • headers/csps/chains/panora.ts
  • headers/csps/index.ts
  • packages/caip/src/adapters/coingecko/index.ts
  • packages/caip/src/adapters/coingecko/utils.ts
  • packages/caip/src/constants.ts
  • packages/chain-adapters/package.json
  • packages/chain-adapters/src/aptos/AptosChainAdapter.test.ts
  • packages/chain-adapters/src/aptos/AptosChainAdapter.ts
  • packages/chain-adapters/src/aptos/index.ts
  • packages/chain-adapters/src/aptos/types.ts
  • packages/chain-adapters/src/index.ts
  • packages/chain-adapters/src/types.ts
  • packages/chain-adapters/src/utils/ledgerAppGate.ts
  • packages/hdwallet-core/src/aptos.ts
  • packages/hdwallet-core/src/index.ts
  • packages/hdwallet-core/src/utils.ts
  • packages/hdwallet-core/src/wallet.ts
  • packages/hdwallet-native/src/aptos.ts
  • packages/hdwallet-native/src/crypto/isolation/adapters/aptos.ts
  • packages/hdwallet-native/src/native.ts
  • packages/public-api/src/routes/chains/types.ts
  • packages/public-api/src/routes/chains/utils.ts
  • packages/public-api/src/swapperDeps.ts
  • packages/swapper/package.json
  • packages/swapper/src/constants.ts
  • packages/swapper/src/index.ts
  • packages/swapper/src/swappers/ButterSwap/swapperApi/getTradeQuote.test.ts
  • packages/swapper/src/swappers/ButterSwap/swapperApi/getTradeRate.test.ts
  • packages/swapper/src/swappers/NearIntentsSwapper/NearIntentsSwapper.ts
  • packages/swapper/src/swappers/NearIntentsSwapper/endpoints.ts
  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.ts
  • packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeRate.ts
  • packages/swapper/src/swappers/NearIntentsSwapper/types.ts
  • packages/swapper/src/swappers/PanoraSwapper/PanoraSwapper.ts
  • packages/swapper/src/swappers/PanoraSwapper/endpoints.ts
  • packages/swapper/src/swappers/PanoraSwapper/index.ts
  • packages/swapper/src/swappers/PanoraSwapper/swapperApi/getPanoraTradeData.ts
  • packages/swapper/src/swappers/PanoraSwapper/swapperApi/getTradeQuote.ts
  • packages/swapper/src/swappers/PanoraSwapper/swapperApi/getTradeRate.ts
  • packages/swapper/src/swappers/PanoraSwapper/types.ts
  • packages/swapper/src/swappers/PanoraSwapper/utils/constants.ts
  • packages/swapper/src/swappers/PanoraSwapper/utils/helpers.ts
  • packages/swapper/src/swappers/PanoraSwapper/utils/panoraService.ts
  • packages/swapper/src/swappers/utils/test-data/cryptoMarketDataById.ts
  • packages/swapper/src/thorchain-utils/getL1RateOrQuote.ts
  • packages/swapper/src/types.ts
  • packages/swapper/src/utils.ts
  • packages/types/src/base.ts
  • packages/utils/src/assetData/baseAssets.ts
  • packages/utils/src/assetData/getBaseAsset.ts
  • packages/utils/src/chainIdToFeeAssetId.ts
  • packages/utils/src/getAssetNamespaceFromChainId.ts
  • packages/utils/src/getChainShortName.ts
  • packages/utils/src/getNativeFeeAssetReference.ts
  • scripts/generateAssetData/aptos/index.ts
  • scripts/generateAssetData/coingecko.ts
  • scripts/generateAssetData/generateAssetData.ts
  • scripts/generateAssetData/generateRelatedAssetIndex/generateChainRelatedAssetIndex.ts
  • scripts/generateAssetData/generateRelatedAssetIndex/generateRelatedAssetIndex.ts
  • scripts/generateAssetData/generateTrustWalletUrl/generateTrustWalletUrl.ts
  • src/components/Modals/Send/utils.ts
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeExecution.tsx
  • src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeNetworkFeeCryptoBaseUnit.tsx
  • src/components/MultiHopTrade/components/TradeInput/components/SwapperIcon/SwapperIcon.tsx
  • src/components/MultiHopTrade/hooks/useGetTradeQuotes/getTradeQuoteOrRateInput.ts
  • src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx
  • src/config.ts
  • src/constants/chains.ts
  • src/context/PluginProvider/PluginProvider.tsx
  • src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx
  • src/hooks/useWalletSupportsChain/useWalletSupportsChain.ts
  • src/lib/account/account.ts
  • src/lib/account/aptos.ts
  • src/lib/asset-service/service/AssetService.ts
  • src/lib/coingecko/constants.ts
  • src/lib/coingecko/utils.ts
  • src/lib/tradeExecution.ts
  • src/lib/utils/aptos.ts
  • src/pages/Markets/components/MarketsRow.tsx
  • src/pages/RFOX/components/Stake/Bridge/hooks/useRfoxBridge.ts
  • src/plugins/activePlugins.ts
  • src/plugins/aptos/index.tsx
  • src/state/apis/swapper/helpers/swapperApiHelpers.ts
  • src/state/helpers.ts
  • src/state/slices/opportunitiesSlice/mappings.ts
  • src/state/slices/portfolioSlice/utils/index.ts
  • src/state/slices/preferencesSlice/preferencesSlice.ts
  • src/test/mocks/store.ts
  • src/vite-env.d.ts

Starknet = 'starknet',
Tron = 'tron',
Sui = 'sui',
Aptos = 'aptos-network',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Fetch and search CoinGecko asset platforms for Aptos identifiers.

curl -s https://api.coingecko.com/api/v3/asset_platforms | jq '.[] | select(.id | contains("aptos"))'

Repository: shapeshift/web

Length of output: 614


Use CoinGecko’s Aptos platform id aptos. aptos-network does not match the asset platforms API response, so Aptos token lookups will fail.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/caip/src/adapters/coingecko/index.ts` at line 101, Update the Aptos
CoinGecko platform identifier in the relevant adapter enum or mapping from
aptos-network to aptos, preserving the existing lookup flow for other platforms.

Comment on lines +207 to +209
getTxHistory(): Promise<never> {
throw new Error('Aptos transaction history not yet implemented')
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the Aptos adapter and related interface/call sites
git ls-files 'packages/chain-adapters/src/aptos/*' \
  'packages/chain-adapters/src/*' | sed -n '1,200p'

echo
echo '--- outline AptosChainAdapter.ts ---'
ast-grep outline packages/chain-adapters/src/aptos/AptosChainAdapter.ts --view expanded || true

echo
echo '--- relevant lines ---'
cat -n packages/chain-adapters/src/aptos/AptosChainAdapter.ts | sed -n '180,225p'

echo
echo '--- search for getTxHistory usage / declaration ---'
rg -n "getTxHistory\s*\(" packages/chain-adapters/src packages -g'!**/dist/**' -g'!**/build/**' || true

Repository: shapeshift/web

Length of output: 22358


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the base adapter/interface to see the expected contract
rg -n "interface .*getTxHistory|abstract .*getTxHistory|getTxHistory\(" packages/chain-adapters/src -g'!**/dist/**' -g'!**/build/**' || true

echo
echo '--- AptosChainAdapter surrounding implementation ---'
cat -n packages/chain-adapters/src/aptos/AptosChainAdapter.ts | sed -n '1,260p'

Repository: shapeshift/web

Length of output: 13746


Return a rejected promise here
getTxHistory() throws before a promise is created, so adapter.getTxHistory().catch(...) will fail synchronously instead of returning a rejected promise. Return Promise.reject(...) or make the method async so callers can handle it uniformly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/chain-adapters/src/aptos/AptosChainAdapter.ts` around lines 207 -
209, Update AptosChainAdapter.getTxHistory() to return a rejected Promise for
the unimplemented operation instead of throwing synchronously, preserving the
existing error message and Promise<never> contract so callers can handle
failures with catch().

Comment on lines +211 to +235
private async estimateMaxGasAmount(
sender: string,
data: InputEntryFunctionData,
): Promise<bigint> {
const tx = await this.client.transaction.build.simple({
sender,
data,
options: { maxGasAmount: 2_000_000 },
})
const dummyPubKey = new Ed25519PublicKey('0x' + '00'.repeat(32))
const [sim] = await this.client.transaction.simulate.simple({
signerPublicKey: dummyPubKey,
transaction: tx,
options: { estimateGasUnitPrice: true, estimateMaxGasAmount: true },
})
// sim.max_gas_amount with estimateMaxGasAmount=true is the AFFORDABILITY ceiling
// (sender balance / gas_unit_price), NOT a recommendation. The real consumption is
// sim.gas_used. Apply the Aptos CLI 1.5x safety factor, capped by affordability.
const gasUsed = BigInt(sim?.gas_used ?? 0)
if (gasUsed === 0n) return MIN_MAX_GAS_AMOUNT
const ceiling = BigInt(sim?.max_gas_amount ?? 0)
const withBuffer = (gasUsed * 3n) / 2n
const recommended = ceiling > 0n && ceiling < withBuffer ? ceiling : withBuffer
return recommended > MIN_MAX_GAS_AMOUNT ? recommended : MIN_MAX_GAS_AMOUNT
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== File map =="
ast-grep outline packages/chain-adapters/src/aptos/AptosChainAdapter.ts --view expanded || true

echo
echo "== Relevant lines =="
sed -n '180,280p' packages/chain-adapters/src/aptos/AptosChainAdapter.ts

echo
echo "== Search for simulation handling =="
rg -n "simulate\.simple|success === false|vm_status|estimateMaxGasAmount|buildEntryFunctionApiTransaction" packages/chain-adapters/src/aptos -S

Repository: shapeshift/web

Length of output: 6591


🌐 Web query:

Aptos TypeScript SDK transaction.simulate.simple return success false error handling gas_used vm_status

💡 Result:

When using the Aptos TypeScript SDK, the aptos.transaction.simulate.simple() function allows you to preview a transaction's outcome—including success, gas usage, and potential errors—without executing it on-chain [1][2]. Error Handling and Simulation Results The simulate.simple function returns an array containing a simulation response object [3][4]. To properly handle simulation outcomes, you should explicitly check the success property of the result [5][6]. If success is false, the transaction would fail if submitted; in such cases, you should inspect the vm_status property to understand the specific cause of the failure [5][7][6]. Example Pattern: const [simResult] = await aptos.transaction.simulate.simple({ signerPublicKey: account.publicKey, transaction }); if (!simResult.success) { // Use simResult.vm_status to identify the error (e.g., INSUFFICIENT_BALANCE_FOR_TRANSACTION_FEE) throw new Error(Simulation failed: ${simResult.vm_status}); } Key Simulation Properties - success (boolean): Indicates whether the transaction would have succeeded or failed [7][6]. - vm_status (string): Provides the Virtual Machine status code or message, which is essential for diagnosing why a transaction failed [7][6]. - gas_used (string): Represents the total gas consumed by the transaction during simulation [7][6]. Note that Aptos represents u64 values as strings to maintain precision in JavaScript/TypeScript environments [7]. Gas Estimation You can use the gas_used value alongside gas_unit_price to estimate the actual cost in Octas: const gasUsed = parseInt(simResult.gas_used); const gasUnitPrice = parseInt(simResult.gas_unit_price); const estimatedCost = gasUsed * gasUnitPrice; If you encounter a status like INSUFFICIENT_BALANCE_FOR_TRANSACTION_FEE, it often indicates that your account lacks sufficient funds to cover the max possible gas fee specified in the transaction [8]. Always ensure you are checking vm_status to determine if the failure is due to logic errors, insufficient balance, or other network constraints [7][8].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== estimateMaxGasAmount and caller =="
sed -n '211,360p' packages/chain-adapters/src/aptos/AptosChainAdapter.ts

echo
echo "== success checks in aptos adapter =="
rg -n "success === false|vm_status|simulate\.simple|estimateMaxGasAmount" packages/chain-adapters/src/aptos/AptosChainAdapter.ts packages/chain-adapters/src/aptos -S

Repository: shapeshift/web

Length of output: 7181


🌐 Web query:

site:aptos.dev transaction.simulate.simple success vm_status gas_used Aptos TypeScript SDK

💡 Result:

In the Aptos TypeScript SDK, the aptos.transaction.simulate.simple method returns an array of transaction responses, typically accessed as const [userTransactionResponse] = await aptos.transaction.simulate.simple(...) [1][2]. The userTransactionResponse object includes critical execution details, specifically: - gas_used: This field provides the actual amount of gas units consumed by the transaction during simulation [3][4]. It is essential for estimating the total gas fee when multiplied by the gas_unit_price [2][4]. - vm_status: This field indicates the result of the Virtual Machine (VM) execution [3]. It provides information on whether the transaction simulation succeeded or failed, and if it failed, it often contains the specific VM error code or status details [3][4]. By inspecting these fields in the simulation response, you can preview the transaction's resource consumption and verify its execution status without actually submitting the transaction to the ledger or incurring real fees [5][1][4]. This is particularly useful for debugging or fine-tuning transaction parameters like maxGasAmount and gasUnitPrice before formal submission [3][6].

Citations:


🌐 Web query:

Aptos TypeScript SDK simulate.simple return fields success gas_used vm_status docs

💡 Result:

In the Aptos TypeScript SDK, the aptos.transaction.simulate.simple method allows you to preview the results of a transaction without submitting it to the ledger or incurring actual fees [1][2]. When you call this method, it returns a simulation response that contains critical information regarding the transaction's potential execution [2][3]. The key fields available in the returned response include: success: A boolean value indicating whether the transaction would succeed (true) or fail (false) [3][4]. gas_used: A string representing the amount of gas that would be consumed by the transaction if it were executed [3][4]. vm_status: A string providing the Virtual Machine (VM) status, which is particularly useful for debugging or understanding the reason for a transaction failure [3][4]. You can typically access these fields directly from the result object returned by the simulation [3]. For example: const [simulationResult] = await aptos.transaction.simulate.simple({ signerPublicKey: signer.publicKey, transaction, }); console.log(Success: ${simulationResult.success}); console.log(Gas used: ${simulationResult.gas_used}); console.log(VM Status: ${simulationResult.vm_status}); Because gas_used is returned as a string, it is common practice to parse it into an integer (e.g., parseInt(simulationResult.gas_used)) if you need to perform calculations with the value, such as estimating total gas costs [3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '370,530p' packages/chain-adapters/src/aptos/AptosChainAdapter.ts

Repository: shapeshift/web

Length of output: 5159


Check sim.success before using simulation gas. Failed Aptos simulations still expose gas_used/max_gas_amount, so estimateMaxGasAmount can return a signable tx for an operation the preflight already marks as failed. Throw with sim.vm_status instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/chain-adapters/src/aptos/AptosChainAdapter.ts` around lines 211 -
235, In estimateMaxGasAmount, check sim.success immediately after simulation and
before reading gas_used or max_gas_amount; when false, throw an error containing
sim.vm_status. Preserve the existing gas calculation only for successful
simulations.

Comment on lines +268 to +281
buildSendApiTransaction(
input: BuildSendApiTxInput<KnownChainIds.AptosMainnet>,
): Promise<SignTx<KnownChainIds.AptosMainnet>> {
const { from, accountNumber, to, value, chainSpecific } = input
const coinType = chainSpecific?.coinType ?? APT_COIN_TYPE

const data: InputEntryFunctionData = {
function: '0x1::aptos_account::transfer_coins',
typeArguments: [coinType],
functionArguments: [to, BigInt(value)],
}

return this.buildEntryFunctionApiTransaction({ from, accountNumber, data })
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

buildSendApiTransaction needs to branch for FA-only Aptos assets
chainSpecific.coinType can be a bare FA metadata address, but this method always passes it to 0x1::aptos_account::transfer_coins as a Move type argument. That works for CoinStore-backed assets only; pure FA assets will produce an invalid payload. Route FA-only transfers through the fungible-asset entry function instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/chain-adapters/src/aptos/AptosChainAdapter.ts` around lines 268 -
281, Update buildSendApiTransaction to distinguish FA-only assets from
CoinStore-backed coin types: retain the existing aptos_account::transfer_coins
payload for standard coins, but route bare FA metadata addresses through the
appropriate fungible-asset transfer entry function with its expected arguments.
Use the existing chainSpecific information and established FA
transaction-building symbols where available.

Comment on lines +38 to +40
aptosWipe() {
this.aptosAdapter = undefined
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add an explicit return type for aptosWipe.

As per coding guidelines, always use explicit types for function parameters and return values in TypeScript.

♻️ Proposed fix
-    aptosWipe() {
+    aptosWipe(): void {
       this.aptosAdapter = undefined
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
aptosWipe() {
this.aptosAdapter = undefined
}
aptosWipe(): void {
this.aptosAdapter = undefined
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/hdwallet-native/src/aptos.ts` around lines 38 - 40, Update the
aptosWipe method to declare an explicit void return type while preserving its
existing behavior of clearing aptosAdapter.

Source: Coding guidelines

assertGetNearChainAdapter: () => vi.fn() as any,
assertGetStarknetChainAdapter: () => vi.fn() as any,
assertGetTonChainAdapter: () => vi.fn() as any,
assertGetAptosChainAdapter: () => vi.fn() as any,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Avoid using any for type assertions.

All three files use as any when mocking the assertGetAptosChainAdapter dependency. As per coding guidelines, you should "NEVER use any type unless absolutely necessary" and "ALWAYS use unknown instead of any".

  • packages/swapper/src/swappers/ButterSwap/swapperApi/getTradeQuote.test.ts#L46-L46: Replace as any with as unknown as ReturnType<SwapperDeps['assertGetAptosChainAdapter']> (or as unknown as ReturnType<typeof vi.fn>).
  • packages/swapper/src/swappers/ButterSwap/swapperApi/getTradeRate.test.ts#L35-L35: Apply the same type assertion fix.
  • packages/swapper/src/swappers/ButterSwap/swapperApi/getTradeRate.test.ts#L80-L80: Apply the same type assertion fix.
📍 Affects 2 files
  • packages/swapper/src/swappers/ButterSwap/swapperApi/getTradeQuote.test.ts#L46-L46 (this comment)
  • packages/swapper/src/swappers/ButterSwap/swapperApi/getTradeRate.test.ts#L35-L35
  • packages/swapper/src/swappers/ButterSwap/swapperApi/getTradeRate.test.ts#L80-L80
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/swapper/src/swappers/ButterSwap/swapperApi/getTradeQuote.test.ts` at
line 46, Replace the any assertions used for mocked assertGetAptosChainAdapter
dependencies with unknown-based assertions typed as
ReturnType<SwapperDeps['assertGetAptosChainAdapter']> or ReturnType<typeof
vi.fn>. Apply this change at
packages/swapper/src/swappers/ButterSwap/swapperApi/getTradeQuote.test.ts:46 and
both locations at
packages/swapper/src/swappers/ButterSwap/swapperApi/getTradeRate.test.ts:35 and
80.

Source: Coding guidelines

Comment thread packages/swapper/src/swappers/PanoraSwapper/utils/panoraService.ts Outdated
sui: 'sui',
near: 'near',
ton: 'ton',
aptos: 'aptos',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

git ls-files 'scripts/generateAssetData/generateTrustWalletUrl/*' 'scripts/generateAssetData/**/*TrustWallet*' 'scripts/generateAssetData/**/*aptos*' | sed 's#^`#-` #'
echo
ast-grep outline scripts/generateAssetData/generateTrustWalletUrl/generateTrustWalletUrl.ts --view expanded || true
echo
cat -n scripts/generateAssetData/generateTrustWalletUrl/generateTrustWalletUrl.ts
echo
rg -n "aptos|chainReference|assetReference|blockchains/.*/assets|trust wallet" scripts/generateAssetData -S

Repository: shapeshift/web

Length of output: 6614


🏁 Script executed:

#!/bin/bash
set -euo pipefail
cat -n scripts/generateAssetData/generateTrustWalletUrl/generateTrustWalletUrl.ts | sed -n '1,220p'

Repository: shapeshift/web

Length of output: 1519


🏁 Script executed:

#!/bin/bash
set -euo pipefail

cat -n scripts/generateAssetData/generateTrustWalletUrl/generateTrustWalletUrl.ts | sed -n '1,220p'

Repository: shapeshift/web

Length of output: 1519


🌐 Web query:

Trust Wallet assets Aptos blockchains/aptos assets info.json aptos assetReference path layout

💡 Result:

In the Trust Wallet assets repository (github.com/trustwallet/assets), assets are organized hierarchically under the blockchains directory. For the Aptos blockchain, the directory structure follows this path layout: blockchains/aptos/assets/<asset_address>/ Within the specific asset folder, two files are required [1][2]: 1. info.json: Contains metadata about the token [1][2]. 2. logo.png: The visual representation of the asset [1][2]. The info.json file serves as the template for token details [3]. To add a new asset, developers typically use the repository's Makefile commands (e.g., make add-token asset_id=...), which automate the creation of the necessary info.json template [3]. The repository configuration explicitly mandates that asset folders contain only logo.png and info.json files [2]. You can find additional technical documentation on the Trust Developers portal for listing new assets [4].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "generateTrustWalletUrl\(" scripts src . -S

Repository: shapeshift/web

Length of output: 1492


🌐 Web query:

Trust Wallet assets Aptos native coin blockchains/aptos/assets info.json AptosCoin 0x1

💡 Result:

In the context of the Trust Wallet assets repository, the Aptos native coin (APT) is identified by the type string 0x1::aptos_coin::AptosCoin [1][2]. The Trust Wallet assets repository organizes tokens within the blockchains folder [3][4]. For networks like Aptos, assets are structured using their specific identifiers rather than Ethereum-style contract addresses [3][4]. While Trust Wallet's official documentation notes that Ethereum-like assets use a checksummed address format for their folder names and info.json files [5][3], the Aptos native coin is defined at the protocol level by the module 0x1::aptos_coin and the resource type AptosCoin [6][7]. For integration purposes, Aptos coins utilize the type format

::<module_name>::<coin_name> [8][2]. The specific identifier for the native APT coin is: 0x1::aptos_coin::AptosCoin Technical documentation from Aptos Labs confirms this is the native token initialized during genesis [6]. Developers integrating with Trust Wallet should refer to the Trust Wallet Assets repository structure for how these assets are registered [9][3], noting that Aptos support has been expanded to include fungible assets [10].

Citations:


Handle the Aptos asset reference here. Trust Wallet’s Aptos assets live under blockchains/aptos/assets/<asset_address>/info.json, but this branch never appends the Aptos assetReference, so all Aptos AssetIds fall back to the same .../blockchains/aptos/assets/info.json URL. Add Aptos-specific native/token handling and tests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/generateAssetData/generateTrustWalletUrl/generateTrustWalletUrl.ts`
at line 18, Update the Aptos entry in the Trust Wallet URL generation logic to
append the assetReference for both native and token assets, producing the
blockchains/aptos/assets/<asset_address>/info.json path instead of the base
assets/info.json path. Add focused tests covering Aptos native and token
AssetIds and verify other chain URL behavior remains unchanged.

Comment on lines +215 to +220
case KnownChainIds.AptosMainnet: {
const aptosTxStatus = await getAptosTransactionStatus(txHash)
isConfirmed =
aptosTxStatus === TxStatus.Confirmed || aptosTxStatus === TxStatus.Failed
break
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Properly handle failed Aptos transactions.

Currently, if an Aptos transaction fails, isConfirmed is set to true, which mistakenly marks the action as completely successful in the UI. Instead, use the existing failAction callback to accurately report failures, similar to how it is handled for TON and Starknet.

🛠️ Proposed fix
                 case KnownChainIds.AptosMainnet: {
                   const aptosTxStatus = await getAptosTransactionStatus(txHash)
-                  isConfirmed =
-                    aptosTxStatus === TxStatus.Confirmed || aptosTxStatus === TxStatus.Failed
+
+                  if (aptosTxStatus === TxStatus.Failed) {
+                    failAction(action)
+
+                    const intervalId = pollingIntervalsRef.current.get(pollingKey)
+                    if (intervalId) {
+                      clearInterval(intervalId)
+                      pollingIntervalsRef.current.delete(pollingKey)
+                    }
+                    return
+                  }
+
+                  isConfirmed = aptosTxStatus === TxStatus.Confirmed
                   break
                 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case KnownChainIds.AptosMainnet: {
const aptosTxStatus = await getAptosTransactionStatus(txHash)
isConfirmed =
aptosTxStatus === TxStatus.Confirmed || aptosTxStatus === TxStatus.Failed
break
}
case KnownChainIds.AptosMainnet: {
const aptosTxStatus = await getAptosTransactionStatus(txHash)
if (aptosTxStatus === TxStatus.Failed) {
failAction(action)
const intervalId = pollingIntervalsRef.current.get(pollingKey)
if (intervalId) {
clearInterval(intervalId)
pollingIntervalsRef.current.delete(pollingKey)
}
return
}
isConfirmed = aptosTxStatus === TxStatus.Confirmed
break
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/useActionCenterSubscribers/useSendActionSubscriber.tsx` around
lines 215 - 220, Update the AptosMainnet branch in the transaction-status
handling to invoke the existing failAction callback when
getAptosTransactionStatus returns TxStatus.Failed, rather than treating the
failure as successful confirmation. Preserve isConfirmed for TxStatus.Confirmed
and keep the existing behavior for other statuses, matching the TON and Starknet
failure handling.

Comment thread src/lib/utils/aptos.ts
import { aptosChainId } from '@shapeshiftoss/caip'
import type { aptos } from '@shapeshiftoss/chain-adapters'
import type { KnownChainIds } from '@shapeshiftoss/types'
import { TxStatus } from 'packages/unchained-client/src/types'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Fix import path for TxStatus.

Importing directly from packages/unchained-client/src/types circumvents package boundaries and workspaces configuration. Please use the standard @shapeshiftoss namespace import instead.

🛠️ Proposed fix
-import { TxStatus } from 'packages/unchained-client/src/types'
+import { TxStatus } from '`@shapeshiftoss/unchained-client`'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { TxStatus } from 'packages/unchained-client/src/types'
import { TxStatus } from '`@shapeshiftoss/unchained-client`'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/utils/aptos.ts` at line 5, Update the TxStatus import in aptos.ts to
use the standard `@shapeshiftoss` package namespace instead of the direct
packages/unchained-client/src/types path, preserving the existing symbol usage.

@swdiscordia
swdiscordia force-pushed the feat/panora-swapper branch from 468ec7f to e013ce3 Compare July 14, 2026 09:37
@swdiscordia

Copy link
Copy Markdown
Contributor Author

Pushed a conformity pass against the swapper integration contract:

  • The Panora API key now lives in VITE_PANORA_API_KEY (SwapperConfig + config validation + public-api env) instead of being hardcoded in the service, matching the BOB Gateway pattern. Note for anyone copying it into another env file: the key contains # characters, so the value must stay quoted or dotenv truncates it and every quote 401s.
  • CSP moved from headers/csps/chains/panora.ts to headers/csps/defi/swappers/Panora.ts where swapper policies live.

Re-verified quotes end to end in the app after the change (APT to USDC via Panora, key threaded through deps.config).

@swdiscordia

Copy link
Copy Markdown
Contributor Author

Swap execution verified end to end on Aptos mainnet with a dev wallet: 0.1 APT swapped to USDC through the Panora router from the trade UI. The BCS transaction built by the new buildEntryFunctionApiTransaction signed and broadcast correctly, and checkTradeStatus polled the on-chain status through to complete. Rate vs executed output delta was within slippage tolerance.

@linear linear Bot mentioned this pull request Jul 14, 2026
13 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant