Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ VITE_FEATURE_POLYGON=true
VITE_FEATURE_GNOSIS=true
VITE_FEATURE_ARBITRUM=true
VITE_FEATURE_SOLANA=true
VITE_FEATURE_STARGATE_SWAP=true
VITE_FEATURE_STARKNET=true
VITE_FEATURE_SUI=true
VITE_FEATURE_MAYACHAIN=true
Expand Down
1 change: 1 addition & 0 deletions .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,4 @@ VITE_PROXY_API_BASE_URL=https://dev-api.proxy.shapeshift.com

# Agentic Chat
# VITE_AGENTIC_SERVER_BASE_URL=http://localhost:4111
VITE_FEATURE_STARGATE_SWAP=true
1 change: 1 addition & 0 deletions .env.production
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ VITE_FEATURE_THORCHAIN_TCY_ACTIVITY=false
VITE_FEATURE_AGENTIC_CHAT=false
VITE_FEATURE_FLOWEVM=false
VITE_FEATURE_CELO=false
VITE_FEATURE_STARGATE_SWAP=false

# mixpanel
VITE_MIXPANEL_TOKEN=9d304465fc72224aead9e027e7c24356
102 changes: 102 additions & 0 deletions e2e/fixtures/stargate-usdc-eth-to-arb.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
name: Stargate USDC Ethereum → Arbitrum
description: >
Cross-chain USDC swap via Stargate V2 swapper: sell USDC on Ethereum mainnet,
receive USDC on Arbitrum One. Verifies that Stargate appears as a quote source,
that slippage is respected, and that the transaction builds and signs correctly.
route: /trade
depends_on:
- wallet-health.yaml

steps:
- name: Dismiss stale notifications
instruction: >
Dismiss any lingering notifications, toasts, or feedback dialogs from
previous tests (close buttons, "Maybe Later", etc.).
expected: Clean trade page with no overlays
screenshot: true

- name: Select USDC (Ethereum) as sell asset
instruction: >
Click the sell asset selector. Search for "USDC". From the results,
select "USD Coin (USDC)" on the Ethereum chain (not Arbitrum, not Base).
Verify USDC Ethereum is selected as the sell asset.
expected: USDC on Ethereum mainnet is the sell asset
screenshot: true

- name: Select USDC (Arbitrum) as buy asset
instruction: >
Click the buy/receive asset selector. Search for "USDC". From the results,
expand USDC if needed and select "USD Coin (USDC)" on the Arbitrum One chain.
Verify USDC on Arbitrum is selected as the buy asset.
expected: USDC on Arbitrum One is the buy asset
screenshot: true

- name: Toggle to fiat input mode
instruction: >
Click the "≈ $0.00" button below the sell amount to toggle to fiat/USD input mode.
If already in fiat mode (placeholder shows "$0"), skip this step.
expected: Sell input is in fiat/USD mode
screenshot: false

- name: Enter swap amount ($1)
instruction: >
Click the sell amount input and type "1" character by character using press
(NOT fill). Wait for the value to register.
expected: $1.00 entered as sell amount
screenshot: true

- name: Wait for Stargate quote
instruction: >
Wait up to 15 seconds for a quote to appear. Verify that:
1. The "You Get" field shows a USDC amount close to $1 (slightly less due to fees)
2. Stargate appears as the swapper source (look for "Stargate" label)
3. The "Preview Trade" button is enabled
If multiple swappers are shown, check that Stargate is one of them.
expected: >
Quote shown with a USDC receive amount slightly less than sell amount,
Stargate visible as source, Preview Trade button enabled
screenshot: true

- name: Verify protocol fee is displayed
instruction: >
In the quote view, look for a fee breakdown section. Verify that a protocol fee
is shown (the Stargate OFT fee, typically 0.5-1% of the swap amount).
Note the fee amount shown.
expected: Protocol fee visible in the quote breakdown
screenshot: true
Comment thread
coderabbitai[bot] marked this conversation as resolved.

- name: Preview trade
instruction: >
Click the "Preview Trade" button. Wait for the "Confirm Details" screen to appear
showing: sell amount (USDC Ethereum), receive amount (USDC Arbitrum), swapper name
(Stargate), estimated fees, and a "Confirm and Trade" button.
expected: >
Confirm Details screen visible with cross-chain summary:
sell = USDC on Ethereum, receive = USDC on Arbitrum, swapper = Stargate
screenshot: true

- name: Confirm and sign
instruction: >
Click the "Confirm and Trade" button. Wait up to 30 seconds for the
"Sign & Swap" button to become enabled (not loading/disabled).
Then click "Sign & Swap". The native wallet signs automatically.
expected: Transaction submitted, cross-chain swap in progress
screenshot: true

- name: Wait for Stargate bridge completion
instruction: >
Cross-chain Stargate bridges take 1-3 minutes (LayerZero messaging).
Wait up to 300 seconds for the swap to complete. Check every 10 seconds.
Look for: trade page reappearing, success notification, Arbitrum USDC
balance increased, or "Awaiting swap" disappearing.
A feedback dialog may appear — dismiss it with "Maybe Later".
expected: >
Swap completed — back on trade page, USDC balance on Arbitrum increased,
no "Awaiting swap" visible
screenshot: true

- name: Clean up notifications
instruction: >
Dismiss any remaining notifications, feedback dialogs, or toasts.
expected: Clean trade page, ready for next test
screenshot: true
5 changes: 5 additions & 0 deletions headers/csps/defi/swappers/Stargate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { Csp } from '../../../types'

export const csp: Csp = {
'connect-src': ['https://api-mainnet.layerzero-scan.com'],
}
2 changes: 2 additions & 0 deletions headers/csps/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import { csp as cowSwap } from './defi/swappers/CowSwap'
import { csp as nearIntents } from './defi/swappers/NearIntents'
import { csp as oneInch } from './defi/swappers/OneInch'
import { csp as portals } from './defi/swappers/Portals'
import { csp as stargate } from './defi/swappers/Stargate'
import { csp as stonfi } from './defi/swappers/Stonfi'
import { csp as sunio } from './defi/swappers/Sunio'
import { csp as thor } from './defi/swappers/Thor'
Expand Down Expand Up @@ -193,6 +194,7 @@ export const csps = [
sunio,
thor,
butterSwap,
stargate,
foxPage,
walletConnectToDapps,
coinbase,
Expand Down
11 changes: 11 additions & 0 deletions packages/swapper/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import { portalsApi } from './swappers/PortalsSwapper/endpoints'
import { portalsSwapper } from './swappers/PortalsSwapper/PortalsSwapper'
import { relaySwapper } from './swappers/RelaySwapper'
import { relayApi } from './swappers/RelaySwapper/endpoints'
import { stargateApi } from './swappers/StargateSwapper/endpoints'
import { stargateSwapper } from './swappers/StargateSwapper/StargateSwapper'
import { stonfiApi } from './swappers/StonfiSwapper/endpoints'
import { stonfiSwapper } from './swappers/StonfiSwapper/StonfiSwapper'
import { sunioApi } from './swappers/SunioSwapper/endpoints'
Expand Down Expand Up @@ -116,6 +118,10 @@ export const swappers: Record<SwapperName, (SwapperApi & Swapper) | undefined> =
...debridgeSwapper,
...debridgeApi,
},
[SwapperName.Stargate]: {
...stargateSwapper,
...stargateApi,
},
[SwapperName.Test]: undefined,
}

Expand All @@ -135,6 +141,7 @@ const DEFAULT_AVNU_SLIPPAGE_DECIMAL_PERCENTAGE = '0.02'
const DEFAULT_STONFI_SLIPPAGE_DECIMAL_PERCENTAGE = '0.01'
// deBridge API off-chain simulation overestimates output on some chains (e.g. SEI ~2.4%), so auto slippage (1%) is insufficient
const DEFAULT_DEBRIDGE_SLIPPAGE_DECIMAL_PERCENTAGE = '0.03'
const DEFAULT_STARGATE_SLIPPAGE_DECIMAL_PERCENTAGE = '0.005'

export const getDefaultSlippageDecimalPercentageForSwapper = (
swapperName: SwapperName | undefined,
Expand Down Expand Up @@ -175,6 +182,8 @@ export const getDefaultSlippageDecimalPercentageForSwapper = (
return DEFAULT_AVNU_SLIPPAGE_DECIMAL_PERCENTAGE
case SwapperName.Stonfi:
return DEFAULT_STONFI_SLIPPAGE_DECIMAL_PERCENTAGE
case SwapperName.Stargate:
return DEFAULT_STARGATE_SLIPPAGE_DECIMAL_PERCENTAGE
default:
return assertUnreachable(swapperName)
}
Expand All @@ -186,6 +195,8 @@ export const isAutoSlippageSupportedBySwapper = (swapperName: SwapperName): bool
case SwapperName.Across:
case SwapperName.Debridge:
return true
case SwapperName.Stargate:
return false
default:
return false
}
Expand Down
1 change: 1 addition & 0 deletions packages/swapper/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export * from './swappers/SunioSwapper'
export * from './swappers/CowSwapper'
export * from './swappers/DebridgeSwapper'
export * from './swappers/PortalsSwapper'
export * from './swappers/StargateSwapper'
export * from './swappers/ThorchainSwapper'
export * from './swappers/MayachainSwapper'
export * from './swappers/ButterSwap'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { Swapper } from '../../types'
import { executeEvmTransaction } from '../../utils'

export const stargateSwapper: Swapper = {
executeEvmTransaction,
}
107 changes: 107 additions & 0 deletions packages/swapper/src/swappers/StargateSwapper/constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import type { ChainId } from '@shapeshiftoss/caip'
import {
arbitrumChainId,
avalancheChainId,
baseChainId,
blastChainId,
bscChainId,
ethChainId,
gnosisChainId,
lineaChainId,
mantleChainId,
optimismChainId,
polygonChainId,
scrollChainId,
sonicChainId,
} from '@shapeshiftoss/caip'

const metisChainId: ChainId = 'eip155:1088' as ChainId

export const chainIdToStargateEndpointId = {
[ethChainId]: 30101,
[arbitrumChainId]: 30110,
[optimismChainId]: 30111,
[baseChainId]: 30184,
[polygonChainId]: 30109,
[bscChainId]: 30102,
[avalancheChainId]: 30106,
[scrollChainId]: 30214,
[lineaChainId]: 30183,
[mantleChainId]: 30181,
[gnosisChainId]: 30145,
[metisChainId]: 30151,
[sonicChainId]: 30332,
[blastChainId]: 30243,
} as const satisfies Record<ChainId, number>

export const STARGATE_SUPPORTED_CHAIN_IDS: ChainId[] = Object.keys(
chainIdToStargateEndpointId,
) as ChainId[]

export const stargateContractsByChainAndAsset: Record<string, Record<string, string>> = {
[ethChainId]: {
'0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48': '0xc026395860Db2d07ee33e05fE50ed7bD583189C7',
'0xdac17f958d2ee523a2206206994597c13d831ec7': '0x933597a323Eb81cAe705C5bC29985172fd5A3973',
'0x0000000000000000000000000000000000000000': '0x77b2043768d28E9C9aB44E1aBfC95944bcE57931',
'0x9e32b13ce7f2e80a01932b42553652e053d6ed8e': '0xcDafB1b2dB43f366E48e6F614b8DCCBFeeFEEcD3',
'0xd5f7838f5c461feff7fe49ea5ebaf7728bb0adfa': '0x268Ca24DAefF1FaC2ed883c598200CcbB79E931D',
'0x1abaea1f7c830bd89acc67ec4af516284b1bc33c': '0x783129E4d7bA0Af0C896c239E57C06DF379aAE8c',
},
[arbitrumChainId]: {
'0xaf88d065e77c8cc2239327c5edb3a432268e5831': '0xe8CDF27AcD73a434D661C84887215F7598e7d0d3',
'0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9': '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0',
'0x0000000000000000000000000000000000000000': '0xA45B5130f36CDcA45667738e2a258AB09f4A5f7F',
},
[optimismChainId]: {
'0x0b2c639c533813f4aa9d7837caf62653d097ff85': '0xcE8CcA271Ebc0533920C83d39F417ED6A0abB7D0',
'0x94b008aa00579c1307b0ef2c499ad98a8ce58e58': '0x19cFCE47eD54a88614648DC3f19A5980097007dD',
'0x0000000000000000000000000000000000000000': '0xe8CDF27AcD73a434D661C84887215F7598e7d0d3',
},
[baseChainId]: {
'0x833589fcd6edb6e08f4c7c32d4f71b54bda02913': '0x27a16dc786820B16E5c9028b75B99F6f604b5d26',
'0x0000000000000000000000000000000000000000': '0xdc181Bd607330aeeBEF6ea62e03e5e1Fb4B6F7C7',
},
[polygonChainId]: {
'0x3c499c542cef5e3811e1192ce70d8cc03d5c3359': '0x9Aa02D4Fae7F58b8E8f34c66E756cC734DAc7fe4',
'0xc2132d05d31c914a87c6611c10748aeb04b58e8f': '0xd47b03ee6d86Cf251ee7860FB2ACf9f91B9fD4d7',
},
[bscChainId]: {
'0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d': '0x962Bd449E630b0d928f308Ce63f1A21F02576057',
'0x55d398326f99059ff775485246999027b3197955': '0x138EB30f73BC423c6455C53df6D89CB01d9eBc63',
},
[avalancheChainId]: {
'0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e': '0x5634c4a5FEd09819E3c46D86A965Dd9447d86e47',
'0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7': '0x12dC9256Acc9895B076f6638D628382881e62CeE',
},
[scrollChainId]: {
'0x06efdbff2a14a7c8e15944d1f4a48f9f95f663a4': '0x3Fc69CC4A842838bCDC9499178740226062b14E4',
'0x0000000000000000000000000000000000000000': '0xC2b638Cb5042c1B3c5d5C969361fB50569840583',
},
[lineaChainId]: {
'0x0000000000000000000000000000000000000000': '0x81F6138153d473E8c5EcebD3DC8Cd4903506B075',
},
[mantleChainId]: {
'0x09bc4e0d864854c6afb6eb9a9cdf58ac190d0df9': '0xAc290Ad4e0c891FDc295ca4F0a6214cf6dC6acDC',
'0x201eba5cc46d216ce6dc03f6a759e8e766e956ae': '0xB715B85682B731dB9D5063187C450095c91C57FC',
'0xdeaddeaddeaddeaddeaddeaddeaddeaddead1111': '0x4c1d3Fc3fC3c177c3b633427c2F769276c547463',
'0xcda86a272531e8640cd7f1a92c01839911b90bb0': '0xF7628d84a2BbD9bb9c8E686AC95BB5d55169F3F1',
},
[gnosisChainId]: {
'0x2a22f9c3b484c3629090feed35f17ff8f88f76f0': '0xB1EeAD6959cb5bB9B20417d6689922523B2B86C3',
'0x6a023ccd1ff6f2045c3309768ead9e68f978f6e1': '0xe9aBA835f813ca05E50A6C0ce65D0D74390F7dE7',
},
[metisChainId]: {
'0xbb06dca3ae6887fabf931640f67cab3e3a16f4dc': '0x4dCBFC0249e8d5032F89D6461218a9D2eFff5125',
'0x420000000000000000000000000000000000000a': '0x36ed193dc7160D3858EC250e69D12B03Ca087D08',
'0xdeaddeaddeaddeaddeaddeaddeaddeaddead0000': '0xD9050e7043102a0391F81462a3916326F86331F0',
},
[sonicChainId]: {
'0x29219dd400f2bf60e5a23d13be72b486d4038894': '0xA272fFe20cFfe769CdFc4b63088DCD2C82a2D8F9',
},
}

export const STARGATE_NATIVE_ASSET_ADDRESS = '0x0000000000000000000000000000000000000000'

export const DEFAULT_STARGATE_USER_ADDRESS = '0x0000000000000000000000000000000000000dead'

export const DEFAULT_STARGATE_GAS_LIMIT = '500000'
Loading