Skip to content

feat(chain-adapters): add Aptos chain integration with NEAR Intents support#12349

Open
swdiscordia wants to merge 13 commits into
shapeshift:developfrom
swdiscordia:feat/aptos-support
Open

feat(chain-adapters): add Aptos chain integration with NEAR Intents support#12349
swdiscordia wants to merge 13 commits into
shapeshift:developfrom
swdiscordia:feat/aptos-support

Conversation

@swdiscordia
Copy link
Copy Markdown
Contributor

@swdiscordia swdiscordia commented May 16, 2026

Description

Adds first-class Aptos blockchain support to ShapeShift Web, plus NEAR Intents routing for Aptos so users can swap into/out of APT and Aptos-native assets via solver-paid cross-chain intents.

Scope of this PR (10 commits):

  • HDWallet (Native): new hdwallet-core Aptos interfaces, SLIP-44 637, supportsAptos / infoAptos; hdwallet-native Ed25519 + SHA3-256 AptosAdapter with mixins wired into native.ts (initialize, wipe, describePath).
  • CAIP / types / utils: Aptos CAIP constants, chain ids, account/address types, helpers.
  • Chain adapter: full AptosChainAdapter (account discovery, balances, BCS-encoded SimpleTransaction.submit.simple, fee estimation, broadcast). 19/19 unit tests pass.
  • Plugin & app wire-up: Aptos plugin, VITE_FEATURE_APTOS flag, CSP headers, asset generation from the Panora token list, CoinGecko market data adapter, treasury / base assets, indexer URL.
  • App integration: portfolio account derivation, send modal, trade execution dispatch, RFOX bridge, state migrations bump (v334).
  • Swapper plumbing: Aptos swapper types added to Swapper / SwapperApi.
  • NEAR Intents Aptos route (web-xeq.3): solver routing for USDC/ETH/etc. ↔ APT and Aptos-native assets.
  • qabot fixture (web-xeq.4): e2e/fixtures/aptos-chain-integration.yaml for future automated regression.
  • Bug fix: Aptos fee estimation now uses sim.gas_used * 1.5 (Aptos CLI safety factor) instead of max_gas_amount, which the node returns as the sender's affordability ceiling and inflated displayed fees by 100–300×.
  • Chore: regenerate pnpm-lock.yaml.

Beads references: web-xeq.1 (chain adapter), web-xeq.3 (NEAR Intents Aptos route), web-xeq.4 (qabot fixtures).

Not in scope (deferred to follow-up PRs):

  • PanoraSwapper (Aptos-native DEX aggregator, web-xeq.2) — deferred to a separate stacked follow-up PR to keep this one reviewable. This PR ships the chain + NEAR Intents path only. Cross-chain swap into/out of Aptos already works end-to-end via NEAR Intents (verified manually — see Testing).
  • web-xeq.5 (external blockers) is also not in this PR.

Commit message numbering note: Earlier commits cite web-ohh.X numbers — that namespace does not exist in beads. The authoritative beads are web-xeq.* as listed above.

Issue (if applicable)

closes #12348

Risk

High Risk PRs Require 2 approvals

This is a HIGH-RISK PR and should carry the High-Risk label + 2 reviewer approvals per the template warning. It introduces a brand-new on-chain transaction type and signing path:

  • New on-chain transaction type: BCS-encoded Aptos SimpleTransaction.submit.simple (signed payloads, sequence numbers, gas params).
  • New HDWallet implementation: Ed25519 + SHA3-256 derivation in hdwallet-native with SLIP-44 637 wired through core, native, mixins, and the wallet info interface (supportsAptos, infoAptos).
  • New AptosChainAdapter: account discovery, fee estimation, signing, broadcast, balance reads — fresh code, not reusing an existing adapter.
  • New trade execution path: Aptos signing dispatch added to tradeExecution.ts; Aptos swapper types threaded through Swapper / SwapperApi.
  • New Send modal path: APT / Aptos-native asset send flow.
  • NEAR Intents Aptos routing: solver-paid cross-chain swaps where the destination is Aptos.
  • State migrations bump (v334) to absorb the new portfolio account namespace.

Risk is contained by feature flag (see Operations) — VITE_FEATURE_APTOS=false in .env.production, so prod users do not see Aptos until the flag is flipped.

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

  • Protocols: NEAR Intents (new Aptos route added — affects existing NEAR Intents code paths via the swapper deps ripple, including ButterSwap test mocks). No EVM / Cosmos / UTXO / Solana / Sui protocol changes.
  • Transaction types: net-new Aptos SimpleTransaction BCS-signed transfers. Existing tx types unchanged.
  • Wallets: hdwallet-core (new Aptos interfaces) and hdwallet-native (new adapter + mixins + native.ts init/wipe/describePath wiring). Wallets without Aptos support gracefully hide the chain via supportsAptos(wallet) === false.
  • Contract interactions: none on EVM. On Aptos, uses standard 0x1::aptos_account::transfer_coins for native sends; cross-chain swaps go through the NEAR Intents solver (no direct Aptos contract write from the swapper).
  • Asset universe: ~80 Aptos tokens added via Panora token list; CoinGecko market data extended.
  • State: migrations bumped to v334.

