3
3
composeContext ,
4
4
generateObjectDeprecated ,
5
5
ModelClass ,
6
+ elizaLogger ,
6
7
} from "@elizaos/core" ;
7
8
import {
8
9
createConfig ,
@@ -15,8 +16,15 @@ import {
15
16
import { initWalletProvider , WalletProvider } from "../providers/wallet" ;
16
17
import { swapTemplate } from "../templates" ;
17
18
import type { SwapParams , SwapQuote , Transaction } from "../types" ;
18
- import { Address , ByteArray , encodeFunctionData , Hex , parseAbi , parseEther , parseUnits } from "viem" ;
19
- import { BebopRoute } from '../types/index' ;
19
+ import {
20
+ Address ,
21
+ ByteArray ,
22
+ encodeFunctionData ,
23
+ Hex ,
24
+ parseAbi ,
25
+ parseUnits ,
26
+ } from "viem" ;
27
+ import { BebopRoute } from "../types/index" ;
20
28
21
29
export { swapTemplate } ;
22
30
@@ -26,7 +34,7 @@ export class SwapAction {
26
34
27
35
constructor ( private walletProvider : WalletProvider ) {
28
36
this . walletProvider = walletProvider ;
29
- let lifiChains : ExtendedChain [ ] = [ ] ;
37
+ const lifiChains : ExtendedChain [ ] = [ ] ;
30
38
for ( const config of Object . values ( this . walletProvider . chains ) ) {
31
39
try {
32
40
lifiChains . push ( {
@@ -58,27 +66,31 @@ export class SwapAction {
58
66
} ,
59
67
coin : config . nativeCurrency . symbol ,
60
68
mainnet : true ,
61
- diamondAddress : "0x0000000000000000000000000000000000000000" ,
69
+ diamondAddress :
70
+ "0x0000000000000000000000000000000000000000" ,
62
71
} as ExtendedChain ) ;
63
72
} catch {
64
73
// Skip chains with missing config in viem
65
74
}
66
75
}
67
76
this . lifiConfig = createConfig ( {
68
77
integrator : "eliza" ,
69
- chains : lifiChains
70
- } )
78
+ chains : lifiChains ,
79
+ } ) ;
71
80
this . bebopChainsMap = {
72
- ' mainnet' : ' ethereum'
73
- }
81
+ mainnet : " ethereum" ,
82
+ } ;
74
83
}
75
84
76
85
async swap ( params : SwapParams ) : Promise < Transaction > {
77
86
const walletClient = this . walletProvider . getWalletClient ( params . chain ) ;
78
87
const [ fromAddress ] = await walletClient . getAddresses ( ) ;
79
88
80
89
// Getting quotes from different aggregators and sorting them by minAmount (amount after slippage)
81
- const sortedQuotes : SwapQuote [ ] = await this . getSortedQuotes ( fromAddress , params ) ;
90
+ const sortedQuotes : SwapQuote [ ] = await this . getSortedQuotes (
91
+ fromAddress ,
92
+ params
93
+ ) ;
82
94
83
95
// Trying to execute the best quote by amount, fallback to the next one if it fails
84
96
for ( const quote of sortedQuotes ) {
@@ -89,7 +101,7 @@ export class SwapAction {
89
101
break ;
90
102
case "bebop" :
91
103
res = await this . executeBebopQuote ( quote , params ) ;
92
- break
104
+ break ;
93
105
default :
94
106
throw new Error ( "No aggregator found" ) ;
95
107
}
@@ -98,31 +110,50 @@ export class SwapAction {
98
110
throw new Error ( "Execution failed" ) ;
99
111
}
100
112
101
- private async getSortedQuotes ( fromAddress : Address , params : SwapParams ) : Promise < SwapQuote [ ] > {
102
- const decimalsAbi = parseAbi ( [ 'function decimals() view returns (uint8)' ] ) ;
103
- const decimals = await this . walletProvider . getPublicClient ( params . chain ) . readContract ( {
104
- address : params . fromToken ,
105
- abi : decimalsAbi ,
106
- functionName : 'decimals' ,
107
- } ) ;
113
+ private async getSortedQuotes (
114
+ fromAddress : Address ,
115
+ params : SwapParams
116
+ ) : Promise < SwapQuote [ ] > {
117
+ const decimalsAbi = parseAbi ( [
118
+ "function decimals() view returns (uint8)" ,
119
+ ] ) ;
120
+ const decimals = await this . walletProvider
121
+ . getPublicClient ( params . chain )
122
+ . readContract ( {
123
+ address : params . fromToken ,
124
+ abi : decimalsAbi ,
125
+ functionName : "decimals" ,
126
+ } ) ;
108
127
const quotes : SwapQuote [ ] | undefined = await Promise . all ( [
109
128
this . getLifiQuote ( fromAddress , params , decimals ) ,
110
- this . getBebopQuote ( fromAddress , params , decimals )
129
+ this . getBebopQuote ( fromAddress , params , decimals ) ,
111
130
] ) ;
112
- const sortedQuotes : SwapQuote [ ] = quotes . filter ( ( quote ) => quote !== undefined ) as SwapQuote [ ] ;
113
- sortedQuotes . sort ( ( a , b ) => BigInt ( a . minOutputAmount ) > BigInt ( b . minOutputAmount ) ? - 1 : 1 ) ;
131
+ const sortedQuotes : SwapQuote [ ] = quotes . filter (
132
+ ( quote ) => quote !== undefined
133
+ ) as SwapQuote [ ] ;
134
+ sortedQuotes . sort ( ( a , b ) =>
135
+ BigInt ( a . minOutputAmount ) > BigInt ( b . minOutputAmount ) ? - 1 : 1
136
+ ) ;
114
137
if ( sortedQuotes . length === 0 ) throw new Error ( "No routes found" ) ;
115
138
return sortedQuotes ;
116
139
}
117
140
118
- private async getLifiQuote ( fromAddress : Address , params : SwapParams , fromTokenDecimals : number ) : Promise < SwapQuote | undefined > {
141
+ private async getLifiQuote (
142
+ fromAddress : Address ,
143
+ params : SwapParams ,
144
+ fromTokenDecimals : number
145
+ ) : Promise < SwapQuote | undefined > {
119
146
try {
120
147
const routes = await getRoutes ( {
121
- fromChainId : this . walletProvider . getChainConfigs ( params . chain ) . id ,
148
+ fromChainId : this . walletProvider . getChainConfigs ( params . chain )
149
+ . id ,
122
150
toChainId : this . walletProvider . getChainConfigs ( params . chain ) . id ,
123
151
fromTokenAddress : params . fromToken ,
124
152
toTokenAddress : params . toToken ,
125
- fromAmount : parseUnits ( params . amount , fromTokenDecimals ) . toString ( ) ,
153
+ fromAmount : parseUnits (
154
+ params . amount ,
155
+ fromTokenDecimals
156
+ ) . toString ( ) ,
126
157
fromAddress : fromAddress ,
127
158
options : {
128
159
slippage : params . slippage / 100 || 0.005 ,
@@ -133,61 +164,79 @@ export class SwapAction {
133
164
return {
134
165
aggregator : "lifi" ,
135
166
minOutputAmount : routes . routes [ 0 ] . steps [ 0 ] . estimate . toAmountMin ,
136
- swapData : routes . routes [ 0 ]
137
- }
167
+ swapData : routes . routes [ 0 ] ,
168
+ } ;
138
169
} catch ( error ) {
139
170
console . debug ( "Error in getLifiQuote:" , error . message ) ;
140
171
return undefined ;
141
172
}
142
173
}
143
174
144
- private async getBebopQuote ( fromAddress : Address , params : SwapParams , fromTokenDecimals : number ) : Promise < SwapQuote | undefined > {
175
+ private async getBebopQuote (
176
+ fromAddress : Address ,
177
+ params : SwapParams ,
178
+ fromTokenDecimals : number
179
+ ) : Promise < SwapQuote | undefined > {
145
180
try {
146
181
const url = `https://api.bebop.xyz/router/${ this . bebopChainsMap [ params . chain ] ?? params . chain } /v1/quote` ;
147
182
const reqParams = new URLSearchParams ( {
148
183
sell_tokens : params . fromToken ,
149
184
buy_tokens : params . toToken ,
150
- sell_amounts : parseUnits ( params . amount , fromTokenDecimals ) . toString ( ) ,
185
+ sell_amounts : parseUnits (
186
+ params . amount ,
187
+ fromTokenDecimals
188
+ ) . toString ( ) ,
151
189
taker_address : fromAddress ,
152
- approval_type : ' Standard' ,
153
- skip_validation : ' true' ,
154
- gasless : ' false' ,
155
- source : ' eliza'
190
+ approval_type : " Standard" ,
191
+ skip_validation : " true" ,
192
+ gasless : " false" ,
193
+ source : " eliza" ,
156
194
} ) ;
157
195
const response = await fetch ( `${ url } ?${ reqParams . toString ( ) } ` , {
158
- method : ' GET' ,
159
- headers : { ' accept' : ' application/json' } ,
196
+ method : " GET" ,
197
+ headers : { accept : " application/json" } ,
160
198
} ) ;
161
199
if ( ! response . ok ) {
162
200
throw Error ( response . statusText ) ;
163
201
}
164
202
const data = await response . json ( ) ;
165
203
const route : BebopRoute = {
166
204
data : data . routes [ 0 ] . quote . tx . data ,
167
- sellAmount : parseUnits ( params . amount , fromTokenDecimals ) . toString ( ) ,
168
- approvalTarget : data . routes [ 0 ] . quote . approvalTarget as `0x${string } `,
205
+ sellAmount : parseUnits (
206
+ params . amount ,
207
+ fromTokenDecimals
208
+ ) . toString ( ) ,
209
+ approvalTarget : data . routes [ 0 ] . quote
210
+ . approvalTarget as `0x${string } `,
169
211
from : data . routes [ 0 ] . quote . tx . from as `0x${string } `,
170
212
value : data . routes [ 0 ] . quote . tx . value . toString ( ) ,
171
213
to : data . routes [ 0 ] . quote . tx . to as `0x${string } `,
172
214
gas : data . routes [ 0 ] . quote . tx . gas . toString ( ) ,
173
- gasPrice : data . routes [ 0 ] . quote . tx . gasPrice . toString ( )
174
- }
215
+ gasPrice : data . routes [ 0 ] . quote . tx . gasPrice . toString ( ) ,
216
+ } ;
175
217
return {
176
218
aggregator : "bebop" ,
177
- minOutputAmount : data . routes [ 0 ] . quote . buyTokens [ params . toToken ] . minimumAmount . toString ( ) ,
178
- swapData : route
179
- }
180
-
219
+ minOutputAmount :
220
+ data . routes [ 0 ] . quote . buyTokens [
221
+ params . toToken
222
+ ] . minimumAmount . toString ( ) ,
223
+ swapData : route ,
224
+ } ;
181
225
} catch ( error ) {
182
226
console . debug ( "Error in getBebopQuote:" , error . message ) ;
183
227
return undefined ;
184
228
}
185
229
}
186
230
187
- private async executeLifiQuote ( quote : SwapQuote ) : Promise < Transaction | undefined > {
231
+ private async executeLifiQuote (
232
+ quote : SwapQuote
233
+ ) : Promise < Transaction | undefined > {
188
234
try {
189
235
const route : Route = quote . swapData as Route ;
190
- const execution = await executeRoute ( quote . swapData as Route , this . lifiConfig ) ;
236
+ const execution = await executeRoute (
237
+ quote . swapData as Route ,
238
+ this . lifiConfig
239
+ ) ;
191
240
const process = execution . steps [ 0 ] ?. execution ?. process [ 0 ] ;
192
241
193
242
if ( ! process ?. status || process . status === "FAILED" ) {
@@ -199,36 +248,77 @@ export class SwapAction {
199
248
to : route . steps [ 0 ] . estimate . approvalAddress as `0x${string } `,
200
249
value : 0n ,
201
250
data : process . data as `0x${string } `,
202
- chainId : route . fromChainId
203
- }
251
+ chainId : route . fromChainId ,
252
+ } ;
204
253
} catch ( error ) {
254
+ elizaLogger . error ( `Failed to execute lifi quote: ${ error } ` ) ;
205
255
return undefined ;
206
256
}
207
257
}
208
258
209
- private async executeBebopQuote ( quote : SwapQuote , params : SwapParams ) : Promise < Transaction | undefined > {
259
+ private async executeBebopQuote (
260
+ quote : SwapQuote ,
261
+ params : SwapParams
262
+ ) : Promise < Transaction | undefined > {
210
263
try {
211
264
const bebopRoute : BebopRoute = quote . swapData as BebopRoute ;
212
- const allowanceAbi = parseAbi ( [ 'function allowance(address,address) view returns (uint256)' ] ) ;
213
- const allowance : bigint = await this . walletProvider . getPublicClient ( params . chain ) . readContract ( {
214
- address : params . fromToken ,
215
- abi : allowanceAbi ,
216
- functionName : 'allowance' ,
217
- args : [ bebopRoute . from , bebopRoute . approvalTarget ]
218
- } ) ;
265
+ const allowanceAbi = parseAbi ( [
266
+ "function allowance(address,address) view returns (uint256)" ,
267
+ ] ) ;
268
+ const allowance : bigint = await this . walletProvider
269
+ . getPublicClient ( params . chain )
270
+ . readContract ( {
271
+ address : params . fromToken ,
272
+ abi : allowanceAbi ,
273
+ functionName : "allowance" ,
274
+ args : [ bebopRoute . from , bebopRoute . approvalTarget ] ,
275
+ } ) ;
219
276
if ( allowance < BigInt ( bebopRoute . sellAmount ) ) {
220
277
const approvalData = encodeFunctionData ( {
221
- abi : parseAbi ( [ 'function approve(address,uint256)' ] ) ,
222
- functionName : 'approve' ,
223
- args : [ bebopRoute . approvalTarget , BigInt ( bebopRoute . sellAmount ) ] ,
278
+ abi : parseAbi ( [ "function approve(address,uint256)" ] ) ,
279
+ functionName : "approve" ,
280
+ args : [
281
+ bebopRoute . approvalTarget ,
282
+ BigInt ( bebopRoute . sellAmount ) ,
283
+ ] ,
224
284
} ) ;
225
- await this . walletProvider . getWalletClient ( params . chain ) . sendTransaction ( {
226
- account : this . walletProvider . getWalletClient ( params . chain ) . account ,
227
- to : params . fromToken ,
228
- value : 0n ,
229
- data : approvalData ,
285
+ await this . walletProvider
286
+ . getWalletClient ( params . chain )
287
+ . sendTransaction ( {
288
+ account : this . walletProvider . getWalletClient (
289
+ params . chain
290
+ ) . account ,
291
+ to : params . fromToken ,
292
+ value : 0n ,
293
+ data : approvalData ,
294
+ kzg : {
295
+ blobToKzgCommitment : function (
296
+ _ : ByteArray
297
+ ) : ByteArray {
298
+ throw new Error ( "Function not implemented." ) ;
299
+ } ,
300
+ computeBlobKzgProof : function (
301
+ _blob : ByteArray ,
302
+ _commitment : ByteArray
303
+ ) : ByteArray {
304
+ throw new Error ( "Function not implemented." ) ;
305
+ } ,
306
+ } ,
307
+ chain : undefined ,
308
+ } ) ;
309
+ }
310
+ const hash = await this . walletProvider
311
+ . getWalletClient ( params . chain )
312
+ . sendTransaction ( {
313
+ account : this . walletProvider . getWalletClient ( params . chain )
314
+ . account ,
315
+ to : bebopRoute . to ,
316
+ value : BigInt ( bebopRoute . value ) ,
317
+ data : bebopRoute . data as Hex ,
230
318
kzg : {
231
- blobToKzgCommitment : function ( _ : ByteArray ) : ByteArray {
319
+ blobToKzgCommitment : function (
320
+ _ : ByteArray
321
+ ) : ByteArray {
232
322
throw new Error ( "Function not implemented." ) ;
233
323
} ,
234
324
computeBlobKzgProof : function (
@@ -240,33 +330,16 @@ export class SwapAction {
240
330
} ,
241
331
chain : undefined ,
242
332
} ) ;
243
- }
244
- const hash = await this . walletProvider . getWalletClient ( params . chain ) . sendTransaction ( {
245
- account : this . walletProvider . getWalletClient ( params . chain ) . account ,
246
- to : bebopRoute . to ,
247
- value : BigInt ( bebopRoute . value ) ,
248
- data : bebopRoute . data as Hex ,
249
- kzg : {
250
- blobToKzgCommitment : function ( _ : ByteArray ) : ByteArray {
251
- throw new Error ( "Function not implemented." ) ;
252
- } ,
253
- computeBlobKzgProof : function (
254
- _blob : ByteArray ,
255
- _commitment : ByteArray
256
- ) : ByteArray {
257
- throw new Error ( "Function not implemented." ) ;
258
- } ,
259
- } ,
260
- chain : undefined ,
261
- } ) ;
262
333
return {
263
334
hash,
264
- from : this . walletProvider . getWalletClient ( params . chain ) . account . address ,
335
+ from : this . walletProvider . getWalletClient ( params . chain ) . account
336
+ . address ,
265
337
to : bebopRoute . to ,
266
338
value : BigInt ( bebopRoute . value ) ,
267
339
data : bebopRoute . data as Hex ,
268
340
} ;
269
341
} catch ( error ) {
342
+ elizaLogger . error ( `Failed to execute bebop quote: ${ error } ` ) ;
270
343
return undefined ;
271
344
}
272
345
}
0 commit comments