Skip to content
Open
Show file tree
Hide file tree
Changes from 69 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
24a2de6
feat(packages/bridging/src/providers/near-intents): starts adding Nea…
allemanfredi Sep 2, 2025
b968971
feat(packages/bridging/src/providers/near-intents): adds getQuote + t…
allemanfredi Sep 3, 2025
bdd5602
refactor(packages/bridging/src/providers/near-intents): sorts imports
allemanfredi Sep 3, 2025
7ce29dd
fix(packages/bridging/src/providers/near-intents): fixes NearIntentsB…
allemanfredi Sep 3, 2025
5ebbaa3
feat(packages/bridging/src/providers/near-intents): implements getUns…
allemanfredi Sep 3, 2025
b493d02
feat(packages/bridging/src/providers/near-intents): implements getGas…
allemanfredi Sep 4, 2025
b39ec0c
feat(packages/bridging/src/providers/near-intents): adds NEAR_BLOCKCH…
allemanfredi Sep 4, 2025
4b775d0
feat(packages/bridging/src/providers/near-intents): implements getSta…
allemanfredi Sep 4, 2025
2c743e2
chore(packages/bridging/src/providers/near-intents): add util.ts
allemanfredi Sep 4, 2025
815c2e1
feat(packages/bridging/src/providers/near-intents): adds hook check w…
allemanfredi Sep 8, 2025
fee6b97
fix(packages/bridging/src/providers/across): adds missing indexed wit…
allemanfredi Sep 8, 2025
c8d9448
refactor(packages/bridging/src/providers/near-intents): updates a com…
allemanfredi Sep 8, 2025
a6ec6af
refactor(packages/bridging/src/providers/near-intents): rm comment wi…
allemanfredi Sep 8, 2025
a95d424
feat(packages/bridging/src/providers/near-intents/util): adds adaptTo…
allemanfredi Sep 9, 2025
e66825a
feat(packages/bridging/src/providers/near-intents): adds getStatus test
allemanfredi Sep 9, 2025
9e75751
chore(packages/bridging/jest.config.ts): rm testTimeout
allemanfredi Sep 9, 2025
5f46c9a
feat(packages/bridging/src/index.ts): exports NearIntentsBridgeProvid…
allemanfredi Sep 9, 2025
02de0e1
fix(packages/bridging/src/providers/near-intents): rm unsigned call w…
allemanfredi Sep 9, 2025
2028c13
feat(packages/bridging/src/providers/near-intents): adds getUnsignedB…
allemanfredi Sep 10, 2025
5ad2207
feat(packages/bridging/src/providers/near-intents): fixes a comment w…
allemanfredi Sep 10, 2025
8439b4f
feat(packages/bridging/src/providers/near-intents): rm sellAmount fro…
allemanfredi Sep 10, 2025
746d5e1
chore(packages/bridging/src/providers/near-intents): fixes a comment …
allemanfredi Sep 11, 2025
2fcb387
chore(packages/bridging/src/providers/near-intents): rm support for d…
allemanfredi Sep 12, 2025
c970efd
fix(packages/bridging/src/providers/near-intents): fixes tests that t…
allemanfredi Sep 12, 2025
4d0c3ea
feat(packages/bridging/src/providers/near-intents): adds util.test.ts
allemanfredi Sep 12, 2025
f247c1f
refactor(packages/bridging/src/providers/near-intents): adds return t…
allemanfredi Sep 12, 2025
9eca866
chore(global): addds near-intents-logo.png and rm some TODO within Ne…
allemanfredi Sep 12, 2025
cded526
chore(packages/bridging/src/providers/near-intents): mv @defuse-proto…
allemanfredi Sep 17, 2025
47b4325
fix(packages/bridging/src/providers/near-intents): rm typo
allemanfredi Sep 17, 2025
d91fbe8
refactor(packages/bridging/src/providers/near-intents): rn NEAR_INTEN…
allemanfredi Sep 17, 2025
4123b49
refactor(packages/bridging/src/providers/near-intents): rm useless check
allemanfredi Sep 17, 2025
ae5a35f
refactor(packages/bridging/src/providers/near-intents): replaces cons…
allemanfredi Sep 17, 2025
3339ce4
feat(packages/bridging/src/providers/near-intents): adds NearBlockcha…
allemanfredi Sep 24, 2025
00f41a9
refactor(packages/bridging/src/providers/near-intents): improves sour…
allemanfredi Sep 25, 2025
573ce4d
refactor(packages/bridging/src/providers/near-intents): replaces NEAR…
allemanfredi Sep 25, 2025
a5a5ed7
chore(src/bridging/providers): <- mv near-intents-logo.png here
allemanfredi Sep 25, 2025
9006d47
refactor(packages/bridging/src/providers/near-intents): adds isWrappe…
allemanfredi Sep 25, 2025
070be99
refactor(packages/bridging/src/providers/near-intents): replaces WRAP…
allemanfredi Sep 25, 2025
67a393a
fix(packages/bridging/src/providers/near-intents): makes everything l…
allemanfredi Sep 25, 2025
fa51380
refactor(packages/bridging/src/providers/near-intents): allows slippa…
allemanfredi Sep 25, 2025
69f5771
refactor(packages/bridging/src/providers/near-intents): rm export def…
allemanfredi Sep 25, 2025
e0d8a18
fix(packages/bridging/src/providers/near-intents): fixes findig depos…
allemanfredi Sep 26, 2025
11a1c31
refactor(packages/bridging/src/providers/near-intents): rm CHAIN_ID_N…
allemanfredi Sep 26, 2025
95c73f5
refactor(packages/bridging/src/providers/near-intents): adds bridgeFe…
allemanfredi Sep 26, 2025
1cd707e
refactor(packages/bridging/src/providers/near-intents): improves getB…
allemanfredi Sep 26, 2025
8eff7be
fix(packages/bridging/src/providers/near-intents): fixes getQuote
allemanfredi Sep 29, 2025
2937304
fix(packages/bridging/src/providers/near-intents): fixes bridgeFee ca…
allemanfredi Sep 29, 2025
297ef53
refactor(packages/bridging/src/providers/near-intents): forces getInt…
allemanfredi Oct 7, 2025
527133d
refactor(bridging): replaces BridgeProvider with ReceiverAccountBridg…
allemanfredi Nov 3, 2025
6b6d2ec
fix(bridging): fixes NearIntentsBridgeProvider.getQuote
allemanfredi Nov 3, 2025
e6dc29b
refactor(bridging): refactors NearIntentsBridgeProvider tests
allemanfredi Nov 3, 2025
c644435
feat(bridging/src/providers/near-intents): adds referral to getQuote
allemanfredi Nov 4, 2025
630cd31
fix(packages/bridging/src/providers/near-intents/NearIntentsBridgePro…
allemanfredi Nov 8, 2025
9267fd0
feat(packages/bridging/src/providers/near-intents): adds getAttestati…
allemanfredi Nov 9, 2025
c20ee71
feat(packages/bridging/src/providers/near-intents/NearIntentsApi): re…
allemanfredi Nov 9, 2025
4722edc
feat(packages/bridging/src/providers/near-intents/NearIntentsBridgePr…
allemanfredi Nov 9, 2025
cf716e3
refactor(packages/bridging/src/providers/near-intents/NearIntentsBrid…
allemanfredi Nov 10, 2025
c915fcc
refactor: replace viem with adapter in near utils
shoom3301 Nov 10, 2025
ec2d8c8
fix(packages/bridging/src/providers/near-intents): fixes tests
allemanfredi Nov 10, 2025
3320c5f
refactor(packages/bridging/src/providers/near-intents/util.ts): rm is…
allemanfredi Nov 12, 2025
0464416
refactor(packages/bridging/src/providers/near-intents/util.ts): filte…
allemanfredi Nov 12, 2025
1b5e91b
feat(packages/bridging/src/providers/near-intents/util.ts): enables s…
allemanfredi Nov 13, 2025
5c04822
refactor(packages/bridging/src/providers/near-intents/const): sets AT…
allemanfredi Nov 14, 2025
10e70b4
fix(packages/bridging/src/providers/near-intents/util.ts): fixes hash…
allemanfredi Nov 14, 2025
e04bc02
Merge remote-tracking branch 'upstream/main' into feat/near-intents
allemanfredi Nov 26, 2025
4d05671
Merge remote-tracking branch 'upstream/main' into feat/near-intents
allemanfredi Feb 23, 2026
4888bd6
Merge remote-tracking branch 'upstream/main' into feat/add-btc-and-sol
allemanfredi Mar 4, 2026
592288e
feat(packages/bridging/src/providers/near-intents): adds support for …
allemanfredi Mar 4, 2026
0cfa90c
feat(packages/bridging/src/providers/near-intents): adds check to pre…
allemanfredi Mar 4, 2026
7524ede
fix(packages/bridging/src/providers/near-intents/util.ts): adds check…
allemanfredi Mar 4, 2026
7624809
refactor(packages/bridging/src/providers/near-intents): adds areAddre…
allemanfredi Mar 5, 2026
bd65937
Merge branch 'main' into feat/add-btc-and-sol
allemanfredi Mar 16, 2026
c791a86
fix(packages/bridging/src/providers/near-intents): adds check + tests…
allemanfredi Mar 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ describe('NearIntentsApi', () => {
})

it("doesn't add Authorization header when api key is not set", async () => {

const api = new NearIntentsApi()

mockFetch.mockResolvedValue({
Expand Down Expand Up @@ -70,4 +69,3 @@ describe('NearIntentsApi', () => {
)
})
})

Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { setGlobalAdapter } from '@cowprotocol/sdk-common'
import { SupportedChainId } from '@cowprotocol/sdk-config'
import {
BTC_CURRENCY_ADDRESS,
NonEvmChains,
SOL_NATIVE_CURRENCY_ADDRESS,
SupportedChainId,
} from '@cowprotocol/sdk-config'
import { GetExecutionStatusResponse, QuoteRequest, TokenResponse } from '@defuse-protocol/one-click-sdk-typescript'

import { createAdapters } from '../../../tests/setup'
Expand Down Expand Up @@ -386,6 +391,230 @@ adapterNames.forEach((adapterName) => {
expect(result?.address).toBeDefined()
expect(result?.address.length).toBeGreaterThan(0)
})

it('should return quote when destination asset is bitcoin', async () => {
const api = new NearIntentsApi()
const sellTokenAddress = '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'
const buyTokenAddress = BTC_CURRENCY_ADDRESS
const testQuoteHash = '0xtestBtcQuoteHash123'

const mockQuoteResponse: QuoteResponse = {
quote: {
amountIn: '1000000',
amountInFormatted: '1.0',
amountInUsd: '1.0',
minAmountIn: '1000000',
amountOut: '10000',
amountOutFormatted: '0.0001',
amountOutUsd: '1.0',
minAmountOut: '9900',
timeEstimate: 600,
deadline: '2025-09-05T12:10:38.605Z',
timeWhenInactive: '2025-09-05T12:10:38.605Z',
depositAddress: '0xAd8b7139196c5ae9fb66B71C91d87A1F9071687e',
},
quoteRequest: {
dry: false,
swapType: QuoteRequest.swapType.EXACT_INPUT,
depositMode: QuoteRequest.depositMode.SIMPLE,
slippageTolerance: 100,
originAsset: 'nep141:base-0x833589fcd6edb6e08f4c7c32d4f71b54bda02913.omft.near',
depositType: QuoteRequest.depositType.ORIGIN_CHAIN,
destinationAsset: 'nep141:btc.omft.near',
amount: '1000000',
refundTo: '0x0000000000000000000000000000000000000000',
refundType: QuoteRequest.refundType.ORIGIN_CHAIN,
recipient: 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4',
recipientType: QuoteRequest.recipientType.DESTINATION_CHAIN,
deadline: '2025-09-05T12:10:38.605Z',
},
signature: 'ed25519:testBtcSignature',
timestamp: '2025-09-05T12:00:38.695Z',
}

jest.spyOn(api, 'getQuote').mockResolvedValue(mockQuoteResponse)
jest.spyOn(api, 'getTokens').mockResolvedValue([
{
assetId: 'nep141:base-0x833589fcd6edb6e08f4c7c32d4f71b54bda02913.omft.near',
decimals: 6,
blockchain: TokenResponse.blockchain.BASE,
symbol: 'USDC',
price: 1,
priceUpdatedAt: '2025-09-05T12:00:38.695Z',
contractAddress: sellTokenAddress,
},
{
assetId: 'nep141:btc.omft.near',
decimals: 8,
blockchain: TokenResponse.blockchain.BTC,
symbol: 'BTC',
price: 60000,
priceUpdatedAt: '2025-09-05T12:00:38.695Z',
},
])
jest.spyOn(api, 'getAttestation').mockResolvedValue({
version: 1,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
provider.setApi(api)

jest.spyOn(provider, 'recoverDepositAddress').mockResolvedValue({
address: ATTESTATOR_ADDRESS,
quoteHash: testQuoteHash,
stringifiedQuote: '',
attestationSignature: '',
})

const quote = await provider.getQuote({
kind: OrderKind.SELL,
sellTokenChainId: SupportedChainId.BASE,
sellTokenAddress,
sellTokenDecimals: 6,
buyTokenChainId: NonEvmChains.BITCOIN as number,
buyTokenAddress,
buyTokenDecimals: 8,
amount: 1000000n,
account: '0x0000000000000000000000000000000000000000',
appCode: 'test',
signer: '0x0000000000000000000000000000000000000000',
})

expect(quote.id).toBe(testQuoteHash)
expect(quote.signature).toBe('ed25519:testBtcSignature')
expect(quote.depositAddress).toBe('0xAd8b7139196c5ae9fb66B71C91d87A1F9071687e')
expect(quote.amountsAndCosts.beforeFee.buyAmount).toBe(10000n)
})

it('should return quote when destination asset is solana', async () => {
const api = new NearIntentsApi()
const sellTokenAddress = '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'
const buyTokenAddress = SOL_NATIVE_CURRENCY_ADDRESS
const testQuoteHash = '0xtestSolQuoteHash123'

const mockQuoteResponse: QuoteResponse = {
quote: {
amountIn: '1000000',
amountInFormatted: '1.0',
amountInUsd: '1.0',
minAmountIn: '1000000',
amountOut: '100000000',
amountOutFormatted: '1.0',
amountOutUsd: '1.0',
minAmountOut: '99000000',
timeEstimate: 60,
deadline: '2025-09-05T12:10:38.605Z',
timeWhenInactive: '2025-09-05T12:10:38.605Z',
depositAddress: '0xAd8b7139196c5ae9fb66B71C91d87A1F9071687e',
},
quoteRequest: {
dry: false,
swapType: QuoteRequest.swapType.EXACT_INPUT,
depositMode: QuoteRequest.depositMode.SIMPLE,
slippageTolerance: 100,
originAsset: 'nep141:base-0x833589fcd6edb6e08f4c7c32d4f71b54bda02913.omft.near',
depositType: QuoteRequest.depositType.ORIGIN_CHAIN,
destinationAsset: 'nep141:sol.omft.near',
amount: '1000000',
refundTo: '0x0000000000000000000000000000000000000000',
refundType: QuoteRequest.refundType.ORIGIN_CHAIN,
recipient: 'So11111111111111111111111111111111111111112',
recipientType: QuoteRequest.recipientType.DESTINATION_CHAIN,
deadline: '2025-09-05T12:10:38.605Z',
},
signature: 'ed25519:testSolSignature',
timestamp: '2025-09-05T12:00:38.695Z',
}

jest.spyOn(api, 'getQuote').mockResolvedValue(mockQuoteResponse)
jest.spyOn(api, 'getTokens').mockResolvedValue([
{
assetId: 'nep141:base-0x833589fcd6edb6e08f4c7c32d4f71b54bda02913.omft.near',
decimals: 6,
blockchain: TokenResponse.blockchain.BASE,
symbol: 'USDC',
price: 1,
priceUpdatedAt: '2025-09-05T12:00:38.695Z',
contractAddress: sellTokenAddress,
},
{
assetId: 'nep141:sol.omft.near',
decimals: 9,
blockchain: TokenResponse.blockchain.SOL,
symbol: 'SOL',
price: 150,
priceUpdatedAt: '2025-09-05T12:00:38.695Z',
},
])
jest.spyOn(api, 'getAttestation').mockResolvedValue({
version: 1,
signature:
'0x66edc32e2ab001213321ab7d959a2207fcef5190cc9abb6da5b0d2a8a9af2d4d2b0700e2c317c4106f337fd934fbbb0bf62efc8811a78603b33a8265d3b8f8cb1c',
})
provider.setApi(api)

jest.spyOn(provider, 'recoverDepositAddress').mockResolvedValue({
address: ATTESTATOR_ADDRESS,
quoteHash: testQuoteHash,
stringifiedQuote: '',
attestationSignature: '',
})

const quote = await provider.getQuote({
kind: OrderKind.SELL,
sellTokenChainId: SupportedChainId.BASE,
sellTokenAddress,
sellTokenDecimals: 6,
buyTokenChainId: NonEvmChains.SOLANA as number,
buyTokenAddress,
buyTokenDecimals: 9,
amount: 1000000n,
account: '0x0000000000000000000000000000000000000000',
appCode: 'test',
signer: '0x0000000000000000000000000000000000000000',
})

expect(quote.id).toBe(testQuoteHash)
expect(quote.signature).toBe('ed25519:testSolSignature')
expect(quote.depositAddress).toBe('0xAd8b7139196c5ae9fb66B71C91d87A1F9071687e')
expect(quote.amountsAndCosts.beforeFee.buyAmount).toBe(100000000n)
})

it('should throw NO_ROUTES when sellTokenAddress is BTC_CURRENCY_ADDRESS', async () => {
await expect(
provider.getQuote({
kind: OrderKind.SELL,
sellTokenChainId: SupportedChainId.BASE,
sellTokenAddress: BTC_CURRENCY_ADDRESS,
sellTokenDecimals: 8,
buyTokenChainId: SupportedChainId.BASE,
buyTokenAddress: '0x4200000000000000000000000000000000000006',
buyTokenDecimals: 18,
amount: 1000000n,
account: '0x0000000000000000000000000000000000000000',
appCode: 'test',
signer: '0x0000000000000000000000000000000000000000',
}),
).rejects.toThrow('NO_ROUTES')
})

it('should throw NO_ROUTES when sellTokenAddress is SOL_NATIVE_CURRENCY_ADDRESS', async () => {
await expect(
provider.getQuote({
kind: OrderKind.SELL,
sellTokenChainId: SupportedChainId.BASE,
sellTokenAddress: SOL_NATIVE_CURRENCY_ADDRESS,
sellTokenDecimals: 9,
buyTokenChainId: SupportedChainId.BASE,
buyTokenAddress: '0x4200000000000000000000000000000000000006',
buyTokenDecimals: 18,
amount: 1000000n,
account: '0x0000000000000000000000000000000000000000',
appCode: 'test',
signer: '0x0000000000000000000000000000000000000000',
}),
).rejects.toThrow('NO_ROUTES')
})
})
})
})
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getGlobalAdapter, setGlobalAdapter } from '@cowprotocol/sdk-common'
import { ETH_ADDRESS } from '@cowprotocol/sdk-config'
import { BTC_CURRENCY_ADDRESS, ETH_ADDRESS, SOL_NATIVE_CURRENCY_ADDRESS } from '@cowprotocol/sdk-config'
import { CowShedSdk } from '@cowprotocol/sdk-cow-shed'
import { EnrichedOrder, OrderKind } from '@cowprotocol/sdk-order-book'
import { QuoteRequest } from '@defuse-protocol/one-click-sdk-typescript'
Expand Down Expand Up @@ -138,6 +138,10 @@ export class NearIntentsBridgeProvider implements ReceiverAccountBridgeProvider<
owner,
} = request

