@vleap/warps-adapter-evm 0.2.0-alpha.17 → 0.2.0-alpha.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,6 +1,178 @@
1
+ // src/chains/arbitrum.ts
2
+ import { WarpChainName } from "@vleap/warps";
3
+
1
4
  // src/WarpEvmDataLoader.ts
2
- import { getProviderUrl } from "@vleap/warps";
5
+ import {
6
+ getProviderUrl
7
+ } from "@vleap/warps";
3
8
  import { ethers } from "ethers";
9
+
10
+ // src/LogoService.ts
11
+ var CHAIN_IDS = {
12
+ ethereum: 1,
13
+ arbitrum: 42161,
14
+ base: 8453
15
+ };
16
+ var FALLBACK_LOGOS = {
17
+ ethereum: {
18
+ "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png",
19
+ "0xdAC17F958D2ee523a2206206994597C13D831ec7": "https://assets.coingecko.com/coins/images/325/small/Tether.png",
20
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599": "https://assets.coingecko.com/coins/images/7598/small/wrapped_bitcoin_wbtc.png",
21
+ "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": "https://assets.coingecko.com/coins/images/2518/small/weth.png",
22
+ "0x6B175474E89094C44Da98b954EedeAC495271d0F": "https://assets.coingecko.com/coins/images/9956/small/4943.png"
23
+ },
24
+ arbitrum: {
25
+ "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8": "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png",
26
+ "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9": "https://assets.coingecko.com/coins/images/325/small/Tether.png",
27
+ "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1": "https://assets.coingecko.com/coins/images/2518/small/weth.png"
28
+ },
29
+ base: {
30
+ "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913": "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png",
31
+ "0x4200000000000000000000000000000000000006": "https://assets.coingecko.com/coins/images/2518/small/weth.png",
32
+ "0x036CbD53842c5426634e7929541eC2318f3dCF7e": "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png",
33
+ "0x808456652fdb597867f38412077A9182bf77359F": "https://assets.coingecko.com/coins/images/3318/small/euro-coin.png",
34
+ "0xcbB7C0006F23900c38EB856149F799620fcb8A4a": "https://assets.coingecko.com/coins/images/7598/small/wrapped_bitcoin_wbtc.png"
35
+ }
36
+ };
37
+ var TOKEN_LISTS = [
38
+ "https://tokens.uniswap.org",
39
+ "https://raw.githubusercontent.com/compound-finance/token-list/master/compound.tokenlist.json",
40
+ "https://tokens.1inch.io"
41
+ ];
42
+ var logoCache = /* @__PURE__ */ new Map();
43
+ var tokenInfoCache = /* @__PURE__ */ new Map();
44
+ var tokenListCache = /* @__PURE__ */ new Map();
45
+ var EvmLogoService = class {
46
+ static async getTokenInfo(chainName, tokenAddress) {
47
+ const cacheKey = `${chainName}:${tokenAddress.toLowerCase()}`;
48
+ if (tokenInfoCache.has(cacheKey)) {
49
+ return tokenInfoCache.get(cacheKey);
50
+ }
51
+ let tokenInfo = {};
52
+ try {
53
+ tokenInfo = await this.fetchFromTokenLists(chainName, tokenAddress);
54
+ } catch (error) {
55
+ }
56
+ if (!tokenInfo.logoURI) {
57
+ try {
58
+ tokenInfo = { ...tokenInfo, ...await this.fetchFromDefiLlama(chainName, tokenAddress) };
59
+ } catch (error) {
60
+ }
61
+ }
62
+ tokenInfoCache.set(cacheKey, tokenInfo);
63
+ return tokenInfo;
64
+ }
65
+ static async getLogoUrl(chainName, tokenAddress, tokenName, tokenSymbol) {
66
+ const cacheKey = `${chainName}:${tokenAddress.toLowerCase()}`;
67
+ if (logoCache.has(cacheKey)) {
68
+ return logoCache.get(cacheKey);
69
+ }
70
+ let logoUrl = "";
71
+ const fallbackLogos = FALLBACK_LOGOS[chainName];
72
+ if (fallbackLogos && fallbackLogos[tokenAddress]) {
73
+ logoUrl = fallbackLogos[tokenAddress];
74
+ } else {
75
+ const tokenInfo = await this.getTokenInfo(chainName, tokenAddress);
76
+ logoUrl = tokenInfo.logoURI || "";
77
+ if (!logoUrl && (tokenSymbol || tokenName)) {
78
+ try {
79
+ logoUrl = await this.fetchFromTrustWallet(chainName, tokenAddress);
80
+ } catch (error) {
81
+ }
82
+ }
83
+ }
84
+ logoCache.set(cacheKey, logoUrl);
85
+ return logoUrl;
86
+ }
87
+ static async fetchFromTokenLists(chainName, tokenAddress) {
88
+ const chainId = CHAIN_IDS[chainName];
89
+ if (!chainId) return {};
90
+ const normalizedAddress = tokenAddress.toLowerCase();
91
+ if (tokenListCache.has(`${chainId}:${normalizedAddress}`)) {
92
+ return tokenListCache.get(`${chainId}:${normalizedAddress}`) || {};
93
+ }
94
+ for (const tokenListUrl of TOKEN_LISTS) {
95
+ try {
96
+ const response = await fetch(tokenListUrl, {
97
+ headers: { Accept: "application/json" },
98
+ signal: AbortSignal.timeout(5e3)
99
+ });
100
+ if (response.ok) {
101
+ const data = await response.json();
102
+ const token = data.tokens.find((t) => t.chainId === chainId && t.address.toLowerCase() === normalizedAddress);
103
+ if (token) {
104
+ const tokenInfo = {
105
+ name: token.name,
106
+ symbol: token.symbol,
107
+ decimals: token.decimals,
108
+ logoURI: token.logoURI
109
+ };
110
+ tokenListCache.set(`${chainId}:${normalizedAddress}`, tokenInfo);
111
+ return tokenInfo;
112
+ }
113
+ }
114
+ } catch (error) {
115
+ continue;
116
+ }
117
+ }
118
+ return {};
119
+ }
120
+ static async fetchFromDefiLlama(chainName, tokenAddress) {
121
+ try {
122
+ const chainMapping = {
123
+ ethereum: "ethereum",
124
+ arbitrum: "arbitrum",
125
+ base: "base"
126
+ };
127
+ const chain = chainMapping[chainName];
128
+ if (!chain) return {};
129
+ const response = await fetch(`https://coins.llama.fi/prices/current/${chain}:${tokenAddress}`, { signal: AbortSignal.timeout(5e3) });
130
+ if (response.ok) {
131
+ const data = await response.json();
132
+ const coinData = data.coins?.[`${chain}:${tokenAddress}`];
133
+ if (coinData) {
134
+ return {
135
+ symbol: coinData.symbol,
136
+ logoURI: coinData.logoURI
137
+ };
138
+ }
139
+ }
140
+ } catch (error) {
141
+ }
142
+ return {};
143
+ }
144
+ static async fetchFromTrustWallet(chainName, tokenAddress) {
145
+ try {
146
+ const chainMapping = {
147
+ ethereum: "ethereum",
148
+ arbitrum: "arbitrum",
149
+ base: "base"
150
+ };
151
+ const chain = chainMapping[chainName];
152
+ if (!chain) return "";
153
+ const logoUrl = `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${chain}/assets/${tokenAddress}/logo.png`;
154
+ const response = await fetch(logoUrl, {
155
+ method: "HEAD",
156
+ signal: AbortSignal.timeout(3e3)
157
+ });
158
+ if (response.ok) {
159
+ return logoUrl;
160
+ }
161
+ } catch (error) {
162
+ }
163
+ return "";
164
+ }
165
+ static clearCache() {
166
+ logoCache.clear();
167
+ tokenInfoCache.clear();
168
+ tokenListCache.clear();
169
+ }
170
+ static getCacheSize() {
171
+ return logoCache.size + tokenInfoCache.size + tokenListCache.size;
172
+ }
173
+ };
174
+
175
+ // src/WarpEvmDataLoader.ts
4
176
  var ERC20_ABI = [
5
177
  "function balanceOf(address owner) view returns (uint256)",
6
178
  "function decimals() view returns (uint8)",
@@ -39,6 +211,25 @@ var KNOWN_TOKENS = {
39
211
  symbol: "DAI",
40
212
  decimals: 18,
41
213
  logoUrl: "https://assets.coingecko.com/coins/images/9956/small/4943.png"
214
+ },
215
+ // Sepolia testnet tokens
216
+ "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238": {
217
+ name: "USD Coin",
218
+ symbol: "USDC",
219
+ decimals: 6,
220
+ logoUrl: "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png"
221
+ },
222
+ "0x7169D38820dfd117C3FA1f22a697dBA58d90BA06": {
223
+ name: "Tether USD",
224
+ symbol: "USDT",
225
+ decimals: 6,
226
+ logoUrl: "https://assets.coingecko.com/coins/images/325/small/Tether.png"
227
+ },
228
+ "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9": {
229
+ name: "Wrapped Ether",
230
+ symbol: "WETH",
231
+ decimals: 18,
232
+ logoUrl: "https://assets.coingecko.com/coins/images/2518/small/weth.png"
42
233
  }
43
234
  },