Testing

Engineering

Local setup:

  1. Pull the branch feat/aptos-support and pnpm install.
  2. VITE_FEATURE_APTOS=true is already set in .env.development — no extra config needed.
  3. pnpm dev.
  4. Open the Trade page and connect a Native wallet (test mnemonic is fine — no Aptos funds required for steps 5–7).
  5. Manage Accounts modal → verify Aptos appears alongside EVM / Cosmos / UTXO / Solana / Sui chains; toggling adds an Aptos account row.
  6. Asset picker → search APT → verify the entry shows Aptos branding (network icon + name).
  7. Buy asset picker → chain filter → Aptos → verify roughly ~80 Aptos tokens are listed (sourced from Panora).
  8. End-to-end swap (optional, requires a funded wallet): on a Native wallet with a small USDC balance on Arbitrum, swap USDC (Arbitrum) → APT (Aptos) via the NEAR Intents route. The destination Aptos account is auto-derived; the solver pays Aptos gas. A reverse swap APT → USDC also works on a wallet funded with APT.

Automated checks (all green on this branch):

  • pnpm run type-check0 errors.
  • pnpm run lint0 errors (9 pre-existing warnings unrelated to this PR).
  • pnpm exec vitest run packages/chain-adapters/src/aptos19 / 19 pass.
  • e2e/fixtures/aptos-chain-integration.yaml is included for future qabot runs (web-xeq.4).

Manual end-to-end verification performed by the author on a real Aptos-funded wallet (Native):

  • USDC (Arbitrum) → APT (Aptos) via NEAR Intents — completed successfully, swap processed on-chain.
  • Aptos account discovery via Manage Accounts works.
  • APT balance reads correctly (test wallet shows 0.04119354 APT).
  • Aptos chain appears in the chain selector and in the buy asset picker's chain filter.
  • Trade UI is functional end-to-end: Preview Trade → Confirm Details → Sign & Swap → Processing (screenshots below).

Operations

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

Ship state of feature flags:

  • .env.production: VITE_FEATURE_APTOS=false
  • .env.development: VITE_FEATURE_APTOS=true

Post-flag-flip operations checklist (when ops is ready to enable Aptos in prod):

  1. Native wallet APT: receive (deposit modal QR + address), display balance, send to another Aptos address — confirm tx on-chain and verify gas/fee match the in-app preview (fee should be ~milli-APT, not ~APT — this is the bug fixed in the fix(aptos) commit).
  2. Cross-chain swap via NEAR Intents: USDC / ETH → APT (in) and APT → USDC / ETH (out). Confirm both directions process and balances settle.
  3. Aptos-native cross-chain via NEAR Intents: try at least one non-APT Aptos token (e.g. USDC on Aptos) in both directions.
  4. No regressions on existing chains: smoke a swap on each of the major existing rails — EVM (Ethereum or Arbitrum), Cosmos (THORChain or native Cosmos), Solana, and Sui — to confirm no swapper/wallet ripple from the AptosSwapperDeps plumbing or the v334 migrations.
  5. Non-supporting wallets (KeepKey, Phantom, WalletConnect, Ledger, etc.): connect each and confirm Aptos is correctly hidden / disabled (no crash, no empty account row).

Screenshots (if applicable)

Accounts — Aptos in Native wallet
Test wallet showing the Aptos account discovered with balance.

Trade — USDC Arbitrum → APT Aptos via NEAR Intents
Quote loaded, route shows NEAR Intents.

Confirm Details
Swap via NEAR Intents in ~40s.

Sign & Swap
Estimated completion 40s, transaction fee + receive address visible.

Processing
"Your swap of 1 USDC to 1.043159 APT is being processed."

Success — full cross-chain swap proof (both legs on-chain)

NEAR Intents is an off-chain intent-matching protocol, so the "trade" itself does not appear as a single on-chain event — it materialises as (1) a USDC send on Arbitrum to a NEAR Intents deposit address and (2) a corresponding APT receive on Aptos delivered by a solver. Both legs are visible and linked by amount + timing:

Leg 1 — Source: USDC send on Arbitrum (signed by the test wallet)

