Skip to content

Commit 5e59b4c

Browse files
feat: add solana chains
1 parent 406efce commit 5e59b4c

File tree

10 files changed

+176
-3
lines changed

10 files changed

+176
-3
lines changed

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@
6464
"types": "./dist/evm/releases/index.d.ts",
6565
"default": "./dist/evm/releases/index.js"
6666
},
67+
"./solana": {
68+
"types": "./dist/solana/index.d.ts",
69+
"default": "./dist/solana/index.js"
70+
},
6771
"./package.json": "./package.json",
6872
"./dist/*": "./dist/*"
6973
},

src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
export * from "./evm";
21
export * from "./helpers";
32
export * from "./sablier";
43
export * from "./types";

src/sablier.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* @file This file exports the Sablier object, singleton that contains the queries for the
3-
* chains, contracts, and releases.
3+
* chains, contracts, and releases for both evm and solana compatible chains.
44
*
55
* @example
66
* ```typescript
@@ -27,6 +27,7 @@ import _ from "lodash";
2727
import { chainsQueries as evmChainsQueries } from "./evm/chains/queries";
2828
import { contractsQueries as evmContractsQueries } from "./evm/contracts/queries";
2929
import { releasesQueries as evmReleasesQueries } from "./evm/releases/queries";
30+
import { chainsQueries as solanaChainsQueries } from "./solana/chains/queries";
3031

3132
/**
3233
* Has to be defined here to avoid circular dependencies.
@@ -53,7 +54,12 @@ const evm = {
5354
releases: evmReleasesQueries,
5455
};
5556

57+
const solana = {
58+
chains: solanaChainsQueries,
59+
};
60+
5661
export const sablier = {
5762
...evm, // re-exporting for backward compatibility
5863
evm,
64+
solana,
5965
};

src/solana/chains/data.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import type { Sablier } from "@src/types";
2+
3+
const CHAIN_ID_SOLANA_MAINNET_BETA = 900000010;
4+
const CHAIN_ID_SOLANA_DEVNET = 900000020;
5+
6+
export const solana_devnet: Sablier.Solana.Chain = {
7+
blockExplorers: {
8+
default: { name: "Explorer", url: "https://solscan.io?cluster=devnet" },
9+
solanaFm: {
10+
name: "Solana FM",
11+
url: "https://solana.fm?cluster=devnet-alpha",
12+
},
13+
},
14+
chainlink: {
15+
feed: "99B2bTijsU6f1GCT73HmdR7HCFFjGMBcPZY6jZ96ynrR",
16+
program: "HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny",
17+
},
18+
contracts: {},
19+
definition: {
20+
chainCode: "SOLDEV",
21+
chainId: CHAIN_ID_SOLANA_DEVNET,
22+
cluster: "devnet",
23+
},
24+
id: CHAIN_ID_SOLANA_DEVNET,
25+
isSupportedByUI: true,
26+
isTestnet: true,
27+
name: "Devnet",
28+
nativeCurrency: {
29+
coinGeckoId: "solana",
30+
decimals: 9,
31+
name: "Solana",
32+
symbol: "SOL",
33+
},
34+
rpc: {
35+
defaults: ["https://api.devnet-beta.solana.com/"],
36+
helius: (key) => `https://devnet.helius-rpc.com/?api-key=${key}`,
37+
},
38+
rpcUrls: {
39+
default: {
40+
http: ["https://api.devnet-beta.solana.com/"],
41+
},
42+
},
43+
slug: "solana-devnet",
44+
} as const;
45+
46+
export const solana_mainnetBeta: Sablier.Solana.Chain = {
47+
blockExplorers: {
48+
default: { name: "Explorer", url: "https://solscan.io" },
49+
solanaFm: { name: "Solana FM", url: "https://solana.fm" },
50+
},
51+
chainlink: {
52+
feed: "99B2bTijsU6f1GCT73HmdR7HCFFjGMBcPZY6jZ96ynrR",
53+
program: "HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny",
54+
},
55+
contracts: {},
56+
definition: {
57+
chainCode: "SOL",
58+
chainId: CHAIN_ID_SOLANA_MAINNET_BETA,
59+
cluster: "mainnet-beta",
60+
},
61+
id: CHAIN_ID_SOLANA_MAINNET_BETA,
62+
isSupportedByUI: true,
63+
isTestnet: false,
64+
name: "Solana",
65+
nativeCurrency: {
66+
coinGeckoId: "solana",
67+
decimals: 9,
68+
name: "Solana",
69+
symbol: "SOL",
70+
},
71+
rpc: {
72+
defaults: ["https://api.mainnet-beta.solana.com/"],
73+
helius: (key) => `https://mainnet.helius-rpc.com/?api-key=${key}`,
74+
},
75+
rpcUrls: {
76+
default: {
77+
http: ["https://api.mainnet-beta.solana.com/"],
78+
},
79+
},
80+
slug: "solana-mainnet-beta",
81+
} as const;

