Skip to content

Commit 4923474

Browse files
committed
add custom enso source
1 parent 43948e5 commit 4923474

File tree

2 files changed

+142
-2
lines changed

2 files changed

+142
-2
lines changed

src/swapService/strategies/balmySDK/customSourceList.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { logQuoteTime } from "@/common/utils/logs"
2-
import { LOG_SLOW_QUERY_TIMEOUT_SECONDS } from "@/swapService/config/constants"
32
import { parseHrtimeToSeconds } from "@/swapService/utils"
43
import type {
54
IFetchService,
@@ -9,7 +8,7 @@ import type {
98
SourceListQuoteResponse,
109
} from "@balmy/sdk"
1110
import { LocalSourceList } from "@balmy/sdk/dist/services/quotes/source-lists/local-source-list"
12-
import { stringify } from "viem"
11+
import { CustomEnsoQuoteSource } from "./sources/ensoQuoteSource"
1312
import { CustomKyberswapQuoteSource } from "./sources/kyberswapQuoteSource"
1413
import { CustomLiFiQuoteSource } from "./sources/lifiQuoteSource"
1514
import { CustomMagpieQuoteSource } from "./sources/magpieQuoteSource"
@@ -38,6 +37,7 @@ const customSources = {
3837
uniswap: new CustomUniswapQuoteSource(),
3938
magpie: new CustomMagpieQuoteSource(),
4039
kyberswap: new CustomKyberswapQuoteSource(),
40+
enso: new CustomEnsoQuoteSource(),
4141
oku_bob_icecreamswap: new CustomOkuQuoteSource(
4242
"icecreamswap",
4343
"IceCreamSwap",
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { Chains } from "@balmy/sdk"
2+
import type {
3+
BuildTxParams,
4+
IQuoteSource,
5+
QuoteParams,
6+
QuoteSourceMetadata,
7+
SourceQuoteResponse,
8+
SourceQuoteTransaction,
9+
} from "@balmy/sdk/dist/services/quotes/quote-sources/types"
10+
import {
11+
addQuoteSlippage,
12+
calculateAllowanceTarget,
13+
checksum,
14+
failed,
15+
} from "@balmy/sdk/dist/services/quotes/quote-sources/utils"
16+
import qs from "qs"
17+
18+
const ENSO_METADATA: QuoteSourceMetadata<EnsoSupport> = {
19+
name: "Enso",
20+
supports: {
21+
chains: [
22+
Chains.ETHEREUM.chainId,
23+
Chains.OPTIMISM.chainId,
24+
Chains.BNB_CHAIN.chainId,
25+
Chains.GNOSIS.chainId,
26+
Chains.POLYGON.chainId,
27+
Chains.BASE.chainId,
28+
Chains.ARBITRUM.chainId,
29+
Chains.AVALANCHE.chainId,
30+
Chains.SONIC.chainId,
31+
80094,
32+
],
33+
swapAndTransfer: false,
34+
buyOrders: false,
35+
},
36+
logoURI: "ipfs://QmWc9U7emJ7YvoLsxCvvJMxnEfMncJXrkqFpGoCP2LxZRJ",
37+
}
38+
type EnsoSupport = { buyOrders: false; swapAndTransfer: false }
39+
type EnsoConfig = {
40+
apiKey: string
41+
routingStrategy?: "router" | "delegate" | "ensowallet"
42+
}
43+
type EnsoData = { tx: SourceQuoteTransaction }
44+
export class CustomEnsoQuoteSource
45+
implements IQuoteSource<EnsoSupport, EnsoConfig, EnsoData>
46+
{
47+
getMetadata() {
48+
return ENSO_METADATA
49+
}
50+
51+
async quote({
52+
components: { fetchService },
53+
request: {
54+
chainId,
55+
sellToken,
56+
buyToken,
57+
order,
58+
config: { slippagePercentage, timeout },
59+
accounts: { takeFrom },
60+
},
61+
config,
62+
}: QuoteParams<EnsoSupport, EnsoConfig>): Promise<
63+
SourceQuoteResponse<EnsoData>
64+
> {
65+
const takeFromChecksummed = checksum(takeFrom)
66+
67+
const queryParams = {
68+
fromAddress: takeFromChecksummed,
69+
spender: takeFromChecksummed,
70+
receiver: takeFromChecksummed,
71+
tokenIn: sellToken,
72+
amountIn: order.sellAmount.toString(),
73+
tokenOut: buyToken,
74+
routingStrategy: config?.routingStrategy ?? "router",
75+
priceImpact: false,
76+
chainId,
77+
slippage: Math.floor(slippagePercentage * 100),
78+
tokenInAmountToApprove: order.sellAmount.toString(),
79+
tokenInAmountToTransfer: order.sellAmount.toString(),
80+
}
81+
82+
const queryString = qs.stringify(queryParams, {
83+
skipNulls: true,
84+
arrayFormat: "comma",
85+
})
86+
const url = `https://api.enso.finance/api/v1/shortcuts/route?${queryString}`
87+
const headers: Record<string, string> = {
88+
"Content-Type": "application/json",
89+
}
90+
if (config.apiKey) {
91+
headers["Authorization"] = `Bearer ${config.apiKey}`
92+
}
93+
94+
const response = await fetchService.fetch(url, { timeout, headers })
95+
96+
if (!response.ok) {
97+
failed(ENSO_METADATA, chainId, sellToken, buyToken, await response.text())
98+
}
99+
100+
const {
101+
amountOut,
102+
// gas,
103+
tx: { data, to, value },
104+
} = await response.json()
105+
106+
const quote = {
107+
sellAmount: order.sellAmount,
108+
buyAmount: BigInt(amountOut),
109+
allowanceTarget: calculateAllowanceTarget(sellToken, to),
110+
// estimatedGas: BigInt(gas),
111+
customData: {
112+
tx: {
113+
calldata: data,
114+
to,
115+
value: BigInt(value ?? 0),
116+
},
117+
},
118+
}
119+
120+
return addQuoteSlippage(quote, order.type, slippagePercentage)
121+
}
122+
123+
async buildTx({
124+
request,
125+
}: BuildTxParams<EnsoConfig, EnsoData>): Promise<SourceQuoteTransaction> {
126+
return request.customData.tx
127+
}
128+
129+
isConfigAndContextValidForQuoting(
130+
config: Partial<EnsoConfig> | undefined,
131+
): config is EnsoConfig {
132+
return !!config?.apiKey
133+
}
134+
135+
isConfigAndContextValidForTxBuilding(
136+
config: Partial<EnsoConfig> | undefined,
137+
): config is EnsoConfig {
138+
return true
139+
}
140+
}

0 commit comments

Comments
 (0)