Leg 2 — Destination: APT receive on Aptos (fulfilled by a solver ~15s later)

  • Tx: 0x41e1c62345fbfc0397998b0191c4501ede1475f3446f89e2abc59f9beb0571b5
  • Version 5300181646, 2026-05-16T21:28:07 UTC (15 seconds after the Arbitrum send)
  • 0x1::aptos_account::transfer_coins(AptosCoin, 0x304ba231…, 104_315_877) — exactly 1.04315877 APT to the test wallet's Aptos account
  • Sender: a solver-pattern address 0xd1a1c180…1af6446 (5,320 prior txs, all transfer_coins/transfer_fungible_assets)
  • Status: Success, gas used 151
  • Aptos Explorer (UI flakes occasionally, raw JSON is source of truth):
    • By hash
    • By version
    • Raw JSON: https://fullnode.mainnet.aptoslabs.com/v1/transactions/by_version/5300181646

The output amount 1.04315877 APT matches exactly the 1.043159 APT quoted in the Sign & Swap screen above. Combined with the 15-second source→destination gap, this proves the NEAR Intents solver path round-tripped successfully end-to-end.

Aptos Explorer — destination leg


Known unrelated issues

The pre-trade warning "Make sure you have ETH in your Arbitrum One account, you'll need it for transactions" misfires for NEAR Intents trades that originate via deposit-to-address (the solver pays destination gas, and the user only needs the source asset on the source chain — not gas on the destination). Origin: src/components/MultiHopTrade/components/TradeInput/components/ConfirmSummary.tsx:270-284. This is not Aptos-specific — it also affects THORChain / Chainflip / NEAR Intents flows generally. Will be addressed in a separate follow-up PR; out of scope here.

Summary by CodeRabbit

  • New Features

    • Full Aptos mainnet support: wallet integration, account discovery/derivation, native APT and token balances
    • Trade and swap Aptos assets (quote, fee estimation, unsigned tx builder, sign & broadcast)
    • Aptos assets appear in portfolio, asset search, popular assets, and market listings
    • Plugin/adapter support for hardware wallets (Aptos signing/paths)
  • Bug Fixes

    • Improved Ledger handling to avoid errors on unsupported wallets

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 16, 2026

Warning

Rate limit exceeded

@swdiscordia has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 43 minutes and 38 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 070049cc-f481-4070-ae63-fb9106bd3172

📥 Commits

Reviewing files that changed from the base of the PR and between f37f911 and aa50930.

📒 Files selected for processing (2)
  • scripts/generateAssetData/aptos/index.ts
  • scripts/generateAssetData/coingecko.ts
📝 Walkthrough

Walkthrough

Adds feature-flagged Aptos chain support: CAIP identifiers and assets, HDWallet Ed25519 support, Aptos chain adapter (sign/broadcast/parse/fees) and tests, swapper/NEAR Intents wiring, asset generation/CoinGecko mapping, UI/state/plugin integration, CSP and env configuration.

Changes

Aptos Chain Integration