44
235
  arbitrum: {
@@ -73,6 +264,24 @@ var KNOWN_TOKENS = {
73
264
  symbol: "WETH",
74
265
  decimals: 18,
75
266
  logoUrl: "https://assets.coingecko.com/coins/images/2518/small/weth.png"
267
+ },
268
+ "0x036CbD53842c5426634e7929541eC2318f3dCF7e": {
269
+ name: "USD Coin",
270
+ symbol: "USDC",
271
+ decimals: 6,
272
+ logoUrl: "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png"
273
+ },
274
+ "0x808456652fdb597867f38412077A9182bf77359F": {
275
+ name: "Euro Coin",
276
+ symbol: "EURC",
277
+ decimals: 6,
278
+ logoUrl: "https://assets.coingecko.com/coins/images/3318/small/euro-coin.png"
279
+ },
280
+ "0xcbB7C0006F23900c38EB856149F799620fcb8A4a": {
281
+ name: "Coinbase Wrapped BTC",
282
+ symbol: "CBETH",
283
+ decimals: 8,
284
+ logoUrl: "https://assets.coingecko.com/coins/images/7598/small/wrapped_bitcoin_wbtc.png"
76
285
  }
77
286
  }
78
287
  };
@@ -81,12 +290,14 @@ var WarpEvmDataLoader = class {
81
290
  this.config = config;
82
291
  this.chain = chain;
83
292
  const apiUrl = getProviderUrl(this.config, this.chain.name, this.config.env, this.chain.defaultApiUrl);
84
- this.provider = new ethers.JsonRpcProvider(apiUrl);
293
+ const network = new ethers.Network(this.chain.name, parseInt(this.chain.chainId));
294
+ this.provider = new ethers.JsonRpcProvider(apiUrl, network);
85
295
  }
