@xlink-network/xlink-sdk
Version:
170 lines (157 loc) • 5 kB
text/typescript
import { getBtc2StacksFeeInfo } from "../bitcoinUtils/peggingHelpers"
import { getStacks2EvmFeeInfo } from "../evmUtils/peggingHelpers"
import { BigNumber } from "../utils/BigNumber"
import {
KnownRoute,
KnownRoute_FromBitcoin_ToEVM,
KnownRoute_FromBitcoin_ToStacks,
} from "../utils/buildSupportedRoutes"
import { UnsupportedBridgeRouteError } from "../utils/errors"
import { assertExclude, checkNever } from "../utils/typeHelpers"
import {
PublicTransferProphetAggregated,
transformToPublicTransferProphet,
transformToPublicTransferProphetAggregated,
} from "../utils/types/TransferProphet"
import { KnownChainId, KnownTokenId } from "../utils/types/knownIds"
import { supportedRoutes } from "./bridgeFromBitcoin"
import { ChainId, SDKNumber, TokenId } from "./types"
import { SDKGlobalContext } from "./types.internal"
export interface BridgeInfoFromBitcoinInput {
fromChain: ChainId
toChain: ChainId
fromToken: TokenId
toToken: TokenId
amount: SDKNumber
}
export interface BridgeInfoFromBitcoinOutput
extends PublicTransferProphetAggregated {}
export const bridgeInfoFromBitcoin = async (
ctx: SDKGlobalContext,
info: BridgeInfoFromBitcoinInput,
): Promise<BridgeInfoFromBitcoinOutput> => {
const route = await supportedRoutes.checkRouteValid(ctx, info)
if (KnownChainId.isBitcoinChain(route.fromChain)) {
if (KnownChainId.isStacksChain(route.toChain)) {
if (
KnownTokenId.isBitcoinToken(route.fromToken) &&
KnownTokenId.isStacksToken(route.toToken)
) {
return bridgeInfoFromBitcoin_toStacks({
...info,
fromChain: route.fromChain,
toChain: route.toChain,
fromToken: route.fromToken,
toToken: route.toToken,
})
}
} else if (KnownChainId.isEVMChain(route.toChain)) {
if (
KnownTokenId.isBitcoinToken(route.fromToken) &&
KnownTokenId.isEVMToken(route.toToken)
) {
return bridgeInfoFromBitcoin_toEVM({
...info,
fromChain: route.fromChain,
toChain: route.toChain,
fromToken: route.fromToken,
toToken: route.toToken,
})
}
} else if (
KnownChainId.isBRC20Chain(route.toChain) ||
KnownChainId.isRunesChain(route.toChain)
) {
assertExclude(route.toChain, assertExclude.i<KnownChainId.BRC20Chain>())
assertExclude(route.toChain, assertExclude.i<KnownChainId.RunesChain>())
// TODO: bitcoin to brc20/runes is not supported yet
} else {
assertExclude(route.toChain, assertExclude.i<KnownChainId.BitcoinChain>())
checkNever(route)
}
} else {
assertExclude(route.fromChain, assertExclude.i<KnownChainId.StacksChain>())
assertExclude(route.fromChain, assertExclude.i<KnownChainId.EVMChain>())
checkNever(route)
}
throw new UnsupportedBridgeRouteError(
info.fromChain,
info.toChain,
info.fromToken,
info.toToken,
)
}
async function bridgeInfoFromBitcoin_toStacks(
info: Omit<
BridgeInfoFromBitcoinInput,
"fromChain" | "toChain" | "fromToken" | "toToken"
> &
KnownRoute_FromBitcoin_ToStacks,
): Promise<BridgeInfoFromBitcoinOutput> {
const step1 = await getBtc2StacksFeeInfo(info)
if (step1 == null) {
throw new UnsupportedBridgeRouteError(
info.fromChain,
info.toChain,
info.fromToken,
info.toToken,
)
}
return {
...transformToPublicTransferProphet(info, info.amount, step1),
transferProphets: [],
}
}
async function bridgeInfoFromBitcoin_toEVM(
info: Omit<
BridgeInfoFromBitcoinInput,
"fromChain" | "toChain" | "fromToken" | "toToken"
> &
KnownRoute_FromBitcoin_ToEVM,
): Promise<BridgeInfoFromBitcoinOutput> {
const transitStacksChainId =
info.fromChain === KnownChainId.Bitcoin.Mainnet
? KnownChainId.Stacks.Mainnet
: KnownChainId.Stacks.Testnet
const step1Route: KnownRoute = {
fromChain: info.fromChain,
fromToken: KnownTokenId.Bitcoin.BTC,
toChain: transitStacksChainId,
toToken: KnownTokenId.Stacks.aBTC,
}
const step2Route: KnownRoute = {
fromChain: transitStacksChainId,
fromToken: KnownTokenId.Stacks.aBTC,
toChain: info.toChain,
toToken: info.toToken,
}
const [step1, step2] = await Promise.all([
getBtc2StacksFeeInfo(step1Route),
getStacks2EvmFeeInfo(step2Route),
])
if (step1 == null || step2 == null) {
throw new UnsupportedBridgeRouteError(
info.fromChain,
info.toChain,
info.fromToken,
info.toToken,
)
}
const step1TransferProphet = transformToPublicTransferProphet(
step1Route,
info.amount,
step1,
)
const step2TransferProphet = transformToPublicTransferProphet(
step2Route,
step1TransferProphet.toAmount,
step2,
)
return {
...transformToPublicTransferProphetAggregated(
[step1TransferProphet, step2TransferProphet],
[BigNumber.ONE],
),
transferProphets: [step1TransferProphet, step2TransferProphet],
}
}