UNPKG

@xlink-network/xlink-sdk

Version:
187 lines (170 loc) 6.01 kB
import { callReadOnlyFunction } from "@stacks/transactions" import { CallReadOnlyFunctionFn, unwrapResponse } from "clarity-codegen" import { toCorrespondingStacksToken } from "../evmUtils/peggingHelpers" import { hasLength } from "../utils/arrayHelpers" import { UnsupportedBridgeRouteError } from "../utils/errors" import { decodeHex } from "../utils/hexHelpers" import { checkNever } from "../utils/typeHelpers" import { KnownChainId, KnownTokenId } from "../utils/types/knownIds" import { StacksContractAddress } from "../xlinkSdkUtils/types" import { contractAssignedChainIdFromKnownChain } from "./crossContractDataMapping" import { getTerminatingStacksTokenContractAddress } from "./stxContractAddresses" import { addressToBuffer, executeReadonlyCallXLINK, getStacksContractCallInfo, getStacksTokenContractInfo, } from "./xlinkContractHelpers" export interface BridgeSwapRouteNode { poolId: bigint tokenContractAddress: `${string}.${string}::${string}` } // prettier-ignore export type BridgeSwapRoute_FromBitcoin = | [] // | [BridgeSwapRouteNode] // | [BridgeSwapRouteNode, BridgeSwapRouteNode] // | [BridgeSwapRouteNode, BridgeSwapRouteNode, BridgeSwapRouteNode] export interface CreateBridgeOrderResult { terminatingStacksToken: StacksContractAddress data: Uint8Array } export async function createBridgeOrder_BitcoinToStacks(info: { fromChain: KnownChainId.BitcoinChain fromBitcoinScriptPubKey: Uint8Array toChain: KnownChainId.StacksChain toToken: KnownTokenId.StacksToken toStacksAddress: string swapRoute: BridgeSwapRoute_FromBitcoin swapSlippedAmount?: bigint }): Promise<undefined | CreateBridgeOrderResult> { let data: undefined | Uint8Array const contractCallInfo = getStacksContractCallInfo( info.toChain, "btc-peg-in-endpoint-v2-05", ) if (contractCallInfo == null) { throw new UnsupportedBridgeRouteError( info.fromChain, info.toChain, KnownTokenId.Bitcoin.BTC, info.toToken, ) } const { swapRoute, toStacksAddress /*, swapSlippedAmount = 0n */ } = info const executeOptions = { deployerAddress: contractCallInfo.deployerAddress, callReadOnlyFunction: (callOptions => callReadOnlyFunction({ ...callOptions, network: contractCallInfo.network, })) satisfies CallReadOnlyFunctionFn, } const targetTokenContractInfo = getStacksTokenContractInfo( info.toChain, info.toToken, ) if (targetTokenContractInfo == null) { return undefined } if (hasLength(swapRoute, 0)) { data = await executeReadonlyCallXLINK( contractCallInfo.contractName, "create-order-cross-or-fail", { order: { from: info.fromBitcoinScriptPubKey, to: addressToBuffer(info.toChain, toStacksAddress), "chain-id": undefined, token: `${targetTokenContractInfo.deployerAddress}.${targetTokenContractInfo.contractName}`, "token-out": `${targetTokenContractInfo.deployerAddress}.${targetTokenContractInfo.contractName}`, }, }, executeOptions, ).then(unwrapResponse) } else { checkNever(swapRoute) } return { terminatingStacksToken: targetTokenContractInfo, data: data!, } } export async function createBridgeOrder_BitcoinToEVM(info: { fromChain: KnownChainId.BitcoinChain fromBitcoinScriptPubKey: Uint8Array toChain: KnownChainId.EVMChain toToken: KnownTokenId.EVMToken toEVMAddress: string swapRoute: BridgeSwapRoute_FromBitcoin swapSlippedAmount?: bigint }): Promise<undefined | CreateBridgeOrderResult> { const contractCallInfo = getStacksContractCallInfo( info.fromChain === KnownChainId.Bitcoin.Mainnet ? KnownChainId.Stacks.Mainnet : KnownChainId.Stacks.Testnet, "btc-peg-in-endpoint-v2-05", ) if (contractCallInfo == null) { throw new UnsupportedBridgeRouteError( info.fromChain, info.toChain, KnownTokenId.Bitcoin.BTC, info.toToken, ) } const { swapRoute, toEVMAddress /*, swapSlippedAmount = 0n */ } = info const executeOptions = { deployerAddress: contractCallInfo.deployerAddress, callReadOnlyFunction: (callOptions => callReadOnlyFunction({ ...callOptions, network: contractCallInfo.network, })) satisfies CallReadOnlyFunctionFn, } const targetChainId = contractAssignedChainIdFromKnownChain(info.toChain) const swappedStacksToken = await toCorrespondingStacksToken(info.toToken) if (swappedStacksToken == null) return undefined const swappedStacksTokenAddress = getStacksTokenContractInfo( contractCallInfo.network.isMainnet() ? KnownChainId.Stacks.Mainnet : KnownChainId.Stacks.Testnet, swappedStacksToken, ) if (swappedStacksTokenAddress == null) return undefined const terminatingStacksTokenAddress = getTerminatingStacksTokenContractAddress({ fromChain: contractCallInfo.network.isMainnet() ? KnownChainId.Stacks.Mainnet : KnownChainId.Stacks.Testnet, fromToken: swappedStacksToken, toChain: info.toChain, toToken: info.toToken, }) ?? swappedStacksTokenAddress let data: undefined | Uint8Array if (hasLength(swapRoute, 0)) { data = await executeReadonlyCallXLINK( contractCallInfo.contractName, "create-order-cross-or-fail", { order: { from: info.fromBitcoinScriptPubKey, to: decodeHex(toEVMAddress), "chain-id": targetChainId, token: `${swappedStacksTokenAddress.deployerAddress}.${swappedStacksTokenAddress.contractName}`, "token-out": `${terminatingStacksTokenAddress.deployerAddress}.${terminatingStacksTokenAddress.contractName}`, }, }, executeOptions, ).then(unwrapResponse) } else { checkNever(swapRoute) } return { terminatingStacksToken: { deployerAddress: terminatingStacksTokenAddress.deployerAddress, contractName: terminatingStacksTokenAddress.contractName, }, data: data!, } }