86
296
  async getAccount(address) {
87
297
  try {
88
298
  const balance = await this.provider.getBalance(address);
89
299
  return {
300
+ chain: this.chain.name,
90
301
  address,
91
302
  balance
92
303
  };
@@ -100,12 +311,19 @@ var WarpEvmDataLoader = class {
100
311
  const tokenBalances = await this.getERC20TokenBalances(address);
101
312
  for (const tokenBalance of tokenBalances) {
102
313
  if (tokenBalance.balance > 0n) {
314
+ const logoUrl = tokenBalance.metadata.logoUrl || await EvmLogoService.getLogoUrl(
315
+ this.chain.name,
316
+ tokenBalance.tokenAddress,
317
+ tokenBalance.metadata.name,
318
+ tokenBalance.metadata.symbol
319
+ );
103
320
  assets.push({
321
+ chain: this.chain.name,
104
322
  identifier: tokenBalance.tokenAddress,
105
323
  name: tokenBalance.metadata.name,
106
324
  amount: tokenBalance.balance,
107
325
  decimals: tokenBalance.metadata.decimals,
108
- logoUrl: tokenBalance.metadata.logoUrl || ""
326
+ logoUrl: logoUrl || ""
109
327
  });
110
328
  }
111
329
  }
@@ -114,6 +332,9 @@ var WarpEvmDataLoader = class {
114
332
  throw new Error(`Failed to get account assets for ${address}: ${error}`);
115
333
  }
116
334
  }
335
+ async getAccountActions(address, options) {
336
+ return [];
337
+ }
117
338
  async getERC20TokenBalances(address) {
118
339
  const tokenBalances = [];
119
340
  const knownTokens = KNOWN_TOKENS[this.chain.name] || {};
@@ -128,7 +349,6 @@ var WarpEvmDataLoader = class {
128
349
  });
129
350
  }
130
351
  } catch (error) {
131
- console.warn(`Failed to get balance for token ${tokenAddress}: ${error}`);
132
352
  }
133
353
  }
134
354
  const additionalTokens = await this.detectTokensFromEvents(address);
@@ -145,7 +365,6 @@ var WarpEvmDataLoader = class {
145
365
  });
146
366
  }
147
367
  } catch (error) {
148
- console.warn(`Failed to get metadata/balance for detected token ${tokenAddress}: ${error}`);
149
368
  }
150
369
  }
151
370
  }
@@ -162,12 +381,26 @@ var WarpEvmDataLoader = class {
162
381
  }
163
382
  async getTokenMetadata(tokenAddress) {
164
383
  try {
384
+ const tokenInfo = await EvmLogoService.getTokenInfo(this.chain.name, tokenAddress);
385
+ if (tokenInfo.name && tokenInfo.symbol && tokenInfo.decimals !== void 0) {
386
+ return {
387
+ name: tokenInfo.name,
388
+ symbol: tokenInfo.symbol,
389
+ decimals: tokenInfo.decimals,
390
+ logoUrl: tokenInfo.logoURI
391
+ };
392
+ }
165
393
  const contract = new ethers.Contract(tokenAddress, ERC20_ABI, this.provider);
166
- const [name, symbol, decimals] = await Promise.all([contract.name(), contract.symbol(), contract.decimals()]);
394
+ const [name, symbol, decimals] = await Promise.all([
395
+ contract.name().catch(() => tokenInfo.name || "Unknown Token"),
396
+ contract.symbol().catch(() => tokenInfo.symbol || "UNKNOWN"),
397
+ contract.decimals().catch(() => tokenInfo.decimals || 18)
398
+ ]);
167
399
  return {
168
- name: name || "Unknown Token",
169
- symbol: symbol || "UNKNOWN",
170
- decimals: decimals || 18
400
+ name: name || tokenInfo.name || "Unknown Token",
401
+ symbol: symbol || tokenInfo.symbol || "UNKNOWN",
402
+ decimals: decimals || tokenInfo.decimals || 18,
403
+ logoUrl: tokenInfo.logoURI
171
404
  };
172
405
  } catch (error) {
173
406
  throw new Error(`Failed to get token metadata: ${error}`);
@@ -195,7 +428,6 @@ var WarpEvmDataLoader = class {
195
428
  }
196
429
  return Array.from(tokenAddresses);
197
430
  } catch (error) {
198
- console.warn(`Failed to detect tokens from events: ${error}`);
199
431
  return [];
200
432
  }
201
433
  }
@@ -204,7 +436,6 @@ var WarpEvmDataLoader = class {
204
436
  try {
205
437
  return await this.getTokenMetadata(tokenAddress);
206
438
  } catch (error) {
207
- console.warn(`Failed to get token info for ${tokenAddress}: ${error}`);
208
439
  return null;
209
440
  }
210
441
  }
@@ -223,23 +454,44 @@ var WarpEvmDataLoader = class {
223
454
  const balance = await this.getTokenBalance(address, tokenAddress);
224
455
  balances.set(tokenAddress, balance);
225
456
  } catch (error) {
226
- console.warn(`Failed to get balance for token ${tokenAddress}: ${error}`);
227
457
  balances.set(tokenAddress, 0n);
228
458
  }
229
459
  })
230
460
  );
231
461
  return balances;
232
462
  }
