@xlink-network/xlink-sdk
Version:
385 lines (360 loc) • 10.7 kB
text/typescript
import { getStacks2BtcFeeInfo } from "../bitcoinUtils/peggingHelpers"
import { nativeCurrencyAddress } from "../evmUtils/addressHelpers"
import {
getEvm2StacksFeeInfo,
getStacks2EvmFeeInfo,
toCorrespondingStacksToken,
} from "../evmUtils/peggingHelpers"
import { getEVMTokenContractInfo } from "../evmUtils/xlinkContractHelpers"
import { getStacks2MetaFeeInfo } from "../metaUtils/peggingHelpers"
import { BigNumber } from "../utils/BigNumber"
import {
KnownRoute,
KnownRoute_FromEVM_ToBitcoin,
KnownRoute_FromEVM_ToBRC20,
KnownRoute_FromEVM_ToEVM,
KnownRoute_FromEVM_ToRunes,
KnownRoute_FromEVM_ToStacks,
KnownRoute_FromStacks_ToBRC20,
KnownRoute_FromStacks_ToRunes,
} 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 "./bridgeFromEVM"
import { ChainId, SDKNumber, TokenId } from "./types"
import { SDKGlobalContext } from "./types.internal"
export interface BridgeInfoFromEVMInput {
fromChain: ChainId
toChain: ChainId
fromToken: TokenId
toToken: TokenId
amount: SDKNumber
}
export interface BridgeInfoFromEVMOutput
extends PublicTransferProphetAggregated {}
export async function bridgeInfoFromEVM(
ctx: SDKGlobalContext,
info: BridgeInfoFromEVMInput,
): Promise<BridgeInfoFromEVMOutput> {
const route = await supportedRoutes.checkRouteValid(ctx, info)
if (KnownChainId.isEVMChain(route.fromChain)) {
if (KnownChainId.isStacksChain(route.toChain)) {
if (
KnownTokenId.isEVMToken(route.fromToken) &&
KnownTokenId.isStacksToken(route.toToken)
) {
return bridgeInfoFromEVM_toStacks(ctx, {
...info,
fromChain: route.fromChain,
toChain: route.toChain,
fromToken: route.fromToken,
toToken: route.toToken,
})
}
} else if (KnownChainId.isBitcoinChain(route.toChain)) {
if (
KnownTokenId.isEVMToken(route.fromToken) &&
KnownTokenId.isBitcoinToken(route.toToken)
) {
return bridgeInfoFromEVM_toBitcoin(ctx, {
...info,
fromChain: route.fromChain,
toChain: route.toChain,
fromToken: route.fromToken,
toToken: route.toToken,
})
}
} else if (KnownChainId.isEVMChain(route.toChain)) {
if (
KnownTokenId.isEVMToken(route.fromToken) &&
KnownTokenId.isEVMToken(route.toToken)
) {
return bridgeInfoFromEVM_toEVM(ctx, {
...info,
fromChain: route.fromChain,
toChain: route.toChain,
fromToken: route.fromToken,
toToken: route.toToken,
})
}
} else if (KnownChainId.isBRC20Chain(route.toChain)) {
if (
KnownTokenId.isEVMToken(route.fromToken) &&
KnownTokenId.isBRC20Token(route.toToken)
) {
return bridgeInfoFromEVM_toMeta(ctx, {
...info,
fromChain: route.fromChain,
toChain: route.toChain,
fromToken: route.fromToken,
toToken: route.toToken,
})
}
} else if (KnownChainId.isRunesChain(route.toChain)) {
if (
KnownTokenId.isEVMToken(route.fromToken) &&
KnownTokenId.isRunesToken(route.toToken)
) {
return bridgeInfoFromEVM_toMeta(ctx, {
...info,
fromChain: route.fromChain,
toChain: route.toChain,
fromToken: route.fromToken,
toToken: route.toToken,
})
}
} else {
checkNever(route.toChain)
}
} else {
assertExclude(route.fromChain, assertExclude.i<KnownChainId.StacksChain>())
assertExclude(route.fromChain, assertExclude.i<KnownChainId.BitcoinChain>())
checkNever(route)
}
throw new UnsupportedBridgeRouteError(
info.fromChain,
info.toChain,
info.fromToken,
info.toToken,
)
}
async function bridgeInfoFromEVM_toStacks(
ctx: SDKGlobalContext,
info: Omit<
BridgeInfoFromEVMInput,
"fromChain" | "toChain" | "fromToken" | "toToken"
> &
KnownRoute_FromEVM_ToStacks,
): Promise<BridgeInfoFromEVMOutput> {
const step1 = await getEvm2StacksFeeInfo(ctx, info)
const evmTokenContractCallInfo = await getEVMTokenContractInfo(
ctx,
info.fromChain,
info.fromToken,
)
if (
step1 == null ||
evmTokenContractCallInfo?.tokenContractAddress === nativeCurrencyAddress
) {
throw new UnsupportedBridgeRouteError(
info.fromChain,
info.toChain,
info.fromToken,
info.toToken,
)
}
return {
...transformToPublicTransferProphet(info, info.amount, step1),
transferProphets: [],
}
}
async function bridgeInfoFromEVM_toBitcoin(
ctx: SDKGlobalContext,
info: Omit<
BridgeInfoFromEVMInput,
"fromChain" | "toChain" | "fromToken" | "toToken"
> &
KnownRoute_FromEVM_ToBitcoin,
): Promise<BridgeInfoFromEVMOutput> {
const transitStacksChain = KnownChainId.isEVMMainnetChain(info.fromChain)
? KnownChainId.Stacks.Mainnet
: KnownChainId.Stacks.Testnet
const transitStacksToken = await toCorrespondingStacksToken(info.fromToken)
if (transitStacksToken == null) {
throw new UnsupportedBridgeRouteError(
info.fromChain,
info.toChain,
info.fromToken,
info.toToken,
)
}
const step1Route: KnownRoute = {
fromChain: info.fromChain,
fromToken: info.fromToken,
toChain: transitStacksChain,
toToken: transitStacksToken,
}
const step2Route: KnownRoute = {
fromChain: transitStacksChain,
fromToken: transitStacksToken,
toChain: info.toChain,
toToken: info.toToken,
}
const [step1, step2] = await Promise.all([
getEvm2StacksFeeInfo(ctx, step1Route),
getStacks2BtcFeeInfo(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],
}
}
async function bridgeInfoFromEVM_toEVM(
ctx: SDKGlobalContext,
info: Omit<
BridgeInfoFromEVMInput,
"fromChain" | "toChain" | "fromToken" | "toToken"
> &
KnownRoute_FromEVM_ToEVM,
): Promise<BridgeInfoFromEVMOutput> {
const evmTokenContractCallInfo = await getEVMTokenContractInfo(
ctx,
info.fromChain,
info.fromToken,
)
const transitStacksChain = KnownChainId.isEVMMainnetChain(info.fromChain)
? KnownChainId.Stacks.Mainnet
: KnownChainId.Stacks.Testnet
const transitStacksToken = await toCorrespondingStacksToken(info.fromToken)
if (
transitStacksToken == null ||
evmTokenContractCallInfo?.tokenContractAddress === nativeCurrencyAddress
) {
throw new UnsupportedBridgeRouteError(
info.fromChain,
info.toChain,
info.fromToken,
info.toToken,
)
}
const step1Route: KnownRoute = {
fromChain: info.fromChain,
fromToken: info.fromToken,
toChain: transitStacksChain,
toToken: transitStacksToken,
}
const step2Route: KnownRoute = {
fromChain: transitStacksChain,
fromToken: transitStacksToken,
toChain: info.toChain,
toToken: info.toToken,
}
const [step1, step2] = await Promise.all([
getEvm2StacksFeeInfo(ctx, 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],
}
}
async function bridgeInfoFromEVM_toMeta(
ctx: SDKGlobalContext,
info: Omit<
BridgeInfoFromEVMInput,
"fromChain" | "toChain" | "fromToken" | "toToken"
> &
(KnownRoute_FromEVM_ToBRC20 | KnownRoute_FromEVM_ToRunes),
): Promise<BridgeInfoFromEVMOutput> {
const evmTokenContractCallInfo = await getEVMTokenContractInfo(
ctx,
info.fromChain,
info.fromToken,
)
const transitStacksChain = KnownChainId.isEVMMainnetChain(info.fromChain)
? KnownChainId.Stacks.Mainnet
: KnownChainId.Stacks.Testnet
const transitStacksToken = await toCorrespondingStacksToken(info.fromToken)
if (
transitStacksToken == null ||
evmTokenContractCallInfo?.tokenContractAddress === nativeCurrencyAddress
) {
throw new UnsupportedBridgeRouteError(
info.fromChain,
info.toChain,
info.fromToken,
info.toToken,
)
}
const step1Route: KnownRoute = {
fromChain: info.fromChain,
fromToken: info.fromToken,
toChain: transitStacksChain,
toToken: transitStacksToken,
}
const step2Route:
| KnownRoute_FromStacks_ToBRC20
| KnownRoute_FromStacks_ToRunes = {
fromChain: transitStacksChain,
fromToken: transitStacksToken,
toChain: info.toChain as any,
toToken: info.toToken as any,
}
const [step1, step2] = await Promise.all([
getEvm2StacksFeeInfo(ctx, step1Route),
getStacks2MetaFeeInfo(ctx, 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],
}
}