@vleap/warps-adapter-evm 0.2.0-alpha.2 → 0.2.0-alpha.20

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.js CHANGED
@@ -20,318 +20,604 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- EVM_CHAIN_CONFIGS: () => EVM_CHAIN_CONFIGS,
24
- WarpEvmBuilder: () => WarpEvmBuilder,
23
+ ArbitrumExplorers: () => ArbitrumExplorers,
24
+ BaseExplorers: () => BaseExplorers,
25
+ EthereumExplorers: () => EthereumExplorers,
26
+ EvmExplorers: () => EvmExplorers,
27
+ EvmLogoService: () => EvmLogoService,
28
+ ExplorerUrls: () => ExplorerUrls,
29
+ NativeTokenArb: () => NativeTokenArb,
30
+ NativeTokenBase: () => NativeTokenBase,
31
+ NativeTokenEth: () => NativeTokenEth,
25
32
  WarpEvmConstants: () => WarpEvmConstants,
33
+ WarpEvmDataLoader: () => WarpEvmDataLoader,
26
34
  WarpEvmExecutor: () => WarpEvmExecutor,
27
35
  WarpEvmExplorer: () => WarpEvmExplorer,
28
36
  WarpEvmResults: () => WarpEvmResults,
29
37
  WarpEvmSerializer: () => WarpEvmSerializer,
30
- getEvmAdapter: () => getEvmAdapter,
31
- getEvmApiUrl: () => getEvmApiUrl,
32
- getEvmBlockTime: () => getEvmBlockTime,
33
- getEvmChainConfig: () => getEvmChainConfig,
34
- getEvmChainId: () => getEvmChainId,
35
- getEvmExplorerUrl: () => getEvmExplorerUrl,
36
- getEvmNativeToken: () => getEvmNativeToken,
37
- getEvmRegistryAddress: () => getEvmRegistryAddress,
38
- getSupportedEnvironments: () => getSupportedEnvironments,
39
- getSupportedEvmChains: () => getSupportedEvmChains
38
+ createEvmAdapter: () => createEvmAdapter,
39
+ getAllEvmAdapters: () => getAllEvmAdapters,
40
+ getAllEvmChainNames: () => getAllEvmChainNames,
41
+ getArbitrumAdapter: () => getArbitrumAdapter,
42
+ getBaseAdapter: () => getBaseAdapter,
43
+ getEthereumAdapter: () => getEthereumAdapter
40
44
  });
41
45
  module.exports = __toCommonJS(index_exports);
42
46
 