463
+ async getAccountTokens(address) {
464
+ return this.getAccountAssets(address);
465
+ }
466
+ async getTokenMetadataPublic(tokenAddress) {
467
+ try {
468
+ return await this.getTokenMetadata(tokenAddress);
469
+ } catch (error) {
470
+ return null;
471
+ }
472
+ }
473
+ async getChainInfo() {
474
+ try {
475
+ const network = await this.provider.getNetwork();
476
+ const latestBlock = await this.provider.getBlock("latest");
477
+ return {
478
+ chainId: network.chainId.toString(),
479
+ blockTime: latestBlock?.timestamp ? Date.now() / 1e3 - latestBlock.timestamp : 12
480
+ };
481
+ } catch (error) {
482
+ throw new Error(`Failed to get chain info: ${error}`);
483
+ }
484
+ }
233
485
  };
234
486
 
235
487
  // src/WarpEvmExecutor.ts
236
488
  import {
237
489
  applyResultsToMessages,
238
490
  getNextInfo,
239
- getProviderUrl as getProviderUrl2,
491
+ getProviderUrl as getProviderUrl3,
240
492
  getWarpActionByIndex
241
493
  } from "@vleap/warps";
242
- import { ethers as ethers3 } from "ethers";
494
+ import { ethers as ethers4 } from "ethers";
243
495
 
244
496
  // src/constants.ts
245
497
  var WarpEvmConstants = {
@@ -248,6 +500,8 @@ var WarpEvmConstants = {
248
500
  ContractCall: 1e5,
249
501
  ContractDeploy: 5e5,
250
502
  Transfer: 21e3,
503
+ TokenTransfer: 65e3,
504
+ // ERC-20 transfer gas limit
251
505
  Approve: 46e3,
252
506
  Swap: 2e5
253
507
  },
@@ -317,9 +571,11 @@ var ExplorerUrls = {
317
571
  // src/WarpEvmResults.ts
318
572
  import {
319
573
  evaluateResultsCommon,
574
+ getProviderUrl as getProviderUrl2,
320
575
  parseResultsOutIndex,
321
576
  WarpConstants as WarpConstants2
322
577
  } from "@vleap/warps";
578
+ import { ethers as ethers3 } from "ethers";
323
579
 
324
580
  // src/WarpEvmSerializer.ts
325
581
  import {
@@ -478,9 +734,19 @@ var WarpEvmSerializer = class {
478
734
 
479
735
  // src/WarpEvmResults.ts
480
736
  var WarpEvmResults = class {
481
- constructor(config) {
737
+ constructor(config, chain) {
482
738
  this.config = config;
739
+ this.chain = chain;
483
740
  this.serializer = new WarpEvmSerializer();
741
+ if (this.chain) {
742
+ const apiUrl = getProviderUrl2(this.config, this.chain.name, this.config.env, this.chain.defaultApiUrl);
743
+ const network = new ethers3.Network(this.chain.name, parseInt(this.chain.chainId));
744
+ this.provider = new ethers3.JsonRpcProvider(apiUrl, network);
745
+ } else {
746
+ const apiUrl = getProviderUrl2(this.config, "ethereum", this.config.env, "https://ethereum-rpc.publicnode.com");
747
+ const network = new ethers3.Network("ethereum", 1);
748
+ this.provider = new ethers3.JsonRpcProvider(apiUrl, network);
749
+ }
484
750
  }
485
751
  async getTransactionExecutionResults(warp, tx) {
486
752
  const success = tx.status === 1;
@@ -505,6 +771,7 @@ var WarpEvmResults = class {
505
771
  tx,
506
772
  next: null,
507
773
  values: [transactionHash, blockNumber, gasUsed, gasPrice, ...logs.length > 0 ? logs : []],
774
+ valuesRaw: [transactionHash, blockNumber, gasUsed, gasPrice, ...logs.length > 0 ? logs : []],
508
775
  results: {},
509
776
  messages: {}
510
777
  };
@@ -513,7 +780,7 @@ var WarpEvmResults = class {
513
780
  const values = typedValues.map((t) => this.serializer.typedToString(t));
514
781
  const valuesRaw = typedValues.map((t) => this.serializer.typedToNative(t)[1]);
515
782
  let results = {};
516
- if (!warp.results) return { values, results };
783
+ if (!warp.results) return { values, valuesRaw, results };
517
784
  const getNestedValue = (path) => {
518
785
  const indices = path.split(".").slice(1).map((i) => parseInt(i) - 1);
519
786
  if (indices.length === 0) return void 0;
@@ -537,7 +804,29 @@ var WarpEvmResults = class {
537
804
  results[key] = path;
538
805
  }
539
806
  }
540
- return { values, results: await evaluateResultsCommon(warp, results, actionIndex, inputs) };
807
+ return { values, valuesRaw, results: await evaluateResultsCommon(warp, results, actionIndex, inputs) };
808
+ }
809
+ async getTransactionStatus(txHash) {
810
+ try {
811
+ const receipt = await this.provider.getTransactionReceipt(txHash);
812
+ if (!receipt) {
813
+ return { status: "pending" };
814
+ }
815
+ return {
816
+ status: receipt.status === 1 ? "confirmed" : "failed",
817
+ blockNumber: receipt.blockNumber,
818
+ gasUsed: receipt.gasUsed
819
+ };
820
+ } catch (error) {
821
+ throw new Error(`Failed to get transaction status: ${error}`);
822
+ }
823
+ }
824
+ async getTransactionReceipt(txHash) {
825
+ try {
826
+ return await this.provider.getTransactionReceipt(txHash);
827
+ } catch (error) {
828
+ return null;
829
+ }
541
830
  }
542
831
  };
543
832
 
@@ -547,9 +836,10 @@ var WarpEvmExecutor = class {
547
836
  this.config = config;
548
837
  this.chain = chain;
549
838
  this.serializer = new WarpEvmSerializer();
550
- const apiUrl = getProviderUrl2(this.config, chain.name, this.config.env, this.chain.defaultApiUrl);
551
- this.provider = new ethers3.JsonRpcProvider(apiUrl);
552
- this.results = new WarpEvmResults(config);
839
+ const apiUrl = getProviderUrl3(this.config, chain.name, this.config.env, this.chain.defaultApiUrl);
840
+ const network = new ethers4.Network(this.chain.name, parseInt(this.chain.chainId));
841
+ this.provider = new ethers4.JsonRpcProvider(apiUrl, network);
842
+ this.results = new WarpEvmResults(config, this.chain);
553
843
  }
554
844
  async createTransaction(executable) {
555
845
  const action = getWarpActionByIndex(executable.warp, executable.action);
@@ -569,11 +859,11 @@ var WarpEvmExecutor = class {
569
859
  async createTransferTransaction(executable) {
570
860
  const userWallet = this.config.user?.wallets?.[executable.chain.name];
571
861
  if (!userWallet) throw new Error("WarpEvmExecutor: createTransfer - user address not set");
572
- if (!ethers3.isAddress(executable.destination)) {
862
+ if (!ethers4.isAddress(executable.destination)) {
573
863
  throw new Error(`WarpEvmExecutor: Invalid destination address: ${executable.destination}`);
574
864
  }
575
- if (executable.value < 0) {
576
- throw new Error(`WarpEvmExecutor: Transfer value cannot be negative: ${executable.value}`);
865
+ if (executable.transfers && executable.transfers.length > 0) {
866
+ return this.createTokenTransferTransaction(executable, userWallet);
577
867
  }
578
868
  const tx = {
579
869
  to: executable.destination,
@@ -589,14 +879,11 @@ var WarpEvmExecutor = class {
589
879
  if (!action || !("func" in action) || !action.func) {
590
880
  throw new Error("WarpEvmExecutor: Contract action must have a function name");
591
881
  }
592
- if (!ethers3.isAddress(executable.destination)) {
882
+ if (!ethers4.isAddress(executable.destination)) {
593
883
  throw new Error(`WarpEvmExecutor: Invalid contract address: ${executable.destination}`);
594
884
  }
595
- if (executable.value < 0) {
596
- throw new Error(`WarpEvmExecutor: Contract call value cannot be negative: ${executable.value}`);
597
- }
598
885
  try {
599
- const iface = new ethers3.Interface([`function ${action.func}`]);
886
+ const iface = new ethers4.Interface([`function ${action.func}`]);
600
887
  const encodedData = iface.encodeFunctionData(action.func, executable.args);
601
888
  const tx = {
602
889
  to: executable.destination,
@@ -608,6 +895,50 @@ var WarpEvmExecutor = class {
608
895
  throw new Error(`WarpEvmExecutor: Failed to encode function data for ${action.func}: ${error}`);
609
896
  }
610
897
  }
898
+ async createTokenTransferTransaction(executable, userWallet) {
899
+ if (executable.transfers.length === 0) {
900
+ throw new Error("WarpEvmExecutor: No transfers provided");
901
+ }
902
+ if (!this.chain.nativeToken?.identifier) {
903
+ throw new Error("WarpEvmExecutor: No native token defined for this chain");
904
+ }
905
+ const nativeTokenTransfers = executable.transfers.filter((transfer) => transfer.identifier === this.chain.nativeToken.identifier);
906
+ const erc20Transfers = executable.transfers.filter((transfer) => transfer.identifier !== this.chain.nativeToken.identifier);
907
+ if (nativeTokenTransfers.length === 1 && erc20Transfers.length === 0) {
908
+ const transfer = nativeTokenTransfers[0];
909
+ if (transfer.amount <= 0n) {
910
+ throw new Error("WarpEvmExecutor: Native token transfer amount must be positive");
911
+ }
912
+ const tx = {
913
+ to: executable.destination,
914
+ value: transfer.amount,
915
+ data: "0x"
916
+ };
917
+ return this.estimateGasAndSetDefaults(tx, userWallet);
918
+ }
919
+ if (nativeTokenTransfers.length === 0 && erc20Transfers.length === 1) {
920
+ return this.createSingleTokenTransfer(executable, erc20Transfers[0], userWallet);
921
+ }
922
+ if (executable.transfers.length > 1) {
923
+ throw new Error("WarpEvmExecutor: Multiple token transfers not yet supported");
924
+ }
925
+ throw new Error("WarpEvmExecutor: Invalid transfer configuration");
926
+ }
927
+ async createSingleTokenTransfer(executable, transfer, userWallet) {
928
+ if (!ethers4.isAddress(transfer.identifier)) {
929
+ throw new Error(`WarpEvmExecutor: Invalid token address: ${transfer.identifier}`);
930
+ }
931
+ const transferInterface = new ethers4.Interface(["function transfer(address to, uint256 amount) returns (bool)"]);
932
+ const encodedData = transferInterface.encodeFunctionData("transfer", [executable.destination, transfer.amount]);
933
+ const tx = {
934
+ to: transfer.identifier,
935
+ // Token contract address
936
+ value: 0n,
937
+ // No native token value for ERC-20 transfers
938
+ data: encodedData
939
+ };
940
+ return this.estimateGasAndSetDefaults(tx, userWallet);
941
+ }
611
942
  async executeQuery(executable) {
612
943
  const action = getWarpActionByIndex(executable.warp, executable.action);
613
944
  if (action.type !== "query") {
@@ -616,11 +947,11 @@ var WarpEvmExecutor = class {
616
947
  if (!action.func) {
617
948
  throw new Error("WarpEvmExecutor: Query action must have a function name");
618
949
  }
619
- if (!ethers3.isAddress(executable.destination)) {
950
+ if (!ethers4.isAddress(executable.destination)) {
620
951
  throw new Error(`WarpEvmExecutor: Invalid contract address for query: ${executable.destination}`);
621
952
  }
622
953
  try {
623
- const iface = new ethers3.Interface([`function ${action.func}`]);
954
+ const iface = new ethers4.Interface([`function ${action.func}`]);
624
955
  const encodedData = iface.encodeFunctionData(action.func, executable.args);
625
956
  const result = await this.provider.call({
626
957
  to: executable.destination,
@@ -628,7 +959,7 @@ var WarpEvmExecutor = class {
628
959
  });
629
960
  const decodedResult = iface.decodeFunctionResult(action.func, result);
630
961
  const isSuccess = true;
631
- const { values, results } = await this.results.extractQueryResults(
962
+ const { values, valuesRaw, results } = await this.results.extractQueryResults(
632
963
  executable.warp,
633
964
  decodedResult,
634
965
  executable.action,
@@ -644,6 +975,7 @@ var WarpEvmExecutor = class {
644
975
  tx: null,
645
976
  next,
646
977
  values,
978
+ valuesRaw,
647
979
  results,
648
980
  messages: applyResultsToMessages(executable.warp, results)
649
981
  };
@@ -657,37 +989,14 @@ var WarpEvmExecutor = class {
657
989
  tx: null,
658
990
  next: null,
659
991
  values: [],
992
+ valuesRaw: [],
660
993
  results: {},
661
994
  messages: {}
662
995
  };
663
996
  }
664
997
  }
665
998
  async preprocessInput(chain, input, type, value) {
666
- const typedValue = this.serializer.stringToTyped(value);
667
- switch (type) {
668
- case "address":
669
- if (!ethers3.isAddress(typedValue)) {
670
- throw new Error(`Invalid address format: ${typedValue}`);
671
- }
672
- return ethers3.getAddress(typedValue);
673
- case "hex":
674
- if (!ethers3.isHexString(typedValue)) {
675
- throw new Error(`Invalid hex format: ${typedValue}`);
676
- }
677
- return typedValue;
678
- case "uint8":
679
- case "uint16":
680
- case "uint32":
681
- case "uint64":
682
- case "biguint":
683
- const bigIntValue = BigInt(typedValue);
684
- if (bigIntValue < 0) {
685
- throw new Error(`Negative value not allowed for type ${type}: ${typedValue}`);
686
- }
687
- return bigIntValue.toString();
688
- default:
689
- return String(typedValue);
690
- }
999
+ return input;
691
1000
  }
692
1001
  async estimateGasAndSetDefaults(tx, from) {
693
1002
  try {
@@ -705,6 +1014,7 @@ var WarpEvmExecutor = class {
705
1014
  if (feeData.maxFeePerGas && feeData.maxPriorityFeePerGas) {
706
1015
  return {
707
1016
  ...tx,
1017
+ chainId: BigInt(this.chain.chainId),
708
1018
  gasLimit: gasEstimate,
709
1019
  maxFeePerGas: feeData.maxFeePerGas,
710
1020
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
@@ -712,32 +1022,53 @@ var WarpEvmExecutor = class {
712
1022
  } else if (feeData.gasPrice) {
713
1023
  return {
714
1024
  ...tx,
1025
+ chainId: BigInt(this.chain.chainId),
715
1026
  gasLimit: gasEstimate,
716
1027
  gasPrice: feeData.gasPrice
717
1028
  };
718
1029
  } else {
719
1030
  return {
720
1031
  ...tx,
1032
+ chainId: BigInt(this.chain.chainId),
721
1033
  gasLimit: gasEstimate,
722
- gasPrice: ethers3.parseUnits(WarpEvmConstants.GasPrice.Default, "wei")
1034
+ gasPrice: ethers4.parseUnits(WarpEvmConstants.GasPrice.Default, "wei")
723
1035
  };
724
1036
  }
725
1037
  } catch (error) {
726
1038
  let defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.Default);
727
1039
  if (tx.data && tx.data !== "0x") {
728
- defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.ContractCall);
1040
+ if (tx.data.startsWith("0xa9059cbb")) {
1041
+ defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.TokenTransfer);
1042
+ } else {
1043
+ defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.ContractCall);
1044
+ }
729
1045
  } else {
730
1046
  defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.Transfer);
731
1047
  }
732
1048
  return {
733
1049
  ...tx,
1050
+ chainId: BigInt(this.chain.chainId),
734
1051
  gasLimit: defaultGasLimit,
735
- gasPrice: ethers3.parseUnits(WarpEvmConstants.GasPrice.Default, "wei")
1052
+ gasPrice: ethers4.parseUnits(WarpEvmConstants.GasPrice.Default, "wei")
736
1053
  };
737
1054
  }
738
1055
  }
739
1056
  async signMessage(message, privateKey) {
740
- throw new Error("Not implemented");
1057
+ try {
1058
+ const wallet = new ethers4.Wallet(privateKey);
1059
+ const signature = await wallet.signMessage(message);
1060
+ return signature;
1061
+ } catch (error) {
1062
+ throw new Error(`Failed to sign message: ${error}`);
1063
+ }
1064
+ }
1065
+ async verifyMessage(message, signature) {
1066
+ try {
1067
+ const recoveredAddress = ethers4.verifyMessage(message, signature);
1068
+ return recoveredAddress;
1069
+ } catch (error) {
1070
+ throw new Error(`Failed to verify message: ${error}`);
1071
+ }
741
1072
  }
742
1073
  };
743
1074
 
@@ -825,6 +1156,39 @@ var WarpEvmExplorer = class {
825
1156
  });
826
1157
  return urls;
827
1158
  }
1159
+ getAssetUrls(identifier) {
1160
+ const explorers = this.getAllExplorers();
1161
+ const urls = {};
1162
+ explorers.forEach((explorer) => {
1163
+ const url = ExplorerUrls[explorer];
1164
+ if (url) {
1165
+ urls[explorer] = `${url}/token/${identifier}`;
1166
+ }
1167
+ });
1168
+ return urls;
1169
+ }
1170
+ getContractUrls(address) {
1171
+ const explorers = this.getAllExplorers();
1172
+ const urls = {};
1173
+ explorers.forEach((explorer) => {
1174
+ const url = ExplorerUrls[explorer];
1175
+ if (url) {
1176
+ urls[explorer] = `${url}/address/${address}`;
1177
+ }
1178
+ });
1179
+ return urls;
1180
+ }
1181
+ getBlockUrls(blockNumber) {
1182
+ const explorers = this.getAllExplorers();
1183
+ const urls = {};
1184
+ explorers.forEach((explorer) => {
1185
+ const url = ExplorerUrls[explorer];
1186
+ if (url) {
1187
+ urls[explorer] = `${url}/block/${blockNumber}`;
1188
+ }
1189
+ });
1190
+ return urls;
1191
+ }
828
1192
  };
829
1193
 
830
1194
  // src/chains/common.ts
@@ -837,7 +1201,7 @@ var createEvmAdapter = (chainName, chainPrefix, chainInfos) => {
837
1201
  prefix: chainPrefix,
838
1202
  builder: () => fallback.builder(),
839
1203
  executor: new WarpEvmExecutor(config, chainInfos[config.env]),
840
- results: new WarpEvmResults(config),
1204
+ results: new WarpEvmResults(config, chainInfos[config.env]),
841
1205
  serializer: new WarpEvmSerializer(),
842
1206
  registry: fallback.registry,
843
1207
  explorer: new WarpEvmExplorer(chainInfos[config.env], config),
@@ -849,54 +1213,55 @@ var createEvmAdapter = (chainName, chainPrefix, chainInfos) => {
849
1213
  };
850
1214
 
851
1215
  // src/chains/arbitrum.ts
852
- var ChainNameArbitrum = "arbitrum";
853
1216
  var NativeTokenArb = {
1217
+ chain: WarpChainName.Arbitrum,
854
1218
  identifier: "ARB",
855
1219
  name: "ARB",
856
1220
  decimals: 18,
857
1221
  logoUrl: "https://vleap.ai/images/tokens/arb.svg"
858
1222
  };
859
- var getArbitrumAdapter = createEvmAdapter(ChainNameArbitrum, "arb", {
860
- devnet: {
861
- name: ChainNameArbitrum,
862
- displayName: "Arbitrum Devnet",
863
- chainId: "421614",
1223
+ var getArbitrumAdapter = createEvmAdapter(WarpChainName.Arbitrum, "arb", {
1224
+ mainnet: {
1225
+ name: WarpChainName.Arbitrum,
1226
+ displayName: "Arbitrum",
1227
+ chainId: "42161",
864
1228
  blockTime: 1e3,
865
1229
  addressHrp: "0x",
866
- defaultApiUrl: "https://sepolia-rollup.arbitrum.io/rpc",
1230
+ defaultApiUrl: "https://arb1.arbitrum.io/rpc",
867
1231
  nativeToken: NativeTokenArb
868
1232
  },
869
1233
  testnet: {
870
- name: ChainNameArbitrum,
871
- displayName: "Arbitrum Testnet",
872
- chainId: "421613",
1234
+ name: WarpChainName.Arbitrum,
1235
+ displayName: "Arbitrum Sepolia",
1236
+ chainId: "421614",
873
1237
  blockTime: 1e3,
874
1238
  addressHrp: "0x",
875
- defaultApiUrl: "https://goerli-rollup.arbitrum.io/rpc",
1239
+ defaultApiUrl: "https://sepolia-rollup.arbitrum.io/rpc",
876
1240
  nativeToken: NativeTokenArb
877
1241
  },
878
- mainnet: {
879
- name: ChainNameArbitrum,
880
- displayName: "Arbitrum",
881
- chainId: "42161",
1242
+ devnet: {
1243
+ name: WarpChainName.Arbitrum,
1244
+ displayName: "Arbitrum Sepolia",
1245
+ chainId: "421614",
882
1246
  blockTime: 1e3,
883
1247
  addressHrp: "0x",
884
- defaultApiUrl: "https://arb1.arbitrum.io/rpc",
1248
+ defaultApiUrl: "https://sepolia-rollup.arbitrum.io/rpc",
885
1249
  nativeToken: NativeTokenArb
886
1250
  }
887
1251
  });
888
1252
 
889
1253
  // src/chains/base.ts
890
- var ChainNameBase = "base";
1254
+ import { WarpChainName as WarpChainName2 } from "@vleap/warps";
891
1255
  var NativeTokenBase = {
1256
+ chain: WarpChainName2.Base,
892
1257
  identifier: "ETH",
893
1258
  name: "ETH",
894
1259
  decimals: 18,
895
1260
  logoUrl: "https://vleap.ai/images/tokens/eth.svg"
896
1261
  };
897
- var getBaseAdapter = createEvmAdapter(ChainNameBase, "base", {
1262
+ var getBaseAdapter = createEvmAdapter(WarpChainName2.Base, "base", {
898
1263
  mainnet: {
899
- name: ChainNameBase,
1264
+ name: WarpChainName2.Base,
900
1265
  displayName: "Base",
901
1266
  chainId: "8453",
902
1267
  blockTime: 2e3,
@@ -905,17 +1270,17 @@ var getBaseAdapter = createEvmAdapter(ChainNameBase, "base", {
905
1270
  nativeToken: NativeTokenBase
906
1271
  },
907
1272
  testnet: {
908
- name: ChainNameBase,
909
- displayName: "Base Testnet",
910
- chainId: "84531",
1273
+ name: WarpChainName2.Base,
1274
+ displayName: "Base Sepolia",
1275
+ chainId: "84532",
911
1276
  blockTime: 2e3,
912
1277
  addressHrp: "0x",
913
- defaultApiUrl: "https://goerli.base.org",
1278
+ defaultApiUrl: "https://sepolia.base.org",
914
1279
  nativeToken: NativeTokenBase
915
1280
  },
916
1281
  devnet: {
917
- name: ChainNameBase,
918
- displayName: "Base Devnet",
1282
+ name: WarpChainName2.Base,
1283
+ displayName: "Base Sepolia",
919
1284
  chainId: "84532",
920
1285
  blockTime: 2e3,
921
1286
  addressHrp: "0x",
@@ -924,40 +1289,44 @@ var getBaseAdapter = createEvmAdapter(ChainNameBase, "base", {
924
1289
  }
925
1290
  });
926
1291
 
1292
+ // src/chains/combined.ts
1293
+ import { WarpChainName as WarpChainName4 } from "@vleap/warps";
1294
+
927
1295
  // src/chains/ethereum.ts
928
- var ChainNameEthereum = "ethereum";
1296
+ import { WarpChainName as WarpChainName3 } from "@vleap/warps";
929
1297
  var NativeTokenEth = {
1298
+ chain: WarpChainName3.Ethereum,
930
1299
  identifier: "ETH",
931
1300
  name: "ETH",
932
1301
  decimals: 18,
933
1302
  logoUrl: "https://vleap.ai/images/tokens/eth.svg"
934
1303
  };
935
- var getEthereumAdapter = createEvmAdapter(ChainNameEthereum, "eth", {
936
- devnet: {
937
- name: ChainNameEthereum,
938
- displayName: "Ethereum Devnet",
939
- chainId: "11155111",
1304
+ var getEthereumAdapter = createEvmAdapter(WarpChainName3.Ethereum, "eth", {
1305
+ mainnet: {
1306
+ name: WarpChainName3.Ethereum,
1307
+ displayName: "Ethereum Mainnet",
1308
+ chainId: "1",
940
1309
  blockTime: 12e3,
941
1310
  addressHrp: "0x",
942
- defaultApiUrl: "https://ethereum-sepolia-rpc.publicnode.com",
1311
+ defaultApiUrl: "https://ethereum-rpc.publicnode.com",
943
1312
  nativeToken: NativeTokenEth
944
1313
  },
945
1314
  testnet: {
946
- name: ChainNameEthereum,
947
- displayName: "Ethereum Testnet",
1315
+ name: WarpChainName3.Ethereum,
1316
+ displayName: "Ethereum Sepolia",
948
1317
  chainId: "11155111",
949
1318
  blockTime: 12e3,
950
1319
  addressHrp: "0x",
951
1320
  defaultApiUrl: "https://ethereum-sepolia-rpc.publicnode.com",
952
1321
  nativeToken: NativeTokenEth
953
1322
  },
954
- mainnet: {
955
- name: ChainNameEthereum,
956
- displayName: "Ethereum Mainnet",
957
- chainId: "1",
1323
+ devnet: {
1324
+ name: WarpChainName3.Ethereum,
1325
+ displayName: "Ethereum Sepolia",
1326
+ chainId: "11155111",
958
1327
  blockTime: 12e3,
959
1328
  addressHrp: "0x",
960
- defaultApiUrl: "https://ethereum-rpc.publicnode.com",
1329
+ defaultApiUrl: "https://ethereum-sepolia-rpc.publicnode.com",
961
1330
  nativeToken: NativeTokenEth
962
1331
  }
963
1332
  });
@@ -968,24 +1337,24 @@ var getAllEvmAdapters = (config, fallback) => [
968
1337
  getArbitrumAdapter(config, fallback),
969
1338
  getBaseAdapter(config, fallback)
970
1339
  ];
971
- var getAllEvmChainNames = () => [ChainNameArbitrum, ChainNameBase, ChainNameEthereum];
1340
+ var getAllEvmChainNames = () => [WarpChainName4.Ethereum, WarpChainName4.Base, WarpChainName4.Arbitrum];
972
1341
  export {
973
1342
  ArbitrumExplorers,
974
1343
  BaseExplorers,
975
- ChainNameArbitrum,
976
- ChainNameBase,
977
- ChainNameEthereum,
978
1344
  EthereumExplorers,
979
1345
  EvmExplorers,
1346
+ EvmLogoService,
980
1347
  ExplorerUrls,
981
1348
  NativeTokenArb,
982
1349
  NativeTokenBase,
983
1350
  NativeTokenEth,
984
1351
  WarpEvmConstants,
1352
+ WarpEvmDataLoader,
985
1353
  WarpEvmExecutor,
986
1354
  WarpEvmExplorer,
987
1355
  WarpEvmResults,
988
1356
  WarpEvmSerializer,
1357
+ createEvmAdapter,
989
1358
  getAllEvmAdapters,
990
1359
  getAllEvmChainNames,
991
1360
  getArbitrumAdapter,