Layer / File(s) Summary
Environment, config and CSP
.env, .env.development, .env.production, src/config.ts, src/vite-env.d.ts, headers/csps/chains/aptos.ts, headers/csps/index.ts
Add VITE_FEATURE_APTOS, node/indexer URLs, config validators, Vite env typings, and CSP connect-src for Aptos endpoints.
CAIP constants & asset generation
packages/caip/src/constants.ts, packages/types/src/base.ts, packages/utils/src/assetData/*, scripts/generateAssetData/*, packages/caip/src/adapters/coingecko/*
Register Aptos chain/asset IDs and namespaces, base APT asset, CoinGecko platform mapping, and include Aptos assets in generation scripts and related-asset mappings.
HDWallet core & native adapter
packages/hdwallet-core/src/aptos.ts, packages/hdwallet-core/src/utils.ts, packages/hdwallet-core/src/wallet.ts, packages/hdwallet-native/src/crypto/isolation/adapters/aptos.ts, packages/hdwallet-native/src/aptos.ts, packages/hdwallet-native/src/native.ts
Define Aptos wallet interfaces, SLIP-44 637 mapping, path helpers, and implement AptosAdapter for Ed25519 key derivation, SHA3 address derivation, and signing; wire mixins into native wallet.
Aptos ChainAdapter & types
packages/chain-adapters/src/aptos/types.ts, packages/chain-adapters/src/aptos/AptosChainAdapter.ts, packages/chain-adapters/src/aptos/AptosChainAdapter.test.ts, packages/chain-adapters/src/aptos/index.ts, packages/chain-adapters/src/index.ts
Add Aptos-specific adapter types; implement ChainAdapter with address derivation, account balances, fee estimation, tx build/sign/broadcast, payload->asset mapping, and comprehensive Vitest coverage.
Swapper types, utils and NearIntents endpoints
packages/swapper/src/types.ts, packages/swapper/src/utils.ts, packages/swapper/src/swappers/NearIntentsSwapper/*, packages/public-api/src/swapperDeps.ts
Introduce Aptos swapper types/deps, execute/check helpers, NEAR Intents getUnsignedAptosTransaction/getAptosTransactionFees, and wire assertGetAptosChainAdapter into swapper deps and test mocks.
App wiring, UI and state
src/plugins/aptos/index.tsx, src/plugins/activePlugins.ts, src/lib/account/aptos.ts, src/lib/account/account.ts, src/state/slices/*, src/components/*, src/lib/utils/aptos.ts, src/lib/tradeExecution.ts, src/components/Modals/Send/utils.ts, src/components/MultiHopTrade/*, src/hooks/*, src/pages/*, e2e/fixtures/aptos-chain-integration.yaml
Register Aptos plugin, gate features by flag, derive Aptos accounts, include Aptos in portfolio/assets/send/trade flows, add status polling, and provide e2e fixture.
Tests & mocks
packages/chain-adapters/src/aptos/AptosChainAdapter.test.ts, packages/swapper/src/swappers/*/getTradeQuote.test.ts, getTradeRate.test.ts, src/test/mocks/store.ts
Add and update tests/mocks to include Aptos deps and adapter behavior.
Misc & utility fixes
packages/chain-adapters/src/utils/ledgerAppGate.ts, packages/utils/*, packages/caip/*
Adjust ledger app gating for non-Ledger wallets and extend various utility mappings to support Aptos.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • shapeshift/web#12338: Modifies same NearIntents swap quote logic; related at packages/swapper/src/swappers/NearIntentsSwapper/swapperApi/getTradeQuote.ts.

"I've hopped a new chain into the fur—
Ed25519 keys make networks purr.
Flags set low in prod's domain,
Yet devs can test Aptos' gain. 🥕✨"

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Discostu added 7 commits May 17, 2026 01:26
- 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
@swdiscordia swdiscordia force-pushed the feat/aptos-support branch from d37ebe6 to f00e21c Compare May 16, 2026 23:29
swdiscordia and others added 3 commits May 17, 2026 02:03
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>
The Aptos Ledger HDWallet integration was deferred to a follow-up PR
(static analysis surfaced 5 show-stopper bugs that need hardware
testing to validate). Drops the @ledgerhq/hw-app-aptos dependency and
its orphan lockfile entries.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@swdiscordia swdiscordia force-pushed the feat/aptos-support branch from f00e21c to d577262 Compare May 17, 2026 00:04
@swdiscordia swdiscordia marked this pull request as ready for review May 17, 2026 00:07
@swdiscordia swdiscordia requested a review from a team as a code owner May 17, 2026 00:07
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🤖 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/chain-adapters/src/aptos/AptosChainAdapter.ts`:
- Around line 197-215: Replace the manual regex-based validation in
validateAddress with the Aptos SDK's AccountAddress.fromString() call: call
AccountAddress.fromString(address) inside validateAddress (in try/catch) and
return valid=true when it succeeds, otherwise catch the thrown error and return
valid=false; ensure you still return the appropriate
ValidAddressResultType.Valid or ValidAddressResultType.Invalid values and keep
the method's Promise-based signature. Use the validateAddress function name and
AccountAddress.fromString symbol to locate where to change the logic.
- Around line 504-505: The current status assignment in AptosChainAdapter.ts
uses tx.success falsiness and treats undefined as Confirmed; change the logic in
the method where `tx` is processed (the line assigning `const status =
tx.success === false ? TxStatus.Failed : TxStatus.Confirmed`) to explicitly
handle three cases: if `tx.success === true` set TxStatus.Confirmed; if
`tx.success === false` set TxStatus.Failed; otherwise (undefined) set
TxStatus.Pending, and ensure any fields derived from confirmation (confirmedAt,
confirmations count) are only populated when status is Confirmed.
- Around line 521-523: Replace direct string comparisons of Aptos addresses with
AccountAddress.equals(): import AccountAddress from '`@aptos-labs/ts-sdk`',
construct AccountAddress instances for the values created in AptosChainAdapter
(e.g., for recipient and sender variables defined in the block with const
recipient = String(...), const sender = tx.sender ?? ''), and compare using
AccountAddress.fromHex(recipient).equals(AccountAddress.fromHex(sender)) (or the
appropriate AccountAddress.fromX factory used in the project) wherever the code
currently does string equality (notably the comparisons referenced around the
recipient/amount/sender handling at the later checks), so address format/casing
differences are handled reliably.

In `@packages/hdwallet-native/src/aptos.ts`:
- Around line 19-21: Replace the thrown Error in aptosNextAccountPath with a
delegation to the core helper: call and return core.aptosNextAccountPath(_msg)
(or the appropriate core helper that computes the next Aptos account path) so
the mixin uses the shared logic instead of throwing.

In `@packages/swapper/src/swappers/NearIntentsSwapper/endpoints.ts`:
- Around line 399-405: The current call to adapter.buildSendApiTransaction(...)
passes an empty chainSpecific causing Aptos transfers to default to APT; detect
when the route/asset is a non-native Aptos token and populate chainSpecific with
the coin type string (the token's coin type identifier) before calling
adapter.buildSendApiTransaction (similar to how tokenId is passed for Solana).
Update the call site that invokes buildSendApiTransaction to supply
chainSpecific: { coinType: <asset.coinType or route.token.coinType> } for
non-native Aptos assets while keeping it empty for native APT.

In `@packages/swapper/src/utils.ts`:
- Around line 535-537: The receive-transfer detection uses
t.to.includes(address) which can produce substring matches; change
receiveTransfer lookup in the tx.transfers scan (function/variable
receiveTransfer, TransferType.Receive) to perform an exact Aptos address
equality by normalizing both sides (ensure consistent 0x prefix and lowercase)
and comparing with === (or array membership on a normalized array if t.to is an
array), so you only match the exact recipient address.

In `@packages/utils/src/treasury.ts`:
- Around line 22-23: treasuryChainIds currently includes
KnownChainIds.AptosMainnet while the corresponding Aptos entry in the treasury
address mapping uses a placeholder/dead address; either remove
KnownChainIds.AptosMainnet from the treasuryChainIds array until you have the
real treasury address, or update the Aptos address constant in the
TREASURY_ADDRESSES (or equivalent Aptos address constant) to the correct live
treasury address; locate the treasuryChainIds array and the Aptos address
constant in this module and make the change so an enabled chain never points at
a placeholder address.

In `@src/context/WalletProvider/Ledger/constants.ts`:
- Line 45: availableLedgerAppAssetIds currently includes aptosAssetId when
VITE_FEATURE_APTOS is enabled but LedgerHDWallet does not implement Aptos
support (LedgerHDWallet, _supportsAptos, supportsAptos), causing false
positives; remove the conditional inclusion of aptosAssetId from the
availableLedgerAppAssetIds array (i.e., delete the
...(getConfig().VITE_FEATURE_APTOS ? [aptosAssetId] : []), entry) so Ledger is
no longer advertised as supporting Aptos until LedgerHDWallet implements Aptos
support and sets _supportsAptos = true and/or implements the AptosWallet
interface.

In `@src/lib/utils/aptos.ts`:
- Around line 9-12: The isAptosChainAdapter type guard calls getChainId without
ensuring that method exists, which can throw for plain objects; update
isAptosChainAdapter to first check that chainAdapter is non-null object and that
(chainAdapter as any).getChainId is a function (e.g., typeof (chainAdapter as
any).getChainId === 'function') before invoking it, and return false if not
present; you can also wrap the call in a try/catch to return false on unexpected
errors so assertGetAptosChainAdapter behavior remains predictable.
🪄 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: 973ad940-e479-4457-b4db-52b939ead6a4

📥 Commits

Reviewing files that changed from the base of the PR and between 7d71d44 and d577262.

⛔ Files ignored due to path filters (3)
  • 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
📒 Files selected for processing (79)
  • .env
  • .env.development
  • .env.production
  • e2e/fixtures/aptos-chain-integration.yaml
  • headers/csps/chains/aptos.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/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/swapperDeps.ts
  • packages/swapper/package.json
  • 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/utils/helpers/helpers.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
  • packages/utils/src/treasury.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/hooks/useGetTradeQuotes/getTradeQuoteOrRateInput.ts
  • src/components/TradeAssetSearch/hooks/useGetPopularAssetsQuery.tsx
  • src/config.ts
  • src/constants/chains.ts
  • src/context/PluginProvider/PluginProvider.tsx
  • src/context/WalletProvider/Ledger/constants.ts
  • 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/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

Comment thread packages/chain-adapters/src/aptos/AptosChainAdapter.ts
Comment thread packages/chain-adapters/src/aptos/AptosChainAdapter.ts Outdated
Comment thread packages/chain-adapters/src/aptos/AptosChainAdapter.ts
Comment thread packages/hdwallet-native/src/aptos.ts Outdated
Comment thread packages/swapper/src/swappers/NearIntentsSwapper/endpoints.ts
Comment thread packages/swapper/src/utils.ts
Comment thread packages/utils/src/treasury.ts Outdated
Comment thread src/context/WalletProvider/Ledger/constants.ts Outdated
Comment thread src/lib/utils/aptos.ts
swdiscordia and others added 2 commits May 17, 2026 02:33
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>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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/chain-adapters/src/aptos/AptosChainAdapter.ts`:
- Around line 249-255: The send/build path currently calls estimateMaxGasAmount
and hard-fails if simulation errors; update the build flow in
buildSendApiTransaction (the code that calls this.estimateMaxGasAmount and
this.client.transaction.build.simple) to catch errors from estimateMaxGasAmount
and fall back to using MIN_MAX_GAS_AMOUNT (the same constant used by getFeeData)
before calling this.client.transaction.build.simple so that transient simulation
failures do not abort transaction building.

In `@packages/swapper/src/swappers/NearIntentsSwapper/endpoints.ts`:
- Around line 382-424: Replace direct throws in getUnsignedAptosTransaction and
getAptosTransactionFees with swapper Result-style errors: instead of throwing
when !isExecutableTradeQuote(tradeQuote) or when nearIntentsSpecific is missing
or when step.feeData.networkFeeCryptoBaseUnit is missing, return
makeSwapErrorRight(...) populated with the appropriate TradeQuoteError enum
value (e.g., TradeQuoteError.UnableToExecuteQuote or
TradeQuoteError.MissingNetworkFee) and include contextual info (stepIndex,
sellAsset.assetId, tradeQuote id/metadata). Use the Result helpers (Ok/Err or
Promise.resolve(Err(...)) as the surrounding code expects) and reference the
existing helpers isExecutableTradeQuote, getExecutableTradeStep,
makeSwapErrorRight, and TradeQuoteError to locate where to change the error
paths.
🪄 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: f4fb07f3-ccd7-4def-875b-4cf1b7f8ae5b

📥 Commits

Reviewing files that changed from the base of the PR and between d577262 and 59b339d.

📒 Files selected for processing (8)
  • packages/chain-adapters/src/aptos/AptosChainAdapter.test.ts
  • packages/chain-adapters/src/aptos/AptosChainAdapter.ts
  • packages/chain-adapters/src/aptos/types.ts
  • packages/chain-adapters/src/utils/ledgerAppGate.ts
  • packages/hdwallet-native/src/aptos.ts
  • packages/swapper/src/swappers/NearIntentsSwapper/endpoints.ts
  • packages/swapper/src/utils.ts
  • src/lib/utils/aptos.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/chain-adapters/src/aptos/types.ts
  • packages/swapper/src/utils.ts
  • src/lib/utils/aptos.ts
  • packages/chain-adapters/src/aptos/AptosChainAdapter.test.ts

Comment on lines +249 to +255
const maxGasAmount = Number(await this.estimateMaxGasAmount(from, data))

const transaction = await this.client.transaction.build.simple({
sender: from,
data,
options: { maxGasAmount },
})
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add a fallback max gas in send build path to avoid hard-failing on simulation errors.

Line 249 currently makes buildSendApiTransaction fail if gas simulation fails transiently. You already use MIN_MAX_GAS_AMOUNT fallback in getFeeData; the send path should mirror that resilience.

Suggested fix
-      const maxGasAmount = Number(await this.estimateMaxGasAmount(from, data))
+      let maxGasAmount = Number(MIN_MAX_GAS_AMOUNT)
+      try {
+        maxGasAmount = Number(await this.estimateMaxGasAmount(from, data))
+      } catch {
+        maxGasAmount = Number(MIN_MAX_GAS_AMOUNT)
+      }
🤖 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 249 -
255, The send/build path currently calls estimateMaxGasAmount and hard-fails if
simulation errors; update the build flow in buildSendApiTransaction (the code
that calls this.estimateMaxGasAmount and this.client.transaction.build.simple)
to catch errors from estimateMaxGasAmount and fall back to using
MIN_MAX_GAS_AMOUNT (the same constant used by getFeeData) before calling
this.client.transaction.build.simple so that transient simulation failures do
not abort transaction building.

Comment on lines +382 to +424
getUnsignedAptosTransaction: ({
stepIndex,
tradeQuote,
from,
assertGetAptosChainAdapter,
}: GetUnsignedAptosTransactionArgs) => {
if (!isExecutableTradeQuote(tradeQuote)) throw new Error('Unable to execute a trade rate quote')

const step = getExecutableTradeStep(tradeQuote, stepIndex)

const { accountNumber, sellAsset, nearIntentsSpecific } = step
if (!nearIntentsSpecific) throw new Error('nearIntentsSpecific is required')

const adapter = assertGetAptosChainAdapter(sellAsset.chainId)

const to = nearIntentsSpecific.depositAddress
const value = step.sellAmountIncludingProtocolFeesCryptoBaseUnit

// Native APT lives at the slip44 namespace; non-native Aptos coins encode
// their Move CoinStore type as the asset reference and must be passed
// through to the adapter so the typeArguments target the right coin.
const { assetNamespace, assetReference } = fromAssetId(sellAsset.assetId)
const chainSpecific =
assetNamespace === ASSET_NAMESPACE.slip44 ? {} : { coinType: assetReference }

return adapter.buildSendApiTransaction({
to,
from,
value,
accountNumber,
chainSpecific,
})
},

getAptosTransactionFees: ({ tradeQuote, stepIndex }: GetUnsignedAptosTransactionArgs) => {
if (!isExecutableTradeQuote(tradeQuote)) throw new Error('Unable to execute a trade rate quote')

const step = getExecutableTradeStep(tradeQuote, stepIndex)
if (!step.feeData.networkFeeCryptoBaseUnit) {
throw new Error('Missing network fee in quote')
}
return Promise.resolve(step.feeData.networkFeeCryptoBaseUnit)
},
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use swapper Result-based errors instead of throwing raw Error.

Line 388, Line 393, Line 417, and Line 421 throw directly in newly added swapper API handlers. In this layer, these should return swapper-typed errors (makeSwapErrorRight + TradeQuoteError) with context, not uncaught exceptions.

As per coding guidelines, **/*.{ts,tsx}: “Use Result<T, E> pattern for error handling in swappers and APIs; ALWAYS use Ok() and Err() from @sniptt/monads; AVOID throwing within swapper API implementations” and **/swapper{s,}/**/*.{ts,tsx}: “ALWAYS use makeSwapErrorRight for swapper errors with TradeQuoteError enum for error codes and provide detailed error information`.

🤖 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/NearIntentsSwapper/endpoints.ts` around lines
382 - 424, Replace direct throws in getUnsignedAptosTransaction and
getAptosTransactionFees with swapper Result-style errors: instead of throwing
when !isExecutableTradeQuote(tradeQuote) or when nearIntentsSpecific is missing
or when step.feeData.networkFeeCryptoBaseUnit is missing, return
makeSwapErrorRight(...) populated with the appropriate TradeQuoteError enum
value (e.g., TradeQuoteError.UnableToExecuteQuote or
TradeQuoteError.MissingNetworkFee) and include contextual info (stepIndex,
sellAsset.assetId, tradeQuote id/metadata). Use the Result helpers (Ok/Err or
Promise.resolve(Err(...)) as the surrounding code expects) and reference the
existing helpers isExecutableTradeQuote, getExecutableTradeStep,
makeSwapErrorRight, and TradeQuoteError to locate where to change the error
paths.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@scripts/generateAssetData/aptos/index.ts`:
- Around line 24-26: The code calls uniqBy on tokensOnly before prepending the
native APT (unfreeze(aptos)), so a duplicate assetId from CoinGecko can still
appear; change the flow to build the combined array first and then deduplicate
by assetId (i.e., produce [unfreeze(aptos), ...tokensOnly] and run uniqBy(...,
'assetId') on that combined array), replacing the current use of allAssets and
returning the deduped result.
- Around line 13-21: Replace the simple console.error(result.reason) with a
structured log that includes context (e.g., the batch item/index, the operation
name) and the full error object/stack (capture result.reason and any surrounding
metadata) so you log both message and error details for debugging; also rename
the regex constant nativeAptCoinPattern to UPPER_SNAKE_CASE
NATIVE_APT_COIN_PATTERN (preserve the same regex value
/^aptos:[^/]+\/aptosCoin:(0x0*a|0x1::aptos_coin::AptosCoin)$/i) to follow
constant naming conventions and update any references accordingly.
🪄 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: 9ce3f83c-150c-410c-9489-3afbe8757357

📥 Commits

Reviewing files that changed from the base of the PR and between 59b339d and f37f911.

📒 Files selected for processing (2)
  • scripts/generateAssetData/aptos/index.ts
  • scripts/generateAssetData/coingecko.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/generateAssetData/coingecko.ts

Comment on lines +13 to +21
console.error(result.reason)
return []
})

// Filter out the native APT token from CoinGecko to avoid duplicates
// CoinGecko includes native APT both as the slip44 base asset (added manually) and
// as the coin-standard token (0x1::aptos_coin::AptosCoin) at the same metadata
// address 0xa under the aptosCoin namespace.
const nativeAptCoinPattern = /^aptos:[^/]+\/aptosCoin:(0x0*a|0x1::aptos_coin::AptosCoin)$/i
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.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Use structured error context and constant naming conventions.

At Line 13, logging only result.reason makes troubleshooting harder in batch scripts. At Line 21, the regex constant should follow UPPER_SNAKE_CASE.

♻️ Proposed fix
-    console.error(result.reason)
+    console.error('Failed to fetch Aptos assets from CoinGecko', {
+      chainId: aptosChainId,
+      reason: result.reason,
+    })
     return []
   })
@@
-  const nativeAptCoinPattern = /^aptos:[^/]+\/aptosCoin:(0x0*a|0x1::aptos_coin::AptosCoin)$/i
-  const tokensOnly = assets.filter(asset => !nativeAptCoinPattern.test(asset.assetId))
+  const NATIVE_APT_COIN_PATTERN = /^aptos:[^/]+\/aptosCoin:(0x0*a|0x1::aptos_coin::AptosCoin)$/i
+  const tokensOnly = assets.filter(asset => !NATIVE_APT_COIN_PATTERN.test(asset.assetId))

As per coding guidelines, "ALWAYS log errors for debugging using structured logging with relevant context and error metadata" and "Use UPPER_SNAKE_CASE for constants and configuration values with descriptive names."

🤖 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/aptos/index.ts` around lines 13 - 21, Replace the
simple console.error(result.reason) with a structured log that includes context
(e.g., the batch item/index, the operation name) and the full error object/stack
(capture result.reason and any surrounding metadata) so you log both message and
error details for debugging; also rename the regex constant nativeAptCoinPattern
to UPPER_SNAKE_CASE NATIVE_APT_COIN_PATTERN (preserve the same regex value
/^aptos:[^/]+\/aptosCoin:(0x0*a|0x1::aptos_coin::AptosCoin)$/i) to follow
constant naming conventions and update any references accordingly.

Comment on lines +24 to +26
const allAssets = uniqBy(tokensOnly, 'assetId')

return [unfreeze(aptos), ...allAssets]
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.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Guarantee final assetId uniqueness after prepending native APT.

uniqBy() runs before adding unfreeze(aptos), so duplicates can still leak if CoinGecko returns the same native assetId. Deduplicate the final merged list instead.

✅ Proposed fix
-  const allAssets = uniqBy(tokensOnly, 'assetId')
-
-  return [unfreeze(aptos), ...allAssets]
+  return uniqBy([unfreeze(aptos), ...tokensOnly], 'assetId')
📝 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
const allAssets = uniqBy(tokensOnly, 'assetId')
return [unfreeze(aptos), ...allAssets]
return uniqBy([unfreeze(aptos), ...tokensOnly], '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 `@scripts/generateAssetData/aptos/index.ts` around lines 24 - 26, The code
calls uniqBy on tokensOnly before prepending the native APT (unfreeze(aptos)),
so a duplicate assetId from CoinGecko can still appear; change the flow to build
the combined array first and then deduplicate by assetId (i.e., produce
[unfreeze(aptos), ...tokensOnly] and run uniqBy(..., 'assetId') on that combined
array), replacing the current use of allAssets and returning the deduped result.

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 force-pushed the feat/aptos-support branch from f37f911 to aa50930 Compare May 17, 2026 03:36
@swdiscordia
Copy link
Copy Markdown
Contributor Author

Code review

Found 2 issues:

  1. Aptos BIP44 derivation passes the address_index segment unhardened (msg.accountIdx), but the Aptos reference wallet (Petra, official @aptos-labs/ts-sdk) requires all five path segments hardened for Ed25519 — derived addresses won't match other Aptos wallets, breaking interop and account recovery from seed.

export function aptosGetAccountPaths(msg: AptosGetAccountPaths): AptosAccountPath[] {
const slip44 = slip44ByCoin('Aptos')
if (slip44 === undefined) return []
return [
{
addressNList: [
0x80000000 + 44,
0x80000000 + slip44,
0x80000000 + 0,
0x80000000 + 0,
msg.accountIdx,
],
},

  1. Non-APT Aptos token sends silently transfer APT: handleSendWithMetadata passes only { memo } in chainSpecific for the Aptos branch, so AptosChainAdapter.buildSendApiTransaction falls back to APT_COIN_TYPE. Sending USDC, USDT, or any non-native Aptos coin from the Send modal will move APT instead. The same gap exists in estimateFees around L223 (fees computed for an APT transfer regardless of the selected asset).

}
if (fromChainId(asset.chainId).chainNamespace === CHAIN_NAMESPACE.Aptos) {
const { accountNumber } = bip44Params
const adapter = assertGetAptosChainAdapter(chainId)
return adapter.buildSendTransaction({
to,
value,
wallet,
accountNumber,
sendMax: sendInput.sendMax,
chainSpecific: { memo },
} as BuildSendTxInput<KnownChainIds.AptosMainnet>)
}

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

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.

feat: add Aptos chain support with NEAR Intents routing

1 participant