43
- // src/config.ts
44
- var EVM_CHAIN_CONFIGS = {
47
+ // src/chains/arbitrum.ts
48
+ var import_warps5 = require("@vleap/warps");
49
+
50
+ // src/WarpEvmDataLoader.ts
51
+ var import_warps = require("@vleap/warps");
52
+ var import_ethers = require("ethers");
53
+
54
+ // src/LogoService.ts
55
+ var CHAIN_IDS = {
56
+ ethereum: 1,
57
+ arbitrum: 42161,
58
+ base: 8453
59
+ };
60
+ var FALLBACK_LOGOS = {
45
61
  ethereum: {
46
- mainnet: {
47
- apiUrl: "https://eth-mainnet.g.alchemy.com/v2/demo",
48
- explorerUrl: "https://etherscan.io",
49
- chainId: "1",
50
- registryAddress: "0x0000000000000000000000000000000000000000",
51
- nativeToken: "ETH",
52
- blockTime: 12
53
- },
54
- testnet: {
55
- apiUrl: "https://eth-sepolia.g.alchemy.com/v2/demo",
56
- explorerUrl: "https://sepolia.etherscan.io",
57
- chainId: "11155111",
58
- registryAddress: "0x0000000000000000000000000000000000000000",
59
- nativeToken: "ETH",
60
- blockTime: 12
61
- },
62
- devnet: {
63
- apiUrl: "http://localhost:8545",
64
- explorerUrl: "http://localhost:4000",
65
- chainId: "1337",
66
- registryAddress: "0x0000000000000000000000000000000000000000",
67
- nativeToken: "ETH",
68
- blockTime: 12
69
- }
62
+ "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png",
63
+ "0xdAC17F958D2ee523a2206206994597C13D831ec7": "https://assets.coingecko.com/coins/images/325/small/Tether.png",
64
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599": "https://assets.coingecko.com/coins/images/7598/small/wrapped_bitcoin_wbtc.png",
65
+ "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": "https://assets.coingecko.com/coins/images/2518/small/weth.png",
66
+ "0x6B175474E89094C44Da98b954EedeAC495271d0F": "https://assets.coingecko.com/coins/images/9956/small/4943.png"
70
67
  },
71
68
  arbitrum: {
72
- mainnet: {
73
- apiUrl: "https://arb-mainnet.g.alchemy.com/v2/demo",
74
- explorerUrl: "https://arbiscan.io",
75
- chainId: "42161",
76
- registryAddress: "0x0000000000000000000000000000000000000000",
77
- nativeToken: "ETH",
78
- blockTime: 1
79
- },
80
- testnet: {
81
- apiUrl: "https://arb-sepolia.g.alchemy.com/v2/demo",
82
- explorerUrl: "https://sepolia.arbiscan.io",
83
- chainId: "421614",
84
- registryAddress: "0x0000000000000000000000000000000000000000",
85
- nativeToken: "ETH",
86
- blockTime: 1
87
- },
88
- devnet: {
89
- apiUrl: "http://localhost:8545",
90
- explorerUrl: "http://localhost:4000",
91
- chainId: "1337",
92
- registryAddress: "0x0000000000000000000000000000000000000000",
93
- nativeToken: "ETH",
94
- blockTime: 1
95
- }
69
+ "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8": "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png",
70
+ "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9": "https://assets.coingecko.com/coins/images/325/small/Tether.png",
71
+ "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1": "https://assets.coingecko.com/coins/images/2518/small/weth.png"
96
72
  },
97
73
  base: {
98
- mainnet: {
99
- apiUrl: "https://mainnet.base.org",
100
- explorerUrl: "https://basescan.org",
101
- chainId: "8453",
102
- registryAddress: "0x0000000000000000000000000000000000000000",
103
- nativeToken: "ETH",
104
- blockTime: 2
105
- },
106
- testnet: {
107
- apiUrl: "https://sepolia.base.org",
108
- explorerUrl: "https://sepolia.basescan.org",
109
- chainId: "84532",
110
- registryAddress: "0x0000000000000000000000000000000000000000",
111
- nativeToken: "ETH",
112
- blockTime: 2
113
- },
114
- devnet: {
115
- apiUrl: "http://localhost:8545",
116
- explorerUrl: "http://localhost:4000",
117
- chainId: "1337",
118
- registryAddress: "0x0000000000000000000000000000000000000000",
119
- nativeToken: "ETH",
120
- blockTime: 2
121
- }
74
+ "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913": "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png",
75
+ "0x4200000000000000000000000000000000000006": "https://assets.coingecko.com/coins/images/2518/small/weth.png",
76
+ "0x036CbD53842c5426634e7929541eC2318f3dCF7e": "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png",
77
+ "0x808456652fdb597867f38412077A9182bf77359F": "https://assets.coingecko.com/coins/images/3318/small/euro-coin.png",
78
+ "0xcbB7C0006F23900c38EB856149F799620fcb8A4a": "https://assets.coingecko.com/coins/images/7598/small/wrapped_bitcoin_wbtc.png"
122
79
  }
123
80
  };
124
- var DEFAULT_CHAIN = "ethereum";
125
- var getEvmChainConfig = (chain = DEFAULT_CHAIN, env) => {
126
- const chainConfigs = EVM_CHAIN_CONFIGS[chain];
127
- if (!chainConfigs) {
128
- throw new Error(`Unsupported EVM chain: ${chain}`);
81
+ var TOKEN_LISTS = [
82
+ "https://tokens.uniswap.org",
83
+ "https://raw.githubusercontent.com/compound-finance/token-list/master/compound.tokenlist.json",
84
+ "https://tokens.1inch.io"
85
+ ];
86
+ var logoCache = /* @__PURE__ */ new Map();
87
+ var tokenInfoCache = /* @__PURE__ */ new Map();
88
+ var tokenListCache = /* @__PURE__ */ new Map();
89
+ var EvmLogoService = class {
90
+ static async getTokenInfo(chainName, tokenAddress) {
91
+ const cacheKey = `${chainName}:${tokenAddress.toLowerCase()}`;
92
+ if (tokenInfoCache.has(cacheKey)) {
93
+ return tokenInfoCache.get(cacheKey);
94
+ }
95
+ let tokenInfo = {};
96
+ try {
97
+ tokenInfo = await this.fetchFromTokenLists(chainName, tokenAddress);
98
+ } catch (error) {
99
+ }
100
+ if (!tokenInfo.logoURI) {
101
+ try {
102
+ tokenInfo = { ...tokenInfo, ...await this.fetchFromDefiLlama(chainName, tokenAddress) };
103
+ } catch (error) {
104
+ }
105
+ }
106
+ tokenInfoCache.set(cacheKey, tokenInfo);
107
+ return tokenInfo;
129
108
  }
130
- const config = chainConfigs[env];
131
- if (!config) {
132
- throw new Error(`Unsupported environment ${env} for chain ${chain}`);
109
+ static async getLogoUrl(chainName, tokenAddress, tokenName, tokenSymbol) {
110
+ const cacheKey = `${chainName}:${tokenAddress.toLowerCase()}`;
111
+ if (logoCache.has(cacheKey)) {
112
+ return logoCache.get(cacheKey);
113
+ }
114
+ let logoUrl = "";
115
+ const fallbackLogos = FALLBACK_LOGOS[chainName];
116
+ if (fallbackLogos && fallbackLogos[tokenAddress]) {
117
+ logoUrl = fallbackLogos[tokenAddress];
118
+ } else {
119
+ const tokenInfo = await this.getTokenInfo(chainName, tokenAddress);
120
+ logoUrl = tokenInfo.logoURI || "";
121
+ if (!logoUrl && (tokenSymbol || tokenName)) {
122
+ try {
123
+ logoUrl = await this.fetchFromTrustWallet(chainName, tokenAddress);
124
+ } catch (error) {
125
+ }
126
+ }
127
+ }
128
+ logoCache.set(cacheKey, logoUrl);
129
+ return logoUrl;
133
130
  }
134
- return config;
135
- };
136
- var getEvmApiUrl = (env, chain = DEFAULT_CHAIN) => {
137
- return getEvmChainConfig(chain, env).apiUrl;
138
- };
139
- var getEvmExplorerUrl = (env, chain = DEFAULT_CHAIN) => {
140
- return getEvmChainConfig(chain, env).explorerUrl;
141
- };
142
- var getEvmChainId = (env, chain = DEFAULT_CHAIN) => {
143
- return getEvmChainConfig(chain, env).chainId;
144
- };
145
- var getEvmRegistryAddress = (env, chain = DEFAULT_CHAIN) => {
146
- return getEvmChainConfig(chain, env).registryAddress;
147
- };
148
- var getEvmNativeToken = (env, chain = DEFAULT_CHAIN) => {
149
- return getEvmChainConfig(chain, env).nativeToken;
150
- };
151
- var getEvmBlockTime = (env, chain = DEFAULT_CHAIN) => {
152
- return getEvmChainConfig(chain, env).blockTime || 12;
153
- };
154
- var getSupportedEvmChains = () => {
155
- return Object.keys(EVM_CHAIN_CONFIGS);
156
- };
157
- var getSupportedEnvironments = (chain) => {
158
- const chainConfigs = EVM_CHAIN_CONFIGS[chain];
159
- if (!chainConfigs) {
160
- return [];
131
+ static async fetchFromTokenLists(chainName, tokenAddress) {
132
+ const chainId = CHAIN_IDS[chainName];
133
+ if (!chainId) return {};
134
+ const normalizedAddress = tokenAddress.toLowerCase();
135
+ if (tokenListCache.has(`${chainId}:${normalizedAddress}`)) {
136
+ return tokenListCache.get(`${chainId}:${normalizedAddress}`) || {};
137
+ }
138
+ for (const tokenListUrl of TOKEN_LISTS) {
139
+ try {
140
+ const response = await fetch(tokenListUrl, {
141
+ headers: { Accept: "application/json" },
142
+ signal: AbortSignal.timeout(5e3)
143
+ });
144
+ if (response.ok) {
145
+ const data = await response.json();
146
+ const token = data.tokens.find((t) => t.chainId === chainId && t.address.toLowerCase() === normalizedAddress);
147
+ if (token) {
148
+ const tokenInfo = {
149
+ name: token.name,
150
+ symbol: token.symbol,
151
+ decimals: token.decimals,
152
+ logoURI: token.logoURI
153
+ };
154
+ tokenListCache.set(`${chainId}:${normalizedAddress}`, tokenInfo);
155
+ return tokenInfo;
156
+ }
157
+ }
158
+ } catch (error) {
159
+ continue;
160
+ }
161
+ }
162
+ return {};
163
+ }
164
+ static async fetchFromDefiLlama(chainName, tokenAddress) {
165
+ try {
166
+ const chainMapping = {
167
+ ethereum: "ethereum",
168
+ arbitrum: "arbitrum",
169
+ base: "base"
170
+ };
171
+ const chain = chainMapping[chainName];
172
+ if (!chain) return {};
173
+ const response = await fetch(`https://coins.llama.fi/prices/current/${chain}:${tokenAddress}`, { signal: AbortSignal.timeout(5e3) });
174
+ if (response.ok) {
175
+ const data = await response.json();
176
+ const coinData = data.coins?.[`${chain}:${tokenAddress}`];
177
+ if (coinData) {
178
+ return {
179
+ symbol: coinData.symbol,
180
+ logoURI: coinData.logoURI
181
+ };
182
+ }
183
+ }
184
+ } catch (error) {
185
+ }
186
+ return {};
187
+ }
188
+ static async fetchFromTrustWallet(chainName, tokenAddress) {
189
+ try {
190
+ const chainMapping = {
191
+ ethereum: "ethereum",
192
+ arbitrum: "arbitrum",
193
+ base: "base"
194
+ };
195
+ const chain = chainMapping[chainName];
196
+ if (!chain) return "";
197
+ const logoUrl = `https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/${chain}/assets/${tokenAddress}/logo.png`;
198
+ const response = await fetch(logoUrl, {
199
+ method: "HEAD",
200
+ signal: AbortSignal.timeout(3e3)
201
+ });
202
+ if (response.ok) {
203
+ return logoUrl;
204
+ }
205
+ } catch (error) {
206
+ }
207
+ return "";
208
+ }
209
+ static clearCache() {
210
+ logoCache.clear();
211
+ tokenInfoCache.clear();
212
+ tokenListCache.clear();
213
+ }
214
+ static getCacheSize() {
215
+ return logoCache.size + tokenInfoCache.size + tokenListCache.size;
161
216
  }
162
- return Object.keys(chainConfigs);
163
217
  };
164
218
 
165
- // src/constants.ts
166
- var WarpEvmConstants = {
167
- ChainName: "evm",
168
- ChainPrefix: "evm",
169
- Ether: {
170
- Identifier: "ETH",
171
- DisplayName: "Ether",
172
- Decimals: 18
173
- },
174
- GasLimit: {
175
- Default: 21e3,
176
- ContractCall: 1e5,
177
- ContractDeploy: 5e5,
178
- Transfer: 21e3,
179
- Approve: 46e3,
180
- Swap: 2e5
181
- },
182
- GasPrice: {
183
- Default: "20000000000",
184
- // 20 gwei
185
- Low: "10000000000",
186
- // 10 gwei
187
- Medium: "20000000000",
188
- // 20 gwei
189
- High: "50000000000"
190
- // 50 gwei
191
- },
192
- Network: {
193
- Ethereum: {
194
- ChainId: "1",
195
- Name: "Ethereum",
196
- BlockTime: 12
219
+ // src/WarpEvmDataLoader.ts
220
+ var ERC20_ABI = [
221
+ "function balanceOf(address owner) view returns (uint256)",
222
+ "function decimals() view returns (uint8)",
223
+ "function name() view returns (string)",
224
+ "function symbol() view returns (string)",
225
+ "function totalSupply() view returns (uint256)"
226
+ ];
227
+ var KNOWN_TOKENS = {
228
+ ethereum: {
229
+ "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": {
230
+ name: "USD Coin",
231
+ symbol: "USDC",
232
+ decimals: 6,
233
+ logoUrl: "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png"
197
234
  },
198
- Arbitrum: {
199
- ChainId: "42161",
200
- Name: "Arbitrum",
201
- BlockTime: 1
235
+ "0xdAC17F958D2ee523a2206206994597C13D831ec7": {
236
+ name: "Tether USD",
237
+ symbol: "USDT",
238
+ decimals: 6,
239
+ logoUrl: "https://assets.coingecko.com/coins/images/325/small/Tether.png"
202
240
  },
203
- Base: {
204
- ChainId: "8453",
205
- Name: "Base",
206
- BlockTime: 2
241
+ "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599": {
242
+ name: "Wrapped Bitcoin",
243
+ symbol: "WBTC",
244
+ decimals: 8,
245
+ logoUrl: "https://assets.coingecko.com/coins/images/7598/small/wrapped_bitcoin_wbtc.png"
246
+ },
247
+ "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": {
248
+ name: "Wrapped Ether",
249
+ symbol: "WETH",
250
+ decimals: 18,
251
+ logoUrl: "https://assets.coingecko.com/coins/images/2518/small/weth.png"
252
+ },
253
+ "0x6B175474E89094C44Da98b954EedeAC495271d0F": {
254
+ name: "Dai Stablecoin",
255
+ symbol: "DAI",
256
+ decimals: 18,
257
+ logoUrl: "https://assets.coingecko.com/coins/images/9956/small/4943.png"
258
+ },
259
+ // Sepolia testnet tokens
260
+ "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238": {
261
+ name: "USD Coin",
262
+ symbol: "USDC",
263
+ decimals: 6,
264
+ logoUrl: "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png"
265
+ },
266
+ "0x7169D38820dfd117C3FA1f22a697dBA58d90BA06": {
267
+ name: "Tether USD",
268
+ symbol: "USDT",
269
+ decimals: 6,
270
+ logoUrl: "https://assets.coingecko.com/coins/images/325/small/Tether.png"
271
+ },
272
+ "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9": {
273
+ name: "Wrapped Ether",
274
+ symbol: "WETH",
275
+ decimals: 18,
276
+ logoUrl: "https://assets.coingecko.com/coins/images/2518/small/weth.png"
207
277
  }
208
278
  },
209
- Validation: {
210
- AddressLength: 42,
211
- HexPrefix: "0x",
212
- MinGasLimit: 21e3,
213
- MaxGasLimit: 3e7
279
+ arbitrum: {
280
+ "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8": {
281
+ name: "USD Coin",
282
+ symbol: "USDC",
283
+ decimals: 6,
284
+ logoUrl: "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png"
285
+ },
286
+ "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9": {
287
+ name: "Tether USD",
288
+ symbol: "USDT",
289
+ decimals: 6,
290
+ logoUrl: "https://assets.coingecko.com/coins/images/325/small/Tether.png"
291
+ },
292
+ "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1": {
293
+ name: "Wrapped Ether",
294
+ symbol: "WETH",
295
+ decimals: 18,
296
+ logoUrl: "https://assets.coingecko.com/coins/images/2518/small/weth.png"
297
+ }
214
298
  },
215
- Timeouts: {
216
- DefaultRpcTimeout: 3e4,
217
- // 30 seconds
218
- GasEstimationTimeout: 1e4,
219
- // 10 seconds
220
- QueryTimeout: 15e3
221
- // 15 seconds
299
+ base: {
300
+ "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913": {
301
+ name: "USD Coin",
302
+ symbol: "USDC",
303
+ decimals: 6,
304
+ logoUrl: "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png"
305
+ },
306
+ "0x4200000000000000000000000000000000000006": {
307
+ name: "Wrapped Ether",
308
+ symbol: "WETH",
309
+ decimals: 18,
310
+ logoUrl: "https://assets.coingecko.com/coins/images/2518/small/weth.png"
311
+ },
312
+ "0x036CbD53842c5426634e7929541eC2318f3dCF7e": {
313
+ name: "USD Coin",
314
+ symbol: "USDC",
315
+ decimals: 6,
316
+ logoUrl: "https://assets.coingecko.com/coins/images/6319/small/USD_Coin_icon.png"
317
+ },
318
+ "0x808456652fdb597867f38412077A9182bf77359F": {
319
+ name: "Euro Coin",
320
+ symbol: "EURC",
321
+ decimals: 6,
322
+ logoUrl: "https://assets.coingecko.com/coins/images/3318/small/euro-coin.png"
323
+ },
324
+ "0xcbB7C0006F23900c38EB856149F799620fcb8A4a": {
325
+ name: "Coinbase Wrapped BTC",
326
+ symbol: "CBETH",
327
+ decimals: 8,
328
+ logoUrl: "https://assets.coingecko.com/coins/images/7598/small/wrapped_bitcoin_wbtc.png"
329
+ }
222
330
  }
223
331
  };
224
-
225
- // src/WarpEvmBuilder.ts
226
- var import_ethers = require("ethers");
227
- var WarpEvmBuilder = class {
228
- constructor(config) {
332
+ var WarpEvmDataLoader = class {
333
+ constructor(config, chain) {
229
334
  this.config = config;
230
- this.warp = {};
231
- this.actions = [];
335
+ this.chain = chain;
336
+ const apiUrl = (0, import_warps.getProviderUrl)(this.config, this.chain.name, this.config.env, this.chain.defaultApiUrl);
337
+ const network = new import_ethers.ethers.Network(this.chain.name, parseInt(this.chain.chainId));
338
+ this.provider = new import_ethers.ethers.JsonRpcProvider(apiUrl, network);
232
339
  }
233
- async createFromRaw(encoded) {
340
+ async getAccount(address) {
234
341
  try {
235
- const decoded = JSON.parse(encoded);
236
- return decoded;
342
+ const balance = await this.provider.getBalance(address);
343
+ return {
344
+ chain: this.chain.name,
345
+ address,
346
+ balance
347
+ };
237
348
  } catch (error) {
238
- throw new Error(`Failed to decode warp from raw data: ${error}`);
349
+ throw new Error(`Failed to get account balance for ${address}: ${error}`);
239
350
  }
240
351
  }
241
- setTitle(title) {
242
- this.warp.title = title;
243
- return this;
244
- }
245
- setDescription(description) {
246
- this.warp.description = description;
247
- return this;
248
- }
249
- setPreview(preview) {
250
- this.warp.preview = preview;
251
- return this;
252
- }
253
- setActions(actions) {
254
- this.actions = actions;
255
- return this;
352
+ async getAccountAssets(address) {
353
+ try {
354
+ const assets = [];
355
+ const tokenBalances = await this.getERC20TokenBalances(address);
356
+ for (const tokenBalance of tokenBalances) {
357
+ if (tokenBalance.balance > 0n) {
358
+ const logoUrl = tokenBalance.metadata.logoUrl || await EvmLogoService.getLogoUrl(
359
+ this.chain.name,
360
+ tokenBalance.tokenAddress,
361
+ tokenBalance.metadata.name,
362
+ tokenBalance.metadata.symbol
363
+ );
364
+ assets.push({
365
+ chain: this.chain.name,
366
+ identifier: tokenBalance.tokenAddress,
367
+ name: tokenBalance.metadata.name,
368
+ amount: tokenBalance.balance,
369
+ decimals: tokenBalance.metadata.decimals,
370
+ logoUrl: logoUrl || ""
371
+ });
372
+ }
373
+ }
374
+ return assets;
375
+ } catch (error) {
376
+ throw new Error(`Failed to get account assets for ${address}: ${error}`);
377
+ }
256
378
  }
257
- addAction(action) {
258
- this.actions.push(action);
259
- return this;
379
+ async getAccountActions(address, options) {
380
+ return [];
260
381
  }
261
- async build() {
262
- if (!this.warp.title) {
263
- throw new Error("Warp title is required");
382
+ async getERC20TokenBalances(address) {
383
+ const tokenBalances = [];
384
+ const knownTokens = KNOWN_TOKENS[this.chain.name] || {};
385
+ for (const [tokenAddress, metadata] of Object.entries(knownTokens)) {
386
+ try {
387
+ const balance = await this.getTokenBalance(address, tokenAddress);
388
+ if (balance > 0n) {
389
+ tokenBalances.push({
390
+ tokenAddress,
391
+ balance,
392
+ metadata
393
+ });
394
+ }
395
+ } catch (error) {
396
+ }
264
397
  }
265
- return {
266
- protocol: "warp",
267
- name: this.warp.name || "evm-warp",
268
- title: this.warp.title,
269
- description: this.warp.description || null,
270
- preview: this.warp.preview || null,
271
- actions: this.actions,
272
- meta: {
273
- chain: "evm",
274
- hash: import_ethers.ethers.keccak256(import_ethers.ethers.toUtf8Bytes(this.warp.title)),
275
- creator: this.config.user?.wallets?.evm || "",
276
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
398
+ const additionalTokens = await this.detectTokensFromEvents(address);
399
+ for (const tokenAddress of additionalTokens) {
400
+ if (!knownTokens[tokenAddress]) {
401
+ try {
402
+ const metadata = await this.getTokenMetadata(tokenAddress);
403
+ const balance = await this.getTokenBalance(address, tokenAddress);
404
+ if (balance > 0n) {
405
+ tokenBalances.push({
406
+ tokenAddress,
407
+ balance,
408
+ metadata
409
+ });
410
+ }
411
+ } catch (error) {
412
+ }
277
413
  }
278
- };
279
- }
280
- createInscriptionTransaction(warp) {
281
- const warpData = JSON.stringify(warp);
282
- const data = import_ethers.ethers.toUtf8Bytes(warpData);
283
- return {
284
- data: import_ethers.ethers.hexlify(data)
285
- };
414
+ }
415
+ return tokenBalances;
286
416
  }
287
- async createFromTransaction(tx, validate) {
288
- if (!tx.data || tx.data === "0x") {
289
- throw new Error("Transaction has no data");
417
+ async getTokenBalance(address, tokenAddress) {
418
+ try {
419
+ const contract = new import_ethers.ethers.Contract(tokenAddress, ERC20_ABI, this.provider);
420
+ const balance = await contract.balanceOf(address);
421
+ return balance;
422
+ } catch (error) {
423
+ throw new Error(`Failed to get token balance: ${error}`);
290
424
  }
425
+ }
426
+ async getTokenMetadata(tokenAddress) {
291
427
  try {
292
- const data = import_ethers.ethers.toUtf8String(tx.data);
293
- const warp = JSON.parse(data);
294
- if (validate) {
295
- if (!warp.protocol || warp.protocol !== "warp") {
296
- throw new Error("Invalid warp protocol");
297
- }
298
- if (!warp.title) {
299
- throw new Error("Warp title is required");
300
- }
428
+ const tokenInfo = await EvmLogoService.getTokenInfo(this.chain.name, tokenAddress);
429
+ if (tokenInfo.name && tokenInfo.symbol && tokenInfo.decimals !== void 0) {
430
+ return {
431
+ name: tokenInfo.name,
432
+ symbol: tokenInfo.symbol,
433
+ decimals: tokenInfo.decimals,
434
+ logoUrl: tokenInfo.logoURI
435
+ };
301
436
  }
302
- return warp;
437
+ const contract = new import_ethers.ethers.Contract(tokenAddress, ERC20_ABI, this.provider);
438
+ const [name, symbol, decimals] = await Promise.all([
439
+ contract.name().catch(() => tokenInfo.name || "Unknown Token"),
440
+ contract.symbol().catch(() => tokenInfo.symbol || "UNKNOWN"),
441
+ contract.decimals().catch(() => tokenInfo.decimals || 18)
442
+ ]);
443
+ return {
444
+ name: name || tokenInfo.name || "Unknown Token",
445
+ symbol: symbol || tokenInfo.symbol || "UNKNOWN",
446
+ decimals: decimals || tokenInfo.decimals || 18,
447
+ logoUrl: tokenInfo.logoURI
448
+ };
303
449
  } catch (error) {
304
- throw new Error(`Failed to create warp from transaction: ${error}`);
450
+ throw new Error(`Failed to get token metadata: ${error}`);
305
451
  }
306
452
  }
307
- async createFromTransactionHash(hash, cache) {
453
+ async detectTokensFromEvents(address) {
308
454
  try {
309
- const provider = new import_ethers.ethers.JsonRpcProvider(getEvmApiUrl(this.config.env));
310
- const tx = await provider.getTransaction(hash);
311
- if (!tx) {
312
- return null;
455
+ const currentBlock = await this.provider.getBlockNumber();
456
+ const fromBlock = Math.max(0, currentBlock - 1e4);
457
+ const filter = {
458
+ fromBlock,
459
+ toBlock: currentBlock,
460
+ topics: [
461
+ import_ethers.ethers.id("Transfer(address,address,uint256)"),
462
+ null,
463
+ // from address (any)
464
+ import_ethers.ethers.zeroPadValue(address, 32)
465
+ // to address (our target)
466
+ ]
467
+ };
468
+ const logs = await this.provider.getLogs(filter);
469
+ const tokenAddresses = /* @__PURE__ */ new Set();
470
+ for (const log of logs) {
471
+ tokenAddresses.add(log.address);
313
472
  }
314
- return await this.createFromTransaction(tx);
473
+ return Array.from(tokenAddresses);
474
+ } catch (error) {
475
+ return [];
476
+ }
477
+ }
478
+ // Additional utility methods for enhanced token support
479
+ async getTokenInfo(tokenAddress) {
480
+ try {
481
+ return await this.getTokenMetadata(tokenAddress);
482
+ } catch (error) {
483
+ return null;
484
+ }
485
+ }
486
+ async getTokenBalanceForAddress(address, tokenAddress) {
487
+ try {
488
+ return await this.getTokenBalance(address, tokenAddress);
489
+ } catch (error) {
490
+ throw new Error(`Failed to get token balance for ${tokenAddress}: ${error}`);
491
+ }
492
+ }
493
+ async getMultipleTokenBalances(address, tokenAddresses) {
494
+ const balances = /* @__PURE__ */ new Map();
495
+ await Promise.all(
496
+ tokenAddresses.map(async (tokenAddress) => {
497
+ try {
498
+ const balance = await this.getTokenBalance(address, tokenAddress);
499
+ balances.set(tokenAddress, balance);
500
+ } catch (error) {
501
+ balances.set(tokenAddress, 0n);
502
+ }
503
+ })
504
+ );
505
+ return balances;
506
+ }
507
+ async getAccountTokens(address) {
508
+ return this.getAccountAssets(address);
509
+ }
510
+ async getTokenMetadataPublic(tokenAddress) {
511
+ try {
512
+ return await this.getTokenMetadata(tokenAddress);
315
513
  } catch (error) {
316
514
  return null;
317
515
  }
318
516
  }
517
+ async getChainInfo() {
518
+ try {
519
+ const network = await this.provider.getNetwork();
520
+ const latestBlock = await this.provider.getBlock("latest");
521
+ return {
522
+ chainId: network.chainId.toString(),
523
+ blockTime: latestBlock?.timestamp ? Date.now() / 1e3 - latestBlock.timestamp : 12
524
+ };
525
+ } catch (error) {
526
+ throw new Error(`Failed to get chain info: ${error}`);
527
+ }
528
+ }
319
529
  };
320
530
 
321
531
  // src/WarpEvmExecutor.ts
322
- var import_warps3 = require("@vleap/warps");
323
- var import_ethers3 = require("ethers");
532
+ var import_warps4 = require("@vleap/warps");
533
+ var import_ethers4 = require("ethers");
534
+
535
+ // src/constants.ts
536
+ var WarpEvmConstants = {
537
+ GasLimit: {
538
+ Default: 21e3,
539
+ ContractCall: 1e5,
540
+ ContractDeploy: 5e5,
541
+ Transfer: 21e3,
542
+ TokenTransfer: 65e3,
543
+ // ERC-20 transfer gas limit
544
+ Approve: 46e3,
545
+ Swap: 2e5
546
+ },
547
+ GasPrice: {
548
+ Default: "20000000000"
549
+ },
550
+ Validation: {
551
+ MinGasLimit: 21e3,
552
+ MaxGasLimit: 3e7
553
+ }
554
+ };
555
+ var EthereumExplorers = /* @__PURE__ */ ((EthereumExplorers2) => {
556
+ EthereumExplorers2["Etherscan"] = "etherscan";
557
+ EthereumExplorers2["EtherscanSepolia"] = "etherscan_sepolia";
558
+ EthereumExplorers2["Ethplorer"] = "ethplorer";
559
+ EthereumExplorers2["Blockscout"] = "blockscout";
560
+ EthereumExplorers2["BlockscoutSepolia"] = "blockscout_sepolia";
561
+ return EthereumExplorers2;
562
+ })(EthereumExplorers || {});
563
+ var ArbitrumExplorers = /* @__PURE__ */ ((ArbitrumExplorers2) => {
564
+ ArbitrumExplorers2["Arbiscan"] = "arbiscan";
565
+ ArbitrumExplorers2["ArbiscanSepolia"] = "arbiscan_sepolia";
566
+ ArbitrumExplorers2["BlockscoutArbitrum"] = "blockscout_arbitrum";
567
+ ArbitrumExplorers2["BlockscoutArbitrumSepolia"] = "blockscout_arbitrum_sepolia";
568
+ return ArbitrumExplorers2;
569
+ })(ArbitrumExplorers || {});
570
+ var BaseExplorers = /* @__PURE__ */ ((BaseExplorers2) => {
571
+ BaseExplorers2["Basescan"] = "basescan";
572
+ BaseExplorers2["BasescanSepolia"] = "basescan_sepolia";
573
+ BaseExplorers2["BlockscoutBase"] = "blockscout_base";
574
+ BaseExplorers2["BlockscoutBaseSepolia"] = "blockscout_base_sepolia";
575
+ return BaseExplorers2;
576
+ })(BaseExplorers || {});
577
+ var EvmExplorers = {
578
+ ethereum: {
579
+ mainnet: ["etherscan" /* Etherscan */, "ethplorer" /* Ethplorer */, "blockscout" /* Blockscout */],
580
+ testnet: ["etherscan_sepolia" /* EtherscanSepolia */, "blockscout_sepolia" /* BlockscoutSepolia */],
581
+ devnet: ["etherscan_sepolia" /* EtherscanSepolia */, "blockscout_sepolia" /* BlockscoutSepolia */]
582
+ },
583
+ arbitrum: {
584
+ mainnet: ["arbiscan" /* Arbiscan */, "blockscout_arbitrum" /* BlockscoutArbitrum */],
585
+ testnet: ["arbiscan_sepolia" /* ArbiscanSepolia */, "blockscout_arbitrum_sepolia" /* BlockscoutArbitrumSepolia */],
586
+ devnet: ["arbiscan_sepolia" /* ArbiscanSepolia */, "blockscout_arbitrum_sepolia" /* BlockscoutArbitrumSepolia */]
587
+ },
588
+ base: {
589
+ mainnet: ["basescan" /* Basescan */, "blockscout_base" /* BlockscoutBase */],
590
+ testnet: ["basescan_sepolia" /* BasescanSepolia */, "blockscout_base_sepolia" /* BlockscoutBaseSepolia */],
591
+ devnet: ["basescan_sepolia" /* BasescanSepolia */, "blockscout_base_sepolia" /* BlockscoutBaseSepolia */]
592
+ }
593
+ };
594
+ var ExplorerUrls = {
595
+ ["etherscan" /* Etherscan */]: "https://etherscan.io",
596
+ ["etherscan_sepolia" /* EtherscanSepolia */]: "https://sepolia.etherscan.io",
597
+ ["ethplorer" /* Ethplorer */]: "https://ethplorer.io",
598
+ ["blockscout" /* Blockscout */]: "https://eth.blockscout.com",
599
+ ["blockscout_sepolia" /* BlockscoutSepolia */]: "https://sepolia.blockscout.com",
600
+ ["arbiscan" /* Arbiscan */]: "https://arbiscan.io",
601
+ ["arbiscan_sepolia" /* ArbiscanSepolia */]: "https://sepolia.arbiscan.io",
602
+ ["blockscout_arbitrum" /* BlockscoutArbitrum */]: "https://arbitrum.blockscout.com",
603
+ ["blockscout_arbitrum_sepolia" /* BlockscoutArbitrumSepolia */]: "https://sepolia.blockscout.com",
604
+ ["basescan" /* Basescan */]: "https://basescan.org",
605
+ ["basescan_sepolia" /* BasescanSepolia */]: "https://sepolia.basescan.org",
606
+ ["blockscout_base" /* BlockscoutBase */]: "https://base.blockscout.com",
607
+ ["blockscout_base_sepolia" /* BlockscoutBaseSepolia */]: "https://sepolia.blockscout.com"
608
+ };
324
609
 
325
610
  // src/WarpEvmResults.ts
326
- var import_warps2 = require("@vleap/warps");
611
+ var import_warps3 = require("@vleap/warps");
612
+ var import_ethers3 = require("ethers");
327
613
 
328
614
  // src/WarpEvmSerializer.ts
329
- var import_warps = require("@vleap/warps");
615
+ var import_warps2 = require("@vleap/warps");
330
616
  var import_ethers2 = require("ethers");
331
- var SplitParamsRegex = new RegExp(`${import_warps.WarpConstants.ArgParamsSeparator}(.*)`);
617
+ var SplitParamsRegex = new RegExp(`${import_warps2.WarpConstants.ArgParamsSeparator}(.*)`);
332
618
  var WarpEvmSerializer = class {
333
619
  constructor() {
334
- this.coreSerializer = new import_warps.WarpSerializer();
620
+ this.coreSerializer = new import_warps2.WarpSerializer();
335
621
  }
336
622
  typedToString(value) {
337
623
  if (typeof value === "string") {
@@ -360,9 +646,9 @@ var WarpEvmSerializer = class {
360
646
  }
361
647
  if (Array.isArray(value)) {
362
648
  if (value.length === 0) return `list:string:`;
363
- const types = value.map((item) => this.typedToString(item).split(import_warps.WarpConstants.ArgParamsSeparator)[0]);
649
+ const types = value.map((item) => this.typedToString(item).split(import_warps2.WarpConstants.ArgParamsSeparator)[0]);
364
650
  const type = types[0];
365
- const values = value.map((item) => this.typedToString(item).split(import_warps.WarpConstants.ArgParamsSeparator)[1]);
651
+ const values = value.map((item) => this.typedToString(item).split(import_warps2.WarpConstants.ArgParamsSeparator)[1]);
366
652
  return `list:${type}:${values.join(",")}`;
367
653
  }
368
654
  if (value === null || value === void 0) {
@@ -372,8 +658,8 @@ var WarpEvmSerializer = class {
372
658
  }
373
659
  typedToNative(value) {
374
660
  const stringValue = this.typedToString(value);
375
- const [type, ...valueParts] = stringValue.split(import_warps.WarpConstants.ArgParamsSeparator);
376
- const nativeValue = valueParts.join(import_warps.WarpConstants.ArgParamsSeparator);
661
+ const [type, ...valueParts] = stringValue.split(import_warps2.WarpConstants.ArgParamsSeparator);
662
+ const nativeValue = valueParts.join(import_warps2.WarpConstants.ArgParamsSeparator);
377
663
  return [type, this.parseNativeValue(type, nativeValue)];
378
664
  }
379
665
  nativeToTyped(type, value) {
@@ -424,7 +710,7 @@ var WarpEvmSerializer = class {
424
710
  }
425
711
  }
426
712
  stringToTyped(value) {
427
- const parts = value.split(import_warps.WarpConstants.ArgParamsSeparator, 2);
713
+ const parts = value.split(import_warps2.WarpConstants.ArgParamsSeparator, 2);
428
714
  if (parts.length < 2) {
429
715
  return value;
430
716
  }
@@ -479,9 +765,19 @@ var WarpEvmSerializer = class {
479
765
 
480
766
  // src/WarpEvmResults.ts
481
767
  var WarpEvmResults = class {
482
- constructor(config) {
768
+ constructor(config, chain) {
483
769
  this.config = config;
770
+ this.chain = chain;
484
771
  this.serializer = new WarpEvmSerializer();
772
+ if (this.chain) {
773
+ const apiUrl = (0, import_warps3.getProviderUrl)(this.config, this.chain.name, this.config.env, this.chain.defaultApiUrl);
774
+ const network = new import_ethers3.ethers.Network(this.chain.name, parseInt(this.chain.chainId));
775
+ this.provider = new import_ethers3.ethers.JsonRpcProvider(apiUrl, network);
776
+ } else {
777
+ const apiUrl = (0, import_warps3.getProviderUrl)(this.config, "ethereum", this.config.env, "https://ethereum-rpc.publicnode.com");
778
+ const network = new import_ethers3.ethers.Network("ethereum", 1);
779
+ this.provider = new import_ethers3.ethers.JsonRpcProvider(apiUrl, network);
780
+ }
485
781
  }
486
782
  async getTransactionExecutionResults(warp, tx) {
487
783
  const success = tx.status === 1;
@@ -503,8 +799,10 @@ var WarpEvmResults = class {
503
799
  action: 0,
504
800
  user: this.config.user?.wallets?.evm || null,
505
801
  txHash: transactionHash,
802
+ tx,
506
803
  next: null,
507
804
  values: [transactionHash, blockNumber, gasUsed, gasPrice, ...logs.length > 0 ? logs : []],
805
+ valuesRaw: [transactionHash, blockNumber, gasUsed, gasPrice, ...logs.length > 0 ? logs : []],
508
806
  results: {},
509
807
  messages: {}
510
808
  };
@@ -513,7 +811,7 @@ var WarpEvmResults = class {
513
811
  const values = typedValues.map((t) => this.serializer.typedToString(t));
514
812
  const valuesRaw = typedValues.map((t) => this.serializer.typedToNative(t)[1]);
515
813
  let results = {};
516
- if (!warp.results) return { values, results };
814
+ if (!warp.results) return { values, valuesRaw, results };
517
815
  const getNestedValue = (path) => {
518
816
  const indices = path.split(".").slice(1).map((i) => parseInt(i) - 1);
519
817
  if (indices.length === 0) return void 0;
@@ -525,8 +823,8 @@ var WarpEvmResults = class {
525
823
  return value;
526
824
  };
527
825
  for (const [key, path] of Object.entries(warp.results)) {
528
- if (path.startsWith(import_warps2.WarpConstants.Transform.Prefix)) continue;
529
- const currentActionIndex = (0, import_warps2.parseResultsOutIndex)(path);
826
+ if (path.startsWith(import_warps3.WarpConstants.Transform.Prefix)) continue;
827
+ const currentActionIndex = (0, import_warps3.parseResultsOutIndex)(path);
530
828
  if (currentActionIndex !== null && currentActionIndex !== actionIndex) {
531
829
  results[key] = null;
532
830
  continue;
@@ -537,20 +835,45 @@ var WarpEvmResults = class {
537
835
  results[key] = path;
538
836
  }
539
837
  }
540
- return { values, results: await (0, import_warps2.evaluateResultsCommon)(warp, results, actionIndex, inputs) };
838
+ return { values, valuesRaw, results: await (0, import_warps3.evaluateResultsCommon)(warp, results, actionIndex, inputs) };
839
+ }
840
+ async getTransactionStatus(txHash) {
841
+ try {
842
+ const receipt = await this.provider.getTransactionReceipt(txHash);
843
+ if (!receipt) {
844
+ return { status: "pending" };
845
+ }
846
+ return {
847
+ status: receipt.status === 1 ? "confirmed" : "failed",
848
+ blockNumber: receipt.blockNumber,
849
+ gasUsed: receipt.gasUsed
850
+ };
851
+ } catch (error) {
852
+ throw new Error(`Failed to get transaction status: ${error}`);
853
+ }
854
+ }
855
+ async getTransactionReceipt(txHash) {
856
+ try {
857
+ return await this.provider.getTransactionReceipt(txHash);
858
+ } catch (error) {
859
+ return null;
860
+ }
541
861
  }
542
862
  };
543
863
 
544
864
  // src/WarpEvmExecutor.ts
545
865
  var WarpEvmExecutor = class {
546
- constructor(config) {
866
+ constructor(config, chain) {
547
867
  this.config = config;
868
+ this.chain = chain;
548
869
  this.serializer = new WarpEvmSerializer();
549
- this.provider = new import_ethers3.ethers.JsonRpcProvider(getEvmApiUrl(config.env));
550
- this.results = new WarpEvmResults(config);
870
+ const apiUrl = (0, import_warps4.getProviderUrl)(this.config, chain.name, this.config.env, this.chain.defaultApiUrl);
871
+ const network = new import_ethers4.ethers.Network(this.chain.name, parseInt(this.chain.chainId));
872
+ this.provider = new import_ethers4.ethers.JsonRpcProvider(apiUrl, network);
873
+ this.results = new WarpEvmResults(config, this.chain);
551
874
  }
552
875
  async createTransaction(executable) {
553
- const action = (0, import_warps3.getWarpActionByIndex)(executable.warp, executable.action);
876
+ const action = (0, import_warps4.getWarpActionByIndex)(executable.warp, executable.action);
554
877
  let tx = null;
555
878
  if (action.type === "transfer") {
556
879
  tx = await this.createTransferTransaction(executable);
@@ -567,11 +890,11 @@ var WarpEvmExecutor = class {
567
890
  async createTransferTransaction(executable) {
568
891
  const userWallet = this.config.user?.wallets?.[executable.chain.name];
569
892
  if (!userWallet) throw new Error("WarpEvmExecutor: createTransfer - user address not set");
570
- if (!import_ethers3.ethers.isAddress(executable.destination)) {
893
+ if (!import_ethers4.ethers.isAddress(executable.destination)) {
571
894
  throw new Error(`WarpEvmExecutor: Invalid destination address: ${executable.destination}`);
572
895
  }
573
- if (executable.value < 0) {
574
- throw new Error(`WarpEvmExecutor: Transfer value cannot be negative: ${executable.value}`);
896
+ if (executable.transfers && executable.transfers.length > 0) {
897
+ return this.createTokenTransferTransaction(executable, userWallet);
575
898
  }
576
899
  const tx = {
577
900
  to: executable.destination,
@@ -583,18 +906,15 @@ var WarpEvmExecutor = class {
583
906
  async createContractCallTransaction(executable) {
584
907
  const userWallet = this.config.user?.wallets?.[executable.chain.name];
585
908
  if (!userWallet) throw new Error("WarpEvmExecutor: createContractCall - user address not set");
586
- const action = (0, import_warps3.getWarpActionByIndex)(executable.warp, executable.action);
909
+ const action = (0, import_warps4.getWarpActionByIndex)(executable.warp, executable.action);
587
910
  if (!action || !("func" in action) || !action.func) {
588
911
  throw new Error("WarpEvmExecutor: Contract action must have a function name");
589
912
  }
590
- if (!import_ethers3.ethers.isAddress(executable.destination)) {
913
+ if (!import_ethers4.ethers.isAddress(executable.destination)) {
591
914
  throw new Error(`WarpEvmExecutor: Invalid contract address: ${executable.destination}`);
592
915
  }
593
- if (executable.value < 0) {
594
- throw new Error(`WarpEvmExecutor: Contract call value cannot be negative: ${executable.value}`);
595
- }
596
916
  try {
597
- const iface = new import_ethers3.ethers.Interface([`function ${action.func}`]);
917
+ const iface = new import_ethers4.ethers.Interface([`function ${action.func}`]);
598
918
  const encodedData = iface.encodeFunctionData(action.func, executable.args);
599
919
  const tx = {
600
920
  to: executable.destination,
@@ -606,19 +926,63 @@ var WarpEvmExecutor = class {
606
926
  throw new Error(`WarpEvmExecutor: Failed to encode function data for ${action.func}: ${error}`);
607
927
  }
608
928
  }
929
+ async createTokenTransferTransaction(executable, userWallet) {
930
+ if (executable.transfers.length === 0) {
931
+ throw new Error("WarpEvmExecutor: No transfers provided");
932
+ }
933
+ if (!this.chain.nativeToken?.identifier) {
934
+ throw new Error("WarpEvmExecutor: No native token defined for this chain");
935
+ }
936
+ const nativeTokenTransfers = executable.transfers.filter((transfer) => transfer.identifier === this.chain.nativeToken.identifier);
937
+ const erc20Transfers = executable.transfers.filter((transfer) => transfer.identifier !== this.chain.nativeToken.identifier);
938
+ if (nativeTokenTransfers.length === 1 && erc20Transfers.length === 0) {
939
+ const transfer = nativeTokenTransfers[0];
940
+ if (transfer.amount <= 0n) {
941
+ throw new Error("WarpEvmExecutor: Native token transfer amount must be positive");
942
+ }
943
+ const tx = {
944
+ to: executable.destination,
945
+ value: transfer.amount,
946
+ data: "0x"
947
+ };
948
+ return this.estimateGasAndSetDefaults(tx, userWallet);
949
+ }
950
+ if (nativeTokenTransfers.length === 0 && erc20Transfers.length === 1) {
951
+ return this.createSingleTokenTransfer(executable, erc20Transfers[0], userWallet);
952
+ }
953
+ if (executable.transfers.length > 1) {
954
+ throw new Error("WarpEvmExecutor: Multiple token transfers not yet supported");
955
+ }
956
+ throw new Error("WarpEvmExecutor: Invalid transfer configuration");
957
+ }
958
+ async createSingleTokenTransfer(executable, transfer, userWallet) {
959
+ if (!import_ethers4.ethers.isAddress(transfer.identifier)) {
960
+ throw new Error(`WarpEvmExecutor: Invalid token address: ${transfer.identifier}`);
961
+ }
962
+ const transferInterface = new import_ethers4.ethers.Interface(["function transfer(address to, uint256 amount) returns (bool)"]);
963
+ const encodedData = transferInterface.encodeFunctionData("transfer", [executable.destination, transfer.amount]);
964
+ const tx = {
965
+ to: transfer.identifier,
966
+ // Token contract address
967
+ value: 0n,
968
+ // No native token value for ERC-20 transfers
969
+ data: encodedData
970
+ };
971
+ return this.estimateGasAndSetDefaults(tx, userWallet);
972
+ }
609
973
  async executeQuery(executable) {
610
- const action = (0, import_warps3.getWarpActionByIndex)(executable.warp, executable.action);
974
+ const action = (0, import_warps4.getWarpActionByIndex)(executable.warp, executable.action);
611
975
  if (action.type !== "query") {
612
976
  throw new Error(`WarpEvmExecutor: Invalid action type for executeQuery: ${action.type}`);
613
977
  }
614
978
  if (!action.func) {
615
979
  throw new Error("WarpEvmExecutor: Query action must have a function name");
616
980
  }
617
- if (!import_ethers3.ethers.isAddress(executable.destination)) {
981
+ if (!import_ethers4.ethers.isAddress(executable.destination)) {
618
982
  throw new Error(`WarpEvmExecutor: Invalid contract address for query: ${executable.destination}`);
619
983
  }
620
984
  try {
621
- const iface = new import_ethers3.ethers.Interface([`function ${action.func}`]);
985
+ const iface = new import_ethers4.ethers.Interface([`function ${action.func}`]);
622
986
  const encodedData = iface.encodeFunctionData(action.func, executable.args);
623
987
  const result = await this.provider.call({
624
988
  to: executable.destination,
@@ -626,24 +990,25 @@ var WarpEvmExecutor = class {
626
990
  });
627
991
  const decodedResult = iface.decodeFunctionResult(action.func, result);
628
992
  const isSuccess = true;
629
- const { values, results } = await this.results.extractQueryResults(
993
+ const { values, valuesRaw, results } = await this.results.extractQueryResults(
630
994
  executable.warp,
631
995
  decodedResult,
632
996
  executable.action,
633
997
  executable.resolvedInputs
634
998
  );
635
- const adapter = getEvmAdapter(this.config);
636
- const next = (0, import_warps3.getNextInfo)(this.config, adapter, executable.warp, executable.action, results);
999
+ const next = (0, import_warps4.getNextInfo)(this.config, [], executable.warp, executable.action, results);
637
1000
  return {
638
1001
  success: isSuccess,
639
1002
  warp: executable.warp,
640
1003
  action: executable.action,
641
1004
  user: this.config.user?.wallets?.[executable.chain.name] || null,
642
1005
  txHash: null,
1006
+ tx: null,
643
1007
  next,
644
1008
  values,
1009
+ valuesRaw,
645
1010
  results,
646
- messages: (0, import_warps3.applyResultsToMessages)(executable.warp, results)
1011
+ messages: (0, import_warps4.applyResultsToMessages)(executable.warp, results)
647
1012
  };
648
1013
  } catch (error) {
649
1014
  return {
@@ -652,39 +1017,17 @@ var WarpEvmExecutor = class {
652
1017
  action: executable.action,
653
1018
  user: this.config.user?.wallets?.[executable.chain.name] || null,
654
1019
  txHash: null,
1020
+ tx: null,
655
1021
  next: null,
656
1022
  values: [],
1023
+ valuesRaw: [],
657
1024
  results: {},
658
1025
  messages: {}
659
1026
  };
660
1027
  }
661
1028
  }
662
1029
  async preprocessInput(chain, input, type, value) {
663
- const typedValue = this.serializer.stringToTyped(value);
664
- switch (type) {
665
- case "address":
666
- if (!import_ethers3.ethers.isAddress(typedValue)) {
667
- throw new Error(`Invalid address format: ${typedValue}`);
668
- }
669
- return import_ethers3.ethers.getAddress(typedValue);
670
- case "hex":
671
- if (!import_ethers3.ethers.isHexString(typedValue)) {
672
- throw new Error(`Invalid hex format: ${typedValue}`);
673
- }
674
- return typedValue;
675
- case "uint8":
676
- case "uint16":
677
- case "uint32":
678
- case "uint64":
679
- case "biguint":
680
- const bigIntValue = BigInt(typedValue);
681
- if (bigIntValue < 0) {
682
- throw new Error(`Negative value not allowed for type ${type}: ${typedValue}`);
683
- }
684
- return bigIntValue.toString();
685
- default:
686
- return String(typedValue);
687
- }
1030
+ return input;
688
1031
  }
689
1032
  async estimateGasAndSetDefaults(tx, from) {
690
1033
  try {
@@ -702,6 +1045,7 @@ var WarpEvmExecutor = class {
702
1045
  if (feeData.maxFeePerGas && feeData.maxPriorityFeePerGas) {
703
1046
  return {
704
1047
  ...tx,
1048
+ chainId: BigInt(this.chain.chainId),
705
1049
  gasLimit: gasEstimate,
706
1050
  maxFeePerGas: feeData.maxFeePerGas,
707
1051
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
@@ -709,85 +1053,344 @@ var WarpEvmExecutor = class {
709
1053
  } else if (feeData.gasPrice) {
710
1054
  return {
711
1055
  ...tx,
1056
+ chainId: BigInt(this.chain.chainId),
712
1057
  gasLimit: gasEstimate,
713
1058
  gasPrice: feeData.gasPrice
714
1059
  };
715
1060
  } else {
716
1061
  return {
717
1062
  ...tx,
1063
+ chainId: BigInt(this.chain.chainId),
718
1064
  gasLimit: gasEstimate,
719
- gasPrice: import_ethers3.ethers.parseUnits(WarpEvmConstants.GasPrice.Default, "wei")
1065
+ gasPrice: import_ethers4.ethers.parseUnits(WarpEvmConstants.GasPrice.Default, "wei")
720
1066
  };
721
1067
  }
722
1068
  } catch (error) {
723
1069
  let defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.Default);
724
1070
  if (tx.data && tx.data !== "0x") {
725
- defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.ContractCall);
1071
+ if (tx.data.startsWith("0xa9059cbb")) {
1072
+ defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.TokenTransfer);
1073
+ } else {
1074
+ defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.ContractCall);
1075
+ }
726
1076
  } else {
727
1077
  defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.Transfer);
728
1078
  }
729
1079
  return {
730
1080
  ...tx,
1081
+ chainId: BigInt(this.chain.chainId),
731
1082
  gasLimit: defaultGasLimit,
732
- gasPrice: import_ethers3.ethers.parseUnits(WarpEvmConstants.GasPrice.Default, "wei")
1083
+ gasPrice: import_ethers4.ethers.parseUnits(WarpEvmConstants.GasPrice.Default, "wei")
733
1084
  };
734
1085
  }
735
1086
  }
736
1087
  async signMessage(message, privateKey) {
737
- throw new Error("Not implemented");
1088
+ try {
1089
+ const wallet = new import_ethers4.ethers.Wallet(privateKey);
1090
+ const signature = await wallet.signMessage(message);
1091
+ return signature;
1092
+ } catch (error) {
1093
+ throw new Error(`Failed to sign message: ${error}`);
1094
+ }
1095
+ }
1096
+ async verifyMessage(message, signature) {
1097
+ try {
1098
+ const recoveredAddress = import_ethers4.ethers.verifyMessage(message, signature);
1099
+ return recoveredAddress;
1100
+ } catch (error) {
1101
+ throw new Error(`Failed to verify message: ${error}`);
1102
+ }
738
1103
  }
739
1104
  };
740
1105
 
741
1106
  // src/WarpEvmExplorer.ts
742
1107
  var WarpEvmExplorer = class {
743
- constructor(chainInfo, chainName = "ethereum") {
744
- this.chainInfo = chainInfo;
745
- this.chainName = chainName;
1108
+ constructor(chain, config) {
1109
+ this.chain = chain;
1110
+ this.config = config;
1111
+ }
1112
+ getExplorers() {
1113
+ const chainExplorers = EvmExplorers[this.chain.name];
1114
+ if (!chainExplorers) {
1115
+ return ["Default"];
1116
+ }
1117
+ const explorers = chainExplorers[this.config.env];
1118
+ if (!explorers) {
1119
+ return ["Default"];
1120
+ }
1121
+ return explorers;
1122
+ }
1123
+ getPrimaryExplorer() {
1124
+ const explorers = this.getExplorers();
1125
+ return explorers[0];
746
1126
  }
747
- getAccountUrl(address) {
748
- const baseUrl = this.chainInfo.explorerUrl || getEvmExplorerUrl("mainnet", this.chainName);
1127
+ getExplorerUrlByName(explorer) {
1128
+ const userPreference = this.config.preferences?.explorers?.[this.chain.name];
1129
+ if (userPreference && !explorer) {
1130
+ const url2 = ExplorerUrls[userPreference];
1131
+ if (url2) return url2;
1132
+ }
1133
+ if (explorer) {
1134
+ const url2 = ExplorerUrls[explorer];
1135
+ if (url2) return url2;
1136
+ }
1137
+ const primaryExplorer = this.getPrimaryExplorer();
1138
+ const url = ExplorerUrls[primaryExplorer];
1139
+ return url || ExplorerUrls[primaryExplorer];
1140
+ }
1141
+ getAccountUrl(address, explorer) {
1142
+ const baseUrl = this.getExplorerUrlByName(explorer);
749
1143
  return `${baseUrl}/address/${address}`;
750
1144
  }
751
- getTransactionUrl(hash) {
752
- const baseUrl = this.chainInfo.explorerUrl || getEvmExplorerUrl("mainnet", this.chainName);
1145
+ getTransactionUrl(hash, explorer) {
1146
+ const baseUrl = this.getExplorerUrlByName(explorer);
753
1147
  return `${baseUrl}/tx/${hash}`;
754
1148
  }
1149
+ getBlockUrl(blockNumber, explorer) {
1150
+ const baseUrl = this.getExplorerUrlByName(explorer);
1151
+ return `${baseUrl}/block/${blockNumber}`;
1152
+ }
1153
+ getAssetUrl(identifier, explorer) {
1154
+ const baseUrl = this.getExplorerUrlByName(explorer);
1155
+ return `${baseUrl}/token/${identifier}`;
1156
+ }
1157
+ getContractUrl(address, explorer) {
1158
+ const baseUrl = this.getExplorerUrlByName(explorer);
1159
+ return `${baseUrl}/address/${address}`;
1160
+ }
1161
+ getAllExplorers() {
1162
+ return this.getExplorers();
1163
+ }
1164
+ getExplorerByName(name) {
1165
+ const explorers = this.getExplorers();
1166
+ return explorers.find((explorer) => explorer.toLowerCase() === name.toLowerCase());
1167
+ }
1168
+ getAccountUrls(address) {
1169
+ const explorers = this.getAllExplorers();
1170
+ const urls = {};
1171
+ explorers.forEach((explorer) => {
1172
+ const url = ExplorerUrls[explorer];
1173
+ if (url) {
1174
+ urls[explorer] = `${url}/address/${address}`;
1175
+ }
1176
+ });
1177
+ return urls;
1178
+ }
1179
+ getTransactionUrls(hash) {
1180
+ const explorers = this.getAllExplorers();
1181
+ const urls = {};
1182
+ explorers.forEach((explorer) => {
1183
+ const url = ExplorerUrls[explorer];
1184
+ if (url) {
1185
+ urls[explorer] = `${url}/tx/${hash}`;
1186
+ }
1187
+ });
1188
+ return urls;
1189
+ }
1190
+ getAssetUrls(identifier) {
1191
+ const explorers = this.getAllExplorers();
1192
+ const urls = {};
1193
+ explorers.forEach((explorer) => {
1194
+ const url = ExplorerUrls[explorer];
1195
+ if (url) {
1196
+ urls[explorer] = `${url}/token/${identifier}`;
1197
+ }
1198
+ });
1199
+ return urls;
1200
+ }
1201
+ getContractUrls(address) {
1202
+ const explorers = this.getAllExplorers();
1203
+ const urls = {};
1204
+ explorers.forEach((explorer) => {
1205
+ const url = ExplorerUrls[explorer];
1206
+ if (url) {
1207
+ urls[explorer] = `${url}/address/${address}`;
1208
+ }
1209
+ });
1210
+ return urls;
1211
+ }
1212
+ getBlockUrls(blockNumber) {
1213
+ const explorers = this.getAllExplorers();
1214
+ const urls = {};
1215
+ explorers.forEach((explorer) => {
1216
+ const url = ExplorerUrls[explorer];
1217
+ if (url) {
1218
+ urls[explorer] = `${url}/block/${blockNumber}`;
1219
+ }
1220
+ });
1221
+ return urls;
1222
+ }
755
1223
  };
756
1224
 
757
- // src/main.ts
758
- var getEvmAdapter = (config, fallback) => {
759
- if (!fallback) throw new Error("EVM adapter requires a fallback adapter");
760
- return {
761
- chain: WarpEvmConstants.ChainName,
762
- prefix: WarpEvmConstants.ChainPrefix,
763
- builder: () => new WarpEvmBuilder(config),
764
- executor: new WarpEvmExecutor(config),
765
- results: new WarpEvmResults(config),
766
- serializer: new WarpEvmSerializer(),
767
- registry: fallback.registry,
768
- explorer: (chainInfo) => new WarpEvmExplorer(chainInfo),
769
- abiBuilder: () => fallback.abiBuilder(),
770
- brandBuilder: () => fallback.brandBuilder()
1225
+ // src/chains/common.ts
1226
+ var createEvmAdapter = (chainName, chainPrefix, chainInfos) => {
1227
+ return (config, fallback) => {
1228
+ if (!fallback) throw new Error(`${chainName} adapter requires a fallback adapter`);
1229
+ return {
1230
+ chain: chainName,
1231
+ chainInfo: chainInfos[config.env],
1232
+ prefix: chainPrefix,
1233
+ builder: () => fallback.builder(),
1234
+ executor: new WarpEvmExecutor(config, chainInfos[config.env]),
1235
+ results: new WarpEvmResults(config, chainInfos[config.env]),
1236
+ serializer: new WarpEvmSerializer(),
1237
+ registry: fallback.registry,
1238
+ explorer: new WarpEvmExplorer(chainInfos[config.env], config),
1239
+ abiBuilder: () => fallback.abiBuilder(),
1240
+ brandBuilder: () => fallback.brandBuilder(),
1241
+ dataLoader: new WarpEvmDataLoader(config, chainInfos[config.env])
1242
+ };
771
1243
  };
772
1244
  };
1245
+
1246
+ // src/chains/arbitrum.ts
1247
+ var NativeTokenArb = {
1248
+ chain: import_warps5.WarpChainName.Arbitrum,
1249
+ identifier: "ARB",
1250
+ name: "ARB",
1251
+ decimals: 18,
1252
+ logoUrl: "https://vleap.ai/images/tokens/arb.svg"
1253
+ };
1254
+ var getArbitrumAdapter = createEvmAdapter(import_warps5.WarpChainName.Arbitrum, "arb", {
1255
+ mainnet: {
1256
+ name: import_warps5.WarpChainName.Arbitrum,
1257
+ displayName: "Arbitrum",
1258
+ chainId: "42161",
1259
+ blockTime: 1e3,
1260
+ addressHrp: "0x",
1261
+ defaultApiUrl: "https://arb1.arbitrum.io/rpc",
1262
+ nativeToken: NativeTokenArb
1263
+ },
1264
+ testnet: {
1265
+ name: import_warps5.WarpChainName.Arbitrum,
1266
+ displayName: "Arbitrum Sepolia",
1267
+ chainId: "421614",
1268
+ blockTime: 1e3,
1269
+ addressHrp: "0x",
1270
+ defaultApiUrl: "https://sepolia-rollup.arbitrum.io/rpc",
1271
+ nativeToken: NativeTokenArb
1272
+ },
1273
+ devnet: {
1274
+ name: import_warps5.WarpChainName.Arbitrum,
1275
+ displayName: "Arbitrum Sepolia",
1276
+ chainId: "421614",
1277
+ blockTime: 1e3,
1278
+ addressHrp: "0x",
1279
+ defaultApiUrl: "https://sepolia-rollup.arbitrum.io/rpc",
1280
+ nativeToken: NativeTokenArb
1281
+ }
1282
+ });
1283
+
1284
+ // src/chains/base.ts
1285
+ var import_warps6 = require("@vleap/warps");
1286
+ var NativeTokenBase = {
1287
+ chain: import_warps6.WarpChainName.Base,
1288
+ identifier: "ETH",
1289
+ name: "ETH",
1290
+ decimals: 18,
1291
+ logoUrl: "https://vleap.ai/images/tokens/eth.svg"
1292
+ };
1293
+ var getBaseAdapter = createEvmAdapter(import_warps6.WarpChainName.Base, "base", {
1294
+ mainnet: {
1295
+ name: import_warps6.WarpChainName.Base,
1296
+ displayName: "Base",
1297
+ chainId: "8453",
1298
+ blockTime: 2e3,
1299
+ addressHrp: "0x",
1300
+ defaultApiUrl: "https://mainnet.base.org",
1301
+ nativeToken: NativeTokenBase
1302
+ },
1303
+ testnet: {
1304
+ name: import_warps6.WarpChainName.Base,
1305
+ displayName: "Base Sepolia",
1306
+ chainId: "84532",
1307
+ blockTime: 2e3,
1308
+ addressHrp: "0x",
1309
+ defaultApiUrl: "https://sepolia.base.org",
1310
+ nativeToken: NativeTokenBase
1311
+ },
1312
+ devnet: {
1313
+ name: import_warps6.WarpChainName.Base,
1314
+ displayName: "Base Sepolia",
1315
+ chainId: "84532",
1316
+ blockTime: 2e3,
1317
+ addressHrp: "0x",
1318
+ defaultApiUrl: "https://sepolia.base.org",
1319
+ nativeToken: NativeTokenBase
1320
+ }
1321
+ });
1322
+
1323
+ // src/chains/combined.ts
1324
+ var import_warps8 = require("@vleap/warps");
1325
+
1326
+ // src/chains/ethereum.ts
1327
+ var import_warps7 = require("@vleap/warps");
1328
+ var NativeTokenEth = {
1329
+ chain: import_warps7.WarpChainName.Ethereum,
1330
+ identifier: "ETH",
1331
+ name: "ETH",
1332
+ decimals: 18,
1333
+ logoUrl: "https://vleap.ai/images/tokens/eth.svg"
1334
+ };
1335
+ var getEthereumAdapter = createEvmAdapter(import_warps7.WarpChainName.Ethereum, "eth", {
1336
+ mainnet: {
1337
+ name: import_warps7.WarpChainName.Ethereum,
1338
+ displayName: "Ethereum Mainnet",
1339
+ chainId: "1",
1340
+ blockTime: 12e3,
1341
+ addressHrp: "0x",
1342
+ defaultApiUrl: "https://ethereum-rpc.publicnode.com",
1343
+ nativeToken: NativeTokenEth
1344
+ },
1345
+ testnet: {
1346
+ name: import_warps7.WarpChainName.Ethereum,
1347
+ displayName: "Ethereum Sepolia",
1348
+ chainId: "11155111",
1349
+ blockTime: 12e3,
1350
+ addressHrp: "0x",
1351
+ defaultApiUrl: "https://ethereum-sepolia-rpc.publicnode.com",
1352
+ nativeToken: NativeTokenEth
1353
+ },
1354
+ devnet: {
1355
+ name: import_warps7.WarpChainName.Ethereum,
1356
+ displayName: "Ethereum Sepolia",
1357
+ chainId: "11155111",
1358
+ blockTime: 12e3,
1359
+ addressHrp: "0x",
1360
+ defaultApiUrl: "https://ethereum-sepolia-rpc.publicnode.com",
1361
+ nativeToken: NativeTokenEth
1362
+ }
1363
+ });
1364
+
1365
+ // src/chains/combined.ts
1366
+ var getAllEvmAdapters = (config, fallback) => [
1367
+ getEthereumAdapter(config, fallback),
1368
+ getArbitrumAdapter(config, fallback),
1369
+ getBaseAdapter(config, fallback)
1370
+ ];
1371
+ var getAllEvmChainNames = () => [import_warps8.WarpChainName.Ethereum, import_warps8.WarpChainName.Base, import_warps8.WarpChainName.Arbitrum];
773
1372
  // Annotate the CommonJS export names for ESM import in node:
774
1373
  0 && (module.exports = {
775
- EVM_CHAIN_CONFIGS,
776
- WarpEvmBuilder,
1374
+ ArbitrumExplorers,
1375
+ BaseExplorers,
1376
+ EthereumExplorers,
1377
+ EvmExplorers,
1378
+ EvmLogoService,
1379
+ ExplorerUrls,
1380
+ NativeTokenArb,
1381
+ NativeTokenBase,
1382
+ NativeTokenEth,
777
1383
  WarpEvmConstants,
1384
+ WarpEvmDataLoader,
778
1385
  WarpEvmExecutor,
779
1386
  WarpEvmExplorer,
780
1387
  WarpEvmResults,
781
1388
  WarpEvmSerializer,
782
- getEvmAdapter,
783
- getEvmApiUrl,
784
- getEvmBlockTime,
785
- getEvmChainConfig,
786
- getEvmChainId,
787
- getEvmExplorerUrl,
788
- getEvmNativeToken,
789
- getEvmRegistryAddress,
790
- getSupportedEnvironments,
791
- getSupportedEvmChains
1389
+ createEvmAdapter,
1390
+ getAllEvmAdapters,
1391
+ getAllEvmChainNames,
1392
+ getArbitrumAdapter,
1393
+ getBaseAdapter,
1394
+ getEthereumAdapter
792
1395
  });
793
1396
  //# sourceMappingURL=index.js.map