mirror of
https://github.com/Brotocol-xyz/bro-sdk.git
synced 2026-04-28 19:35:10 +08:00
feat: implement Solana support in SDK with caching and route fetching
This commit is contained in:
@@ -296,6 +296,9 @@ export class BroSDK {
|
||||
tron: {
|
||||
routesConfigCache: new Map(),
|
||||
},
|
||||
solana: {
|
||||
routesConfigCache: new Map(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import { GeneralCacheInterface } from "../utils/types/GeneralCacheInterface"
|
||||
import { KnownChainId } from "../utils/types/knownIds"
|
||||
import { TransferProphet } from "../utils/types/TransferProphet"
|
||||
import { TronSupportedRoute } from "../tronUtils/types"
|
||||
import { SolanaSupportedRoute } from "../solanaUtils/types"
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
export interface SDKGlobalContextCache<K, V>
|
||||
@@ -94,4 +95,10 @@ export interface SDKGlobalContext {
|
||||
Promise<TronSupportedRoute[]>
|
||||
>
|
||||
}
|
||||
solana: {
|
||||
routesConfigCache?: SDKGlobalContextCache<
|
||||
"mainnet" | "testnet",
|
||||
Promise<SolanaSupportedRoute[]>
|
||||
>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
import { getStacksToken } from "../../stacksUtils/contractHelpers"
|
||||
import { requestAPI } from "../../utils/apiHelpers"
|
||||
import { BigNumber } from "../../utils/BigNumber"
|
||||
import { isNotNull } from "../../utils/typeHelpers"
|
||||
import { KnownChainId, KnownTokenId } from "../../utils/types/knownIds"
|
||||
import { StacksContractAddress } from "../../sdkUtils/types"
|
||||
import { SDKGlobalContext } from "../../sdkUtils/types.internal"
|
||||
|
||||
export interface SolanaSupportedRoute {
|
||||
evmToken: KnownTokenId.EVMToken
|
||||
stacksChain: KnownChainId.StacksChain
|
||||
stacksToken: KnownTokenId.StacksToken
|
||||
proxyStacksTokenContractAddress: null | StacksContractAddress
|
||||
pegOutFeeRate: BigNumber
|
||||
pegOutMinFeeAmount: null | BigNumber
|
||||
pegOutMinAmount: null | BigNumber
|
||||
pegOutMaxAmount: null | BigNumber
|
||||
}
|
||||
import { getStacksToken } from "../stacksUtils/contractHelpers"
|
||||
import { requestAPI } from "../utils/apiHelpers"
|
||||
import { BigNumber } from "../utils/BigNumber"
|
||||
import { isNotNull } from "../utils/typeHelpers"
|
||||
import { KnownChainId, KnownTokenId } from "../utils/types/knownIds"
|
||||
import { StacksContractAddress } from "../sdkUtils/types"
|
||||
import { SDKGlobalContext } from "../sdkUtils/types.internal"
|
||||
import { SolanaSupportedRoute } from "./types"
|
||||
|
||||
type NetworkType = "mainnet" | "testnet"
|
||||
|
||||
@@ -29,22 +19,22 @@ async function getSolanaSupportedRoutesByNetwork(
|
||||
sdkContext: SDKGlobalContext,
|
||||
network: NetworkType,
|
||||
): Promise<SolanaSupportedRoute[]> {
|
||||
const cacheKey = `solana-${network}`
|
||||
const cacheKey = network
|
||||
if (
|
||||
sdkContext.evm.routesConfigCache != null &&
|
||||
sdkContext.evm.routesConfigCache.get(cacheKey) != null
|
||||
sdkContext.solana.routesConfigCache != null &&
|
||||
sdkContext.solana.routesConfigCache.get(cacheKey) != null
|
||||
) {
|
||||
return sdkContext.evm.routesConfigCache.get(cacheKey)!
|
||||
return sdkContext.solana.routesConfigCache.get(cacheKey)!
|
||||
}
|
||||
|
||||
const promise = _getSolanaSupportedRoutes(sdkContext, network).catch(err => {
|
||||
const cachedPromise = sdkContext.evm.routesConfigCache?.get(cacheKey)
|
||||
const cachedPromise = sdkContext.solana.routesConfigCache?.get(cacheKey)
|
||||
if (promise === cachedPromise) {
|
||||
sdkContext.evm.routesConfigCache?.delete(cacheKey)
|
||||
sdkContext.solana.routesConfigCache?.delete(cacheKey)
|
||||
}
|
||||
throw err
|
||||
})
|
||||
sdkContext.evm.routesConfigCache?.set(cacheKey, promise)
|
||||
sdkContext.solana.routesConfigCache?.set(cacheKey, promise)
|
||||
return promise
|
||||
}
|
||||
|
||||
@@ -70,7 +60,7 @@ async function _getSolanaSupportedRoutes(
|
||||
|
||||
const routes = await Promise.all(
|
||||
resp.routes.map(async (route): Promise<null | SolanaSupportedRoute> => {
|
||||
const evmToken = route.evmToken as KnownTokenId.KnownToken
|
||||
const solanaToken = KnownTokenId.createSolanaToken(route.tokenAddress)
|
||||
const stacksToken = await getStacksToken(
|
||||
sdkContext,
|
||||
stacksChain,
|
||||
@@ -78,10 +68,10 @@ async function _getSolanaSupportedRoutes(
|
||||
)
|
||||
|
||||
if (stacksToken == null) return null
|
||||
if (!KnownTokenId.isEVMToken(evmToken)) return null
|
||||
if (!KnownTokenId.isSolanaToken(solanaToken)) return null
|
||||
|
||||
return {
|
||||
evmToken,
|
||||
solanaToken,
|
||||
stacksChain,
|
||||
stacksToken,
|
||||
proxyStacksTokenContractAddress: route.proxyStacksTokenContractAddress,
|
||||
@@ -106,7 +96,7 @@ async function _getSolanaSupportedRoutes(
|
||||
}
|
||||
|
||||
interface SupportedSolanaBridgeRoute {
|
||||
evmToken: string
|
||||
tokenAddress: `0x${string}`
|
||||
stacksTokenContractAddress: StacksContractAddress
|
||||
proxyStacksTokenContractAddress: null | StacksContractAddress
|
||||
pegOutFeeRate: `${number}`
|
||||
14
src/solanaUtils/types.ts
Normal file
14
src/solanaUtils/types.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { BigNumber } from "../utils/BigNumber"
|
||||
import { KnownChainId, KnownTokenId } from "../utils/types/knownIds"
|
||||
import { StacksContractAddress } from "../sdkUtils/types"
|
||||
|
||||
export interface SolanaSupportedRoute {
|
||||
solanaToken: KnownTokenId.SolanaToken
|
||||
stacksChain: KnownChainId.StacksChain
|
||||
stacksToken: KnownTokenId.StacksToken
|
||||
proxyStacksTokenContractAddress: null | StacksContractAddress
|
||||
pegOutFeeRate: BigNumber
|
||||
pegOutMinFeeAmount: null | BigNumber
|
||||
pegOutMinAmount: null | BigNumber
|
||||
pegOutMaxAmount: null | BigNumber
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import { getStacksToken } from "../../stacksUtils/contractHelpers"
|
||||
import { requestAPI } from "../../utils/apiHelpers"
|
||||
import { BigNumber } from "../../utils/BigNumber"
|
||||
import { isNotNull } from "../../utils/typeHelpers"
|
||||
import { KnownChainId, KnownTokenId } from "../../utils/types/knownIds"
|
||||
import { StacksContractAddress } from "../../sdkUtils/types"
|
||||
import { SDKGlobalContext } from "../../sdkUtils/types.internal"
|
||||
import { TronSupportedRoute } from "../../tronUtils/types"
|
||||
import { getStacksToken } from "../stacksUtils/contractHelpers"
|
||||
import { requestAPI } from "../utils/apiHelpers"
|
||||
import { BigNumber } from "../utils/BigNumber"
|
||||
import { isNotNull } from "../utils/typeHelpers"
|
||||
import { KnownChainId, KnownTokenId } from "../utils/types/knownIds"
|
||||
import { StacksContractAddress } from "../sdkUtils/types"
|
||||
import { SDKGlobalContext } from "../sdkUtils/types.internal"
|
||||
import { TronSupportedRoute } from "./types"
|
||||
|
||||
type NetworkType = "mainnet" | "testnet"
|
||||
|
||||
@@ -19,22 +19,22 @@ async function getTronSupportedRoutesByNetwork(
|
||||
sdkContext: SDKGlobalContext,
|
||||
network: NetworkType,
|
||||
): Promise<TronSupportedRoute[]> {
|
||||
const cacheKey = `tron-${network}`
|
||||
const cacheKey = network
|
||||
if (
|
||||
sdkContext.tron?.routesConfigCache != null &&
|
||||
sdkContext.tron.routesConfigCache != null &&
|
||||
sdkContext.tron.routesConfigCache.get(cacheKey) != null
|
||||
) {
|
||||
return sdkContext.tron.routesConfigCache.get(cacheKey)!
|
||||
}
|
||||
|
||||
const promise = _getTronSupportedRoutes(sdkContext, network).catch(err => {
|
||||
const cachedPromise = sdkContext.tron?.routesConfigCache?.get(cacheKey)
|
||||
const cachedPromise = sdkContext.tron.routesConfigCache?.get(cacheKey)
|
||||
if (promise === cachedPromise) {
|
||||
sdkContext.tron?.routesConfigCache?.delete(cacheKey)
|
||||
sdkContext.tron.routesConfigCache?.delete(cacheKey)
|
||||
}
|
||||
throw err
|
||||
})
|
||||
sdkContext.tron?.routesConfigCache?.set(cacheKey, promise)
|
||||
sdkContext.tron.routesConfigCache?.set(cacheKey, promise)
|
||||
return promise
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ async function _getTronSupportedRoutes(
|
||||
|
||||
const routes = await Promise.all(
|
||||
resp.routes.map(async (route): Promise<null | TronSupportedRoute> => {
|
||||
const tronToken = route.evmToken as KnownTokenId.KnownToken
|
||||
const tronToken = KnownTokenId.createTronToken(route.tokenAddress)
|
||||
const stacksToken = await getStacksToken(
|
||||
sdkContext,
|
||||
stacksChain,
|
||||
@@ -96,7 +96,7 @@ async function _getTronSupportedRoutes(
|
||||
}
|
||||
|
||||
interface SupportedTronBridgeRoute {
|
||||
evmToken: string
|
||||
tokenAddress: `0x${string}`
|
||||
stacksTokenContractAddress: StacksContractAddress
|
||||
proxyStacksTokenContractAddress: null | StacksContractAddress
|
||||
pegOutFeeRate: `${number}`
|
||||
@@ -177,38 +177,32 @@ export namespace KnownTokenId {
|
||||
return value.startsWith("stx-")
|
||||
}
|
||||
|
||||
/** A namespace that contains constants and types for Tron tokens. */
|
||||
export namespace Tron {
|
||||
/** Represents the USDT token ID on the Tron blockchain. */
|
||||
export const USDT = tokenId("tron-usdt")
|
||||
}
|
||||
/** This type defines known tokens on the Tron blockchain. */
|
||||
export type TronToken = (typeof _allKnownTronTokens)[number]
|
||||
export type TronToken = TokenId<"a tron token">
|
||||
export function isTronToken(value: TokenId): value is TronToken {
|
||||
return _allKnownTronTokens.includes(value as any)
|
||||
return value.startsWith("tron-")
|
||||
}
|
||||
export const createTronToken = (
|
||||
evmTokenAddress: `0x${string}`,
|
||||
): KnownTokenId.TronToken => {
|
||||
return `tron-${evmTokenAddress}` as any
|
||||
}
|
||||
|
||||
/** A namespace that contains constants and types for Solana tokens. */
|
||||
export namespace Solana {
|
||||
/** Represents the USDC token ID on the Solana blockchain. */
|
||||
export const USDC = tokenId("solana-usdc")
|
||||
/** Represents the USDT token ID on the Solana blockchain. */
|
||||
export const USDT = tokenId("solana-usdt")
|
||||
/** Represents the SOL token ID on the Solana blockchain. */
|
||||
export const SOL = tokenId("solana-sol")
|
||||
}
|
||||
/** This type defines known tokens on the Solana blockchain. */
|
||||
export type SolanaToken = (typeof _allKnownSolanaTokens)[number]
|
||||
export type SolanaToken = TokenId<"a solana token">
|
||||
export function isSolanaToken(value: TokenId): value is SolanaToken {
|
||||
return _allKnownSolanaTokens.includes(value as any)
|
||||
return value.startsWith("solana-")
|
||||
}
|
||||
export const createSolanaToken = (
|
||||
evmTokenAddress: `0x${string}`,
|
||||
): KnownTokenId.SolanaToken => {
|
||||
return `solana-${evmTokenAddress}` as any
|
||||
}
|
||||
}
|
||||
|
||||
export const _allKnownBitcoinTokens = Object.values(KnownTokenId.Bitcoin)
|
||||
export const _allKnownStacksTokens = Object.values(KnownTokenId.Stacks)
|
||||
export const _allKnownEVMTokens = Object.values(KnownTokenId.EVM)
|
||||
export const _allKnownTronTokens = Object.values(KnownTokenId.Tron)
|
||||
export const _allKnownSolanaTokens = Object.values(KnownTokenId.Solana)
|
||||
|
||||
/**
|
||||
* The `KnownChainId` namespace provides types of blockchain networks
|
||||
|
||||
Reference in New Issue
Block a user