src/solana/chains/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * as chains from "./data";
2+
export * from "./data";

src/solana/chains/queries.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { sortChains } from "@src/helpers";
2+
import type { Sablier } from "@src/types";
3+
import _ from "lodash";
4+
import * as chains from "./data";
5+
6+
export const chainsQueries = {
7+
get: (chainId: number): Sablier.Solana.Chain | undefined => {
8+
return _.find(chains, (c) => c.id === chainId);
9+
},
10+
getAll: (): Sablier.Solana.Chain[] => {
11+
return sortChains(_.values(chains));
12+
},
13+
getBySlug: (slug: string): Sablier.Solana.Chain | undefined => {
14+
return _.find(chains, (c) => c.slug === slug);
15+
},
16+
getMainnets: (): Sablier.Solana.Chain[] => {
17+
return sortChains(_.filter(_.values(chains), (c) => !c.isTestnet));
18+
},
19+
getOrThrow: (chainId: number): Sablier.Solana.Chain => {
20+
const chain = _.find(chains, (c) => c.id === chainId);
21+
if (!chain) {
22+
throw new Error(`Sablier SDK: Chain with ID ${chainId} not found`);
23+
}
24+
return chain;
25+
},
26+
getTestnets: (): Sablier.Solana.Chain[] => {
27+
return sortChains(_.filter(_.values(chains), (c) => c.isTestnet));
28+
},
29+
};

src/solana/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
export { chains } from "./chains";
12
export * from "./idl";

src/solana/types.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import type { Chain as ViemChain } from "viem";
2+
3+
/**
4+
* @see https://github.com/wevm/viem/discussions/3678
5+
*/
6+
type ChainBlockExplorer = {
7+
name: string;
8+
url: string;
9+
apiUrl?: string | undefined;
10+
};
11+
12+
export namespace Solana {
13+
export type Address = string;
14+
export type ChainCode = "SOL" | "SOLDEV" | "SOLTEST";
15+
export type Cluster = "mainnet-beta" | "devnet" | "testnet";
16+
17+
export type Chain = ViemChain & {
18+
blockExplorers: {
19+
[key: string]: ChainBlockExplorer;
20+
default: ChainBlockExplorer;
21+
};
22+
/** Whether this chain is supported by the Sablier Interface at https://app.sablier.com. */
23+
isSupportedByUI: boolean;
24+
/** Whether this is a testnet network. */
25+
isTestnet: boolean;
26+
/** Whether this is a zkEVM like zkSync. */
27+
nativeCurrency: ViemChain["nativeCurrency"] & {
28+
coinGeckoId: string;
29+
};
30+
slug: string;
31+
32+
rpc: {
33+
/** Helius RPC URL generator. */
34+
helius?: (apiKey: string) => string;
35+
/** Default RPC URL. */
36+
defaults: string[];
37+
};
38+
/** Used in deployment files to identify the chain, e.g., arbitrum-sepolia. */
39+
chainlink: {
40+
program: Address; // Chainlink program used to retrieve on-chain price feeds
41+
feed: Address; // Account providing the SOL/USD price feed data.
42+
};
43+
definition: {
44+
chainCode: ChainCode;
45+
chainId: number;
46+
cluster: Cluster;
47+
};
48+
};
49+
}

src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import * as EVMTypes from "./evm/types";
2+
import * as SolanaTypes from "./solana/types";
23

34
export namespace Sablier {
45
export import EVM = EVMTypes.EVM;
6+
export import Solana = SolanaTypes.Solana;
57

68
/* -------------------------------------------------------------------------- */
79
/* BACKWARD COMPATIBILITY */

tests/helpers/missing.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const MISSING_CONTRACTS: ProtocolMap = {
5353
lockup: MISSING_LOCKUP,
5454
};
5555

56-
// Chains for which we completely lack broadcasts.
56+
// chains for which we completely lack broadcasts.
5757
export const MISSING_CHAINS: number[] = [chains.iotex.id, chains.ronin.id, chains.tangle.id];
5858

5959
export function isKnownMissing(release: Sablier.EVM.Release, chain: Sablier.EVM.Chain, contractName: string): boolean {

0 commit comments

Comments
 (0)