-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add solana chains #60
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
Merged
gavriliumircea
merged 2 commits into
10-20-feat_add_solana_idls
from
10-20-feat_add_solana_chains
Nov 6, 2025
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,29 +1,5 @@ | ||
| import { sortChains } from "@src/helpers"; | ||
| import { createChainQueries } from "@src/internal/factories/chains"; | ||
| import type { Sablier } from "@src/types"; | ||
| import _ from "lodash"; | ||
| import * as chains from "./data"; | ||
|
|
||
| export const chainsQueries = { | ||
| get: (chainId: number): Sablier.EVM.Chain | undefined => { | ||
| return _.find(chains, (c) => c.id === chainId); | ||
| }, | ||
| getAll: (): Sablier.EVM.Chain[] => { | ||
| return sortChains(_.values(chains)); | ||
| }, | ||
| getBySlug: (slug: string): Sablier.EVM.Chain | undefined => { | ||
| return _.find(chains, (c) => c.slug === slug); | ||
| }, | ||
| getMainnets: (): Sablier.EVM.Chain[] => { | ||
| return sortChains(_.filter(_.values(chains), (c) => !c.isTestnet)); | ||
| }, | ||
| getOrThrow: (chainId: number): Sablier.EVM.Chain => { | ||
| const chain = _.find(chains, (c) => c.id === chainId); | ||
| if (!chain) { | ||
| throw new Error(`Sablier SDK: Chain with ID ${chainId} not found`); | ||
| } | ||
| return chain; | ||
| }, | ||
| getTestnets: (): Sablier.EVM.Chain[] => { | ||
| return sortChains(_.filter(_.values(chains), (c) => c.isTestnet)); | ||
| }, | ||
| }; | ||
| export const chainsQueries = createChainQueries<Sablier.EVM.Chain>(chains); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,3 @@ | ||
| export * from "./evm"; | ||
| export * from "./helpers"; | ||
| export * from "./sablier"; | ||
| export * from "./types"; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| import { sortChains } from "@src/helpers"; | ||
| import type { Shared } from "@src/shared/types"; | ||
| import _ from "lodash"; | ||
|
|
||
| /** | ||
| * Generic factory function to create type-safe chain query objects. | ||
| * | ||
| * @template T - Chain type extending ChainCommon constraint | ||
| * @param chains - Record of chain definitions keyed by chain identifier | ||
| * @returns Query object with type-safe methods for chain operations | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * const evmQueries = createChainQueries<Sablier.EVM.Chain>(evmChains); | ||
| * const solanaQueries = createChainQueries<Sablier.Solana.Chain>(solanaChains); | ||
| * ``` | ||
| */ | ||
| export function createChainQueries<T extends Shared.Chain>(chains: Record<string, T>) { | ||
| return { | ||
| /** | ||
| * Find a chain by its numeric ID. | ||
| * | ||
| * @param chainId - The numeric chain identifier | ||
| * @returns The chain if found, undefined otherwise | ||
| */ | ||
| get: (chainId: number): T | undefined => { | ||
| return _.find(chains, (c) => c.id === chainId); | ||
| }, | ||
|
|
||
| /** | ||
| * Get all chains sorted by name. | ||
| * | ||
| * @returns Array of all chains sorted alphabetically | ||
| */ | ||
| getAll: (): T[] => { | ||
| return sortChains(_.values(chains)); | ||
| }, | ||
|
|
||
| /** | ||
| * Find a chain by its slug identifier. | ||
| * | ||
| * @param slug - The chain slug (e.g., "ethereum", "solana-mainnet") | ||
| * @returns The chain if found, undefined otherwise | ||
| */ | ||
| getBySlug: (slug: string): T | undefined => { | ||
| return _.find(chains, (c) => c.slug === slug); | ||
| }, | ||
|
|
||
| /** | ||
| * Get all mainnet chains sorted by name. | ||
| * | ||
| * @returns Array of mainnet chains sorted alphabetically | ||
| */ | ||
| getMainnets: (): T[] => { | ||
| return sortChains(_.filter(_.values(chains), (c) => !c.isTestnet)); | ||
| }, | ||
|
|
||
| /** | ||
| * Find a chain by its numeric ID, throwing an error if not found. | ||
| * | ||
| * @param chainId - The numeric chain identifier | ||
| * @returns The chain | ||
| * @throws Error if chain with the given ID is not found | ||
| */ | ||
| getOrThrow: (chainId: number): T => { | ||
| const chain = _.find(chains, (c) => c.id === chainId); | ||
| if (!chain) { | ||
| throw new Error(`Sablier SDK: Chain with ID ${chainId} not found`); | ||
| } | ||
| return chain; | ||
| }, | ||
|
|
||
| /** | ||
| * Get all testnet chains sorted by name. | ||
| * | ||
| * @returns Array of testnet chains sorted alphabetically | ||
| */ | ||
| getTestnets: (): T[] => { | ||
| return sortChains(_.filter(_.values(chains), (c) => c.isTestnet)); | ||
| }, | ||
| }; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import type { Chain as ViemChain } from "viem"; | ||
|
|
||
| /** | ||
| * @see https://github.com/wevm/viem/discussions/3678 | ||
| */ | ||
| type ChainBlockExplorer = { | ||
| name: string; | ||
| url: string; | ||
| apiUrl?: string | undefined; | ||
| }; | ||
|
|
||
| export namespace Shared { | ||
| /** | ||
| * Common properties shared by EVM and Solana chains. | ||
| * This type represents the minimal interface required for chain queries and operations. | ||
| */ | ||
| export type Chain = ViemChain & { | ||
| blockExplorers: { | ||
| [key: string]: ChainBlockExplorer; | ||
| default: ChainBlockExplorer; | ||
| }; | ||
| /** Whether this chain is supported by the Sablier Interface at https://app.sablier.com. */ | ||
| isSupportedByUI: boolean; | ||
| /** Whether this is a testnet network. */ | ||
| isTestnet: boolean; | ||
| nativeCurrency: ViemChain["nativeCurrency"] & { | ||
| coinGeckoId: string; | ||
| }; | ||
| rpc: { | ||
| /** Default RPC URL. */ | ||
| defaults: string[]; | ||
| [key: string]: unknown; | ||
| }; | ||
| /** Used in deployment files to identify the chain, e.g., arbitrum-sepolia. */ | ||
| slug: string; | ||
| }; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| import type { Sablier } from "@src/types"; | ||
|
|
||
gavriliumircea marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /** | ||
| * Solana does not have chain IDs. These are made-up numbers so that we can use the same type for EVM and Solana chains. | ||
| */ | ||
| const CHAIN_ID_SOLANA_MAINNET_BETA = 900000010; | ||
| const CHAIN_ID_SOLANA_DEVNET = 900000020; | ||
|
|
||
| export const solanaDevnet: Sablier.Solana.Chain = { | ||
| blockExplorers: { | ||
| default: { name: "Explorer", url: "https://solscan.io?cluster=devnet" }, | ||
| solanaFm: { | ||
| name: "Solana FM", | ||
| url: "https://solana.fm?cluster=devnet-alpha", | ||
| }, | ||
| }, | ||
| chainlink: { | ||
| feed: "99B2bTijsU6f1GCT73HmdR7HCFFjGMBcPZY6jZ96ynrR", | ||
| program: "HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny", | ||
razgraf marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }, | ||
| contracts: {}, | ||
| definition: { | ||
| chainCode: "SOLDEV", | ||
| chainId: CHAIN_ID_SOLANA_DEVNET, | ||
| cluster: "devnet", | ||
| }, | ||
| id: CHAIN_ID_SOLANA_DEVNET, | ||
| isSupportedByUI: true, | ||
| isTestnet: true, | ||
| name: "Devnet", | ||
| nativeCurrency: { | ||
| coinGeckoId: "solana", | ||
| decimals: 9, | ||
| name: "Solana", | ||
| symbol: "SOL", | ||
| }, | ||
| rpc: { | ||
| defaults: ["https://api.devnet-beta.solana.com/"], | ||
| helius: (key) => `https://devnet.helius-rpc.com/?api-key=${key}`, | ||
| }, | ||
| rpcUrls: { | ||
| default: { | ||
| http: ["https://api.devnet-beta.solana.com/"], | ||
| }, | ||
| }, | ||
| slug: "solana-devnet", | ||
| } as const; | ||
|
|
||
| export const solanaMainnetBeta: Sablier.Solana.Chain = { | ||
| blockExplorers: { | ||
| default: { name: "Explorer", url: "https://solscan.io" }, | ||
| solanaFm: { name: "Solana FM", url: "https://solana.fm" }, | ||
| }, | ||
| chainlink: { | ||
| feed: "99B2bTijsU6f1GCT73HmdR7HCFFjGMBcPZY6jZ96ynrR", | ||
| program: "HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny", | ||
| }, | ||
| contracts: {}, | ||
| definition: { | ||
| chainCode: "SOL", | ||
| chainId: CHAIN_ID_SOLANA_MAINNET_BETA, | ||
| cluster: "mainnet-beta", | ||
| }, | ||
| id: CHAIN_ID_SOLANA_MAINNET_BETA, | ||
| isSupportedByUI: true, | ||
| isTestnet: false, | ||
| name: "Solana", | ||
| nativeCurrency: { | ||
| coinGeckoId: "solana", | ||
| decimals: 9, | ||
| name: "Solana", | ||
| symbol: "SOL", | ||
| }, | ||
| rpc: { | ||
| defaults: ["https://api.mainnet-beta.solana.com/"], | ||
| helius: (key) => `https://mainnet.helius-rpc.com/?api-key=${key}`, | ||
| }, | ||
| rpcUrls: { | ||
| default: { | ||
| http: ["https://api.mainnet-beta.solana.com/"], | ||
| }, | ||
| }, | ||
| slug: "solana-mainnet-beta", | ||
| } as const; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| export * as chains from "./data"; | ||
| export * from "./data"; |
gavriliumircea marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import { createChainQueries } from "@src/internal/factories/chains"; | ||
| import type { Sablier } from "@src/types"; | ||
| import * as chains from "./data"; | ||
|
|
||
| export const chainsQueries = createChainQueries<Sablier.Solana.Chain>(chains); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| export enum ChainCode { | ||
| mainnet = "SOL", | ||
| devnet = "SOLDEV", | ||
| testnet = "SOLTEST", | ||
| } | ||
| export enum Cluster { | ||
| mainnet = "mainnet-beta", | ||
| devnet = "devnet", | ||
| testnet = "testnet", | ||
| } | ||
|
|
||
| export const enums = { | ||
| ChainCode, | ||
| Cluster, | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| export { chains } from "./chains"; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import type { Shared } from "@src/shared/types"; | ||
| import type * as enums from "./enums"; | ||
|
|
||
| export namespace Solana { | ||
| export type Address = string; | ||
| export type ChainCode = `${enums.ChainCode}` | enums.ChainCode; | ||
| export type Cluster = `${enums.Cluster}` | enums.Cluster; | ||
|
|
||
| export type Chain = Shared.Chain & { | ||
| rpc: Shared.Chain["rpc"] & { | ||
| /** Helius RPC URL generator. */ | ||
| helius?: (apiKey: string) => string; | ||
| }; | ||
| chainlink: { | ||
| program: Address; // Chainlink program used to retrieve on-chain price feeds | ||
| feed: Address; // Account providing the SOL/USD price feed data. | ||
| }; | ||
| definition: { | ||
| chainCode: ChainCode; | ||
| chainId: number; | ||
| cluster: Cluster; | ||
| }; | ||
| }; | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.