-
Notifications
You must be signed in to change notification settings - Fork 202
feat: integrate Story (1514) as second-class Relay chain #11936
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4e7cc39
6af57d8
39573f5
afd9d50
723ba6a
c88e783
f2a5684
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| [ | ||
| { | ||
| "id": "ss-dx5.16", | ||
| "title": "Integrate Story (chainId: 1514, IP, L1)", | ||
| "description": "TVL: $42.4M | RPC: https://mainnet.storyrpc.io | Explorer: https://storyscan.xyz | Token Support: All | Pattern B (RPC-only) | IP blockchain", | ||
| "notes": "\nLogo: https://assets.relay.link/icons/1514/light.png (dark: dark.png)\nCoinGecko platform: story\nCoinGecko native ID: story-2 (⚠️ NOT \"story\"!)\nArch: L1 (IP/Intellectual Property blockchain)\nNative token: IP (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: NO — IP gas token\nViem: ✅ story (id: 1514) — import { story } from \"viem/chains\"\nAcross: ❌ NOT SUPPORTED\nZerion ID: \"story\" (standard lowercase)\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_1514/adapter.json → {\"eip155:1514/slip44:60\":\"story-2\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add storyChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"story\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ❌ SKIP — not supported\n[ ] ETH test ordering: ❌ SKIP — not ETH-native\n[ ] Market-service counts: ❌ SKIP — not ETH-native\n[ ] relatedAssetKey: null (NOT eip155:1/slip44:60)\n\n--- RELAY ACTIVATION ---\n[ ] Add [storyChainId]: story.id to chainIdToRelayChainId\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/story/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-story-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", | ||
| "status": "open", | ||
| "priority": 2, | ||
| "issue_type": "task", | ||
| "owner": "14963751+NeOMakinG@users.noreply.github.com", | ||
| "created_at": "2026-02-17T10:56:01Z", | ||
| "created_by": "NeOMakinG", | ||
| "updated_at": "2026-02-17T22:43:23Z", | ||
| "labels": [ | ||
| "evm", | ||
| "non-eth-gas", | ||
| "relay", | ||
| "tier-2" | ||
| ], | ||
| "dependencies": [ | ||
| { | ||
| "id": "ss-dx5", | ||
| "title": "Add support for missing Relay.link EVM chains", | ||
| "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", | ||
| "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", | ||
| "status": "open", | ||
| "priority": 0, | ||
| "issue_type": "epic", | ||
| "owner": "14963751+NeOMakinG@users.noreply.github.com", | ||
| "created_at": "2026-02-17T10:55:02Z", | ||
| "created_by": "NeOMakinG", | ||
| "updated_at": "2026-02-17T11:21:27Z", | ||
| "external_ref": "gh-11902", | ||
| "dependency_type": "parent-child" | ||
| } | ||
| ], | ||
| "parent": "ss-dx5" | ||
| } | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import { loadEnv } from 'vite' | ||
|
|
||
| import type { Csp } from '../../types' | ||
|
|
||
| const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' | ||
| const env = loadEnv(mode, process.cwd(), '') | ||
|
|
||
| export const csp: Csp = { | ||
| 'connect-src': [env.VITE_STORY_NODE_URL], | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| {"eip155:1514/slip44:60":"story-2"} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -70,6 +70,8 @@ import { | |
| sonicChainId, | ||
| starknetAssetId, | ||
| starknetChainId, | ||
| storyAssetId, | ||
| storyChainId, | ||
| suiAssetId, | ||
| suiChainId, | ||
| thorchainChainId, | ||
|
|
@@ -431,6 +433,20 @@ export const parseData = (coins: CoingeckoCoin[]): AssetMap => { | |
| } | ||
| } | ||
|
|
||
| if (Object.keys(platforms).includes(CoingeckoAssetPlatform.Story)) { | ||
| try { | ||
| const assetId = toAssetId({ | ||
| chainNamespace: CHAIN_NAMESPACE.Evm, | ||
| chainReference: CHAIN_REFERENCE.StoryMainnet, | ||
| assetNamespace: 'erc20', | ||
| assetReference: platforms[CoingeckoAssetPlatform.Story], | ||
| }) | ||
| prev[storyChainId][assetId] = id | ||
| } catch { | ||
| // unable to create assetId, skip token | ||
| } | ||
| } | ||
|
|
||
| if (Object.keys(platforms).includes(CoingeckoAssetPlatform.ZkSyncEra)) { | ||
| try { | ||
| const assetId = toAssetId({ | ||
|
|
@@ -606,6 +622,7 @@ export const parseData = (coins: CoingeckoCoin[]): AssetMap => { | |
| [berachainChainId]: { [berachainAssetId]: 'berachain-bera' }, | ||
| [cronosChainId]: { [cronosAssetId]: 'crypto-com-chain' }, | ||
| [katanaChainId]: { [katanaAssetId]: 'katana' }, | ||
| [storyChainId]: { [storyAssetId]: 'story-2' }, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: Story Protocol’s native IP token (“Story”, ticker IP) has CoinGecko coin ID: 🏁 Script executed: # Check the actual line 625 in the utils.ts file
sed -n '620,630p' packages/caip/src/adapters/coingecko/utils.tsRepository: shapeshift/web Length of output: 696 🏁 Script executed: # Check for all references to story in the coingecko utils file
rg -n "story" packages/caip/src/adapters/coingecko/utils.ts -iRepository: shapeshift/web Length of output: 413 🏁 Script executed: # Check the test file for references to story
rg -n "story" packages/caip/src/adapters/coingecko/utils.test.ts -i -A 2 -B 2Repository: shapeshift/web Length of output: 194 Wrong CoinGecko coin ID for Story Protocol's native IP asset — will source market data from incorrect token.
Update line 625 in Proposed fixes- [storyChainId]: { [storyAssetId]: 'story-2' },
+ [storyChainId]: { [storyAssetId]: 'story' },- 'eip155:1514/slip44:60': 'story-2',
+ 'eip155:1514/slip44:60': 'story',🤖 Prompt for AI Agents |
||
| [zkSyncEraChainId]: { [zkSyncEraAssetId]: 'ethereum' }, | ||
| [blastChainId]: { [blastAssetId]: 'ethereum' }, | ||
| [worldChainChainId]: { [worldChainAssetId]: 'ethereum' }, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test expectation will need updating once the CoinGecko ID bug in
utils.tsis fixed.See the comment on
packages/caip/src/adapters/coingecko/utils.ts— the coin ID'story-2'is incorrect. Once that is corrected to'story', this expectation should become:🐛 Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents