Skip to content
This repository was archived by the owner on Aug 6, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
"prepare": "husky && ./scripts/gen-defuse-types.sh"
},
"dependencies": {
"@defuse-protocol/bridge-sdk": "^0.7.4",
"@defuse-protocol/bridge-sdk": "0.10.0",
"@defuse-protocol/internal-utils": "0.1.2",
"@lifeomic/attempt": "^3.1.0",
"@noble/curves": "1.4.0",
"@noble/hashes": "^1.7.1",
Expand Down
20 changes: 15 additions & 5 deletions src/constants/aurora.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,36 @@
import type { SupportedChainName } from "src/types/base"
import type { VirtualChains } from "../types/base"

/**
* SiloToSilo addresses on blockchains within Aurora Engine
*/
export const siloToSiloAddress = {
export const siloToSiloAddress: Record<VirtualChains, string> = {
aurora: "0x055707c67977e8217F98f19cFa8aca18B2282D0C",
turbochain: "0x8a4Bf14C51e1092581F1392810eE38c5A20f83da",
tuxappchain: "0xA50fFd8a0953B3965E70C4F7F880B00BcdB9A313",
vertex: "0xA50fFd8a0953B3965E70C4F7F880B00BcdB9A313",
optima: "0xA50fFd8a0953B3965E70C4F7F880B00BcdB9A313",
easychain: "0xA50fFd8a0953B3965E70C4F7F880B00BcdB9A313",
} as const
}

/**
* Account ids on Near of Aurora Engine powered blockchains
* Mapping: ChainName -> AccountId
*/
export const auroraEngineContractId = {
export const auroraEngineContractId: Record<VirtualChains, string> = {
aurora: "aurora",
turbochain: "0x4e45415f.c.aurora",
tuxappchain: "0x4e454165.c.aurora",
vertex: "0x4e454173.c.aurora",
optima: "0x4e454161.c.aurora",
easychain: "0x4e454218.c.aurora",
} as Record<SupportedChainName, string>
}

export function getAuroraEngineContractId(chainName: string) {
if (!(chainName in auroraEngineContractId)) {
throw new Error(`Unsupported virtual chain = ${chainName}`)
}

return auroraEngineContractId[
chainName as keyof typeof auroraEngineContractId
]
}
43 changes: 22 additions & 21 deletions src/features/machines/intentStatusMachine.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import type { BridgeSDK } from "@defuse-protocol/bridge-sdk"
import {
type RouteConfig,
createNearWithdrawalRoute,
createVirtualChainRoute,
} from "@defuse-protocol/bridge-sdk"
import { solverRelay } from "@defuse-protocol/internal-utils"
import {
type ActorRef,
Expand All @@ -9,7 +13,7 @@ import {
sendTo,
setup,
} from "xstate"
import { auroraEngineContractId } from "../../constants/aurora"
import { getAuroraEngineContractId } from "../../constants/aurora"
import { bridgeSDK } from "../../constants/bridgeSdk"
import { logger } from "../../logger"
import type {
Expand All @@ -20,7 +24,7 @@ import type {
} from "../../types/base"
import type { IntentsUserId } from "../../types/intentsUserId"
import { assert } from "../../utils/assert"
import { CAIP2_NETWORK } from "../../utils/caip2"
import { getCAIP2 } from "../../utils/caip2"
import type { IntentDescription } from "./swapIntentMachine"

type ChildEvent = {
Expand Down Expand Up @@ -99,7 +103,7 @@ export const intentStatusMachine = setup({
}) => {
return bridgeSDK
.waitForWithdrawalCompletion({
bridge: toBridgeConfig(
routeConfig: toRouteConfig(
input.nearIntentsNetwork ? "direct" : input.bridge,
input.chainName
),
Expand Down Expand Up @@ -249,32 +253,29 @@ export const intentStatusMachine = setup({
},
})

function toBridgeConfig(
function toRouteConfig(
bridge: SupportedBridge,
chainName: SupportedChainName
): Parameters<
(typeof BridgeSDK.prototype)["waitForWithdrawalCompletion"]
>["0"]["bridge"] {
): RouteConfig {
switch (bridge) {
case "aurora_engine":
return {
bridge,
auroraEngineContractId: auroraEngineContractId[chainName],
proxyTokenContractId: null, // TODO: provide the correct value once you know it
}
case "aurora_engine": {
return createVirtualChainRoute(
getAuroraEngineContractId(chainName),
null // TODO: provide the correct value once you know it
)
}
case "hot_omni":
return {
bridge: "hot",
// biome-ignore lint/suspicious/noExplicitAny: it expects just a caip2 string, but mistakenly strongly typed
chain: CAIP2_NETWORK[chainName] as any,
route: "hot_bridge",
chain: getCAIP2(chainName),
}
case "poa":
case "direct":
return {
bridge,
// biome-ignore lint/suspicious/noExplicitAny: it expects just a caip2 string, but mistakenly strongly typed
chain: CAIP2_NETWORK[chainName] as any,
route: "poa_bridge",
chain: getCAIP2(chainName),
}
case "direct":
return createNearWithdrawalRoute()
default:
bridge satisfies never
throw new Error(`Unsupported bridge: ${bridge}`)
Expand Down
6 changes: 5 additions & 1 deletion src/sdk/aggregatedQuote/getAggregatedQuoteExactIn.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import { QuoteError } from "../solverRelay/errors/quote"
import { AggregatedQuoteError } from "./errors/aggregatedQuoteError"
import { getAggregatedQuoteExactIn } from "./getAggregatedQuoteExactIn"

vi.spyOn(solverRelay, "quote")
vi.mock("@defuse-protocol/internal-utils", () => ({
solverRelay: {
quote: vi.fn(),
},
}))

const tokenInfo: BaseTokenInfo = {
defuseAssetId: "",
Expand Down
6 changes: 5 additions & 1 deletion src/services/quoteService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import type { BaseTokenInfo } from "../types/base"
import { adjustDecimals } from "../utils/tokenUtils"
import { queryQuote } from "./quoteService"

vi.spyOn(solverRelay, "quote")
vi.mock("@defuse-protocol/internal-utils", () => ({
solverRelay: {
quote: vi.fn(),
},
}))

const tokenInfo: BaseTokenInfo = {
defuseAssetId: "",
Expand Down
52 changes: 19 additions & 33 deletions src/services/withdrawService.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import {
type FeeEstimation,
FeeExceedsAmountError,
type RouteConfig,
createDefaultRoute,
createInternalTransferRoute,
createNearWithdrawalRoute,
createVirtualChainRoute,
} from "@defuse-protocol/bridge-sdk"
import { Err, Ok, type Result } from "@thames/monads"
import { type ActorRefFrom, waitFor } from "xstate"
import { auroraEngineContractId } from "../constants/aurora"
import { getAuroraEngineContractId } from "../constants/aurora"
import { bridgeSDK } from "../constants/bridgeSdk"
import type {
QuoteInput,
Expand Down Expand Up @@ -74,21 +79,6 @@ export type PreparationOutput =
| { tag: "ok"; value: PreparedWithdrawReturnType }
| { tag: "err"; value: PrepareWithdrawErrorType }

// todo: import it from bridge-sdk
type BridgeConfig =
| {
bridge: "direct"
chain: "near:mainnet"
}
| {
bridge: "aurora_engine"
auroraEngineContractId: string
proxyTokenContractId: string | null
}
| {
bridge: "intents"
}

export async function prepareWithdraw(
{
formValues,
Expand Down Expand Up @@ -197,24 +187,22 @@ export async function prepareWithdraw(
directWithdrawAvailable
)

const bridgeConfig: BridgeConfig | undefined = isAuroraVirtualChain(
const routeConfig: RouteConfig | undefined = isAuroraVirtualChain(
formValues.tokenOut.chainName
)
? {
bridge: "aurora_engine",
auroraEngineContractId:
auroraEngineContractId[formValues.tokenOut.chainName],
proxyTokenContractId: null, // TODO: provide the correct value once you know it
}
? createVirtualChainRoute(
getAuroraEngineContractId(formValues.tokenOut.chainName),
null // TODO: provide the correct value once you know it
)
: formValues.tokenOut.chainName === "near"
? { bridge: "direct", chain: "near:mainnet" }
: undefined
? createNearWithdrawalRoute()
: createDefaultRoute()

const feeEstimation = await estimateFee({
defuseAssetId: formValues.tokenOut.defuseAssetId,
amount: totalWithdrawn.amount,
recipient: formValues.parsedRecipient,
bridgeConfig,
routeConfig,
})
if (feeEstimation.isErr()) {
return { tag: "err", value: feeEstimation.unwrapErr() }
Expand Down Expand Up @@ -250,7 +238,7 @@ export async function prepareWithdraw(
destinationAddress: formValues.parsedRecipient,
destinationMemo: formValues.parsedDestinationMemo ?? undefined,
feeInclusive: false,
bridgeConfig,
routeConfig,
},
feeEstimation: feeEstimation.unwrap(),
})
Expand Down Expand Up @@ -375,12 +363,12 @@ async function estimateFee({
defuseAssetId,
amount,
recipient,
bridgeConfig,
routeConfig,
}: {
defuseAssetId: string
amount: bigint
recipient: string
bridgeConfig: BridgeConfig | undefined
routeConfig: RouteConfig | undefined
}): Promise<Result<FeeEstimation, { reason: "ERR_WITHDRAWAL_FEE_FETCH" }>> {
return bridgeSDK
.estimateWithdrawalFee({
Expand All @@ -389,7 +377,7 @@ async function estimateFee({
amount: amount,
destinationAddress: recipient,
feeInclusive: true,
bridgeConfig,
routeConfig,
},
})
.then(Ok, (err) => {
Expand Down Expand Up @@ -581,9 +569,7 @@ async function prepareNearIntentsWithdraw({
destinationAddress: formValues.parsedRecipient,
destinationMemo: undefined, // Destination memo is only used for XRP Ledger withdrawals
feeInclusive: false,
bridgeConfig: {
bridge: "intents",
},
routeConfig: createInternalTransferRoute(),
},
feeEstimation: {
amount: 0n,
Expand Down
19 changes: 12 additions & 7 deletions src/types/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,31 @@ export type SupportedChainName =
| "bitcoin"
| "solana"
| "dogecoin"
| "turbochain"
| "tuxappchain"
| "vertex"
| "optima"
| "easychain"
| "aurora"
| "xrpledger"
| "zcash"
| "gnosis"
| "berachain"
| "tron"
| "polygon"
| "bsc"
| "hyperliquid"
| "ton"
| "optimism"
| "avalanche"
| "sui"
| "stellar"
| "aptos"
| VirtualChains
| MockedChains

export type VirtualChains =
| "turbochain"
| "tuxappchain"
| "vertex"
| "optima"
| "easychain"
| "aurora"

export type MockedChains = "hyperliquid"

export type SupportedBridge = "direct" | "poa" | "aurora_engine" | "hot_omni"

Expand Down
65 changes: 36 additions & 29 deletions src/utils/caip2.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,38 @@
import type { SupportedChainName } from "../types/base"
import { CAIP2_NETWORK } from "@defuse-protocol/bridge-sdk"
import type {
MockedChains,
SupportedChainName,
VirtualChains,
} from "../types/base"

export const CAIP2_NETWORK: Record<SupportedChainName, string> = {
bitcoin: "bip122:000000000019d6689c085ae165831e93",
eth: "eip155:1",
base: "eip155:8453",
arbitrum: "eip155:42161",
bsc: "eip155:56",
polygon: "eip155:137",
near: "near:mainnet",
solana: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
tron: "tron:27Lqcw",
gnosis: "eip155:100",
xrpledger: "xrpl:0",
dogecoin: "bip122:1a91e3dace36e2be3bf030a65679fe82",
zcash: "zcash:0",
berachain: "eip155:80085",
ton: "tvm:-239",
aurora: "eip155:1313161554",
turbochain: "eip155:1313161567",
tuxappchain: "eip155:1313161573",
vertex: "eip155:1313161587",
optima: "eip155:1313161569",
easychain: "eip155:1313161752",
hyperliquid: "hyperliquid:mainnet", // todo: This is not reviewed and most likely incorrect
optimism: "eip155:10",
avalanche: "eip155:43114",
sui: "sui:mainnet",
stellar: "stellar:mainnet",
aptos: "aptos:mainnet",
type RealChains = Exclude<SupportedChainName, VirtualChains | MockedChains>

const mapping: Record<RealChains, CAIP2_NETWORK> = {
bitcoin: CAIP2_NETWORK.Bitcoin,
eth: CAIP2_NETWORK.Ethereum,
base: CAIP2_NETWORK.Base,
arbitrum: CAIP2_NETWORK.Arbitrum,
bsc: CAIP2_NETWORK.BNB,
polygon: CAIP2_NETWORK.Polygon,
near: CAIP2_NETWORK.Near,
solana: CAIP2_NETWORK.Solana,
tron: CAIP2_NETWORK.Tron,
gnosis: CAIP2_NETWORK.Gnosis,
xrpledger: CAIP2_NETWORK.XRPL,
dogecoin: CAIP2_NETWORK.Dogecoin,
zcash: CAIP2_NETWORK.Zcash,
berachain: CAIP2_NETWORK.Berachain,
ton: CAIP2_NETWORK.TON,
optimism: CAIP2_NETWORK.Optimism,
avalanche: CAIP2_NETWORK.Avalanche,
sui: CAIP2_NETWORK.Sui,
stellar: CAIP2_NETWORK.Stellar,
aptos: CAIP2_NETWORK.Aptos,
}

export function getCAIP2(chainName: SupportedChainName): CAIP2_NETWORK {
if (chainName in mapping) {
return mapping[chainName as keyof typeof mapping]
}
throw new Error(`Unsupported chain name: ${chainName}`)
}
Loading