if (sellTokenAddress === BTC_CURRENCY_ADDRESS || sellTokenAddress === SOL_NATIVE_CURRENCY_ADDRESS) {
throw new BridgeProviderQuoteError(BridgeQuoteErrors.NO_ROUTES)
}

const tokens = await this.api.getTokens()
const sellToken = getTokenByAddressAndChainId(tokens, sellTokenAddress, sellTokenChainId)
const buyToken = getTokenByAddressAndChainId(tokens, buyTokenAddress, buyTokenChainId)
Expand Down
34 changes: 31 additions & 3 deletions packages/bridging/src/providers/near-intents/const/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
import { arbitrumOne, avalanche, base, bnb, gnosisChain, mainnet, optimism, polygon, plasma } from '@cowprotocol/sdk-config'
import {
arbitrumOne,
avalanche,
base,
bnb,
gnosisChain,
mainnet,
optimism,
polygon,
plasma,
bitcoin,
solana,
ChainId,
} from '@cowprotocol/sdk-config'

import { HOOK_DAPP_BRIDGE_PROVIDER_PREFIX } from '../../../const'

Expand All @@ -16,9 +29,22 @@ export const NEAR_INTENTS_SUPPORTED_NETWORKS = [
optimism,
polygon,
plasma,
bitcoin,
solana,
]

export type NearBlockchainKey = 'arb' | 'avax' | 'base' | 'bsc' | 'eth' | 'gnosis' | 'op' | 'pol' | 'plasma'
export type NearBlockchainKey =
| 'arb'
| 'avax'
| 'base'
| 'bsc'
| 'eth'
| 'gnosis'
| 'op'
| 'pol'
| 'plasma'
| 'btc'
| 'sol'

export const NEAR_INTENTS_BLOCKCHAIN_CHAIN_IDS = {
arb: arbitrumOne.id,
Expand All @@ -30,7 +56,9 @@ export const NEAR_INTENTS_BLOCKCHAIN_CHAIN_IDS = {
op: optimism.id,
pol: polygon.id,
plasma: plasma.id,
} as const satisfies Record<NearBlockchainKey, number>
btc: bitcoin.id,
sol: solana.id,
} as const satisfies Record<NearBlockchainKey, ChainId>

export const NEAR_INTENTS_STATUS_TO_COW_STATUS: Record<string, BridgeStatus> = {
KNOWN_DEPOSIT_TX: BridgeStatus.IN_PROGRESS,
Expand Down
8 changes: 4 additions & 4 deletions packages/bridging/src/providers/near-intents/util.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ describe('Near Intents Utils', () => {

it('should return null for a non supported chain', () => {
const tokenResponse: TokenResponse = {
assetId: 'nep141:sol.omft.near',
assetId: 'nep141:ton.omft.near',
decimals: 9,
blockchain: TokenResponse.blockchain.SOL,
symbol: 'SOL',
price: 234.78,
blockchain: TokenResponse.blockchain.TON,
symbol: 'TON',
price: 5.0,
priceUpdatedAt: '2025-09-12T04:08:30.252Z',
}

Expand Down
30 changes: 23 additions & 7 deletions packages/bridging/src/providers/near-intents/util.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import stringify from 'json-stable-stringify'
import type { Quote, QuoteRequest, TokenResponse } from '@defuse-protocol/one-click-sdk-typescript'
import { getGlobalAdapter } from '@cowprotocol/sdk-common'
import { ETH_ADDRESS, TokenInfo, ChainId, isEvmChain } from '@cowprotocol/sdk-config'
import {
BTC_CURRENCY_ADDRESS,
ETH_ADDRESS,
SOL_NATIVE_CURRENCY_ADDRESS,
TokenInfo,
ChainId,
isEvmChain,
} from '@cowprotocol/sdk-config'
import type { Hex } from 'viem'

import { NEAR_INTENTS_BLOCKCHAIN_CHAIN_IDS } from './const'
Expand Down Expand Up @@ -45,18 +52,27 @@ export const getTokenByAddressAndChainId = (
targetTokenAddress: string,
targetTokenChainId: ChainId,
): TokenResponse | undefined => {
// will handle non-EVM chains in the future
if (!isEvmChain(targetTokenChainId)) {
return undefined
}
return tokens.find((token) => {
const chainId = NEAR_INTENTS_BLOCKCHAIN_CHAIN_IDS[token.blockchain as NearBlockchainKey]
if (!chainId) return false
if (chainId !== targetTokenChainId) return false

// For non-EVM chains, match native tokens (no contractAddress) against known native sentinels,
// or match SPL/other tokens by contractAddress directly
if (!isEvmChain(targetTokenChainId)) {
if (!token.contractAddress) {
return targetTokenAddress === BTC_CURRENCY_ADDRESS || targetTokenAddress === SOL_NATIVE_CURRENCY_ADDRESS
}
return token.contractAddress.toLowerCase() === targetTokenAddress.toLowerCase()
}

// Match native/unwrapped EVM tokens (no contractAddress) via ETH_ADDRESS sentinel
if (targetTokenAddress.toLowerCase() === ETH_ADDRESS.toLowerCase()) {
return chainId === targetTokenChainId && !token.contractAddress
return !token.contractAddress
}

const tokenAddress = token.contractAddress || ETH_ADDRESS
return tokenAddress?.toLowerCase() === targetTokenAddress.toLowerCase() && chainId === targetTokenChainId
return tokenAddress?.toLowerCase() === targetTokenAddress.toLowerCase()
})
}

Expand Down