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

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,609 @@ 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 accountReq = this.getAccount(address);
355
+ const tokenBalancesReq = this.getERC20TokenBalances(address);
356
+ const [account, tokenBalances] = await Promise.all([accountReq, tokenBalancesReq]);
357
+ const assets = [];
358
+ if (account.balance > 0n) {
359
+ assets.push({ ...this.chain.nativeToken, amount: account.balance });
360
+ }
361
+ for (const tokenBalance of tokenBalances) {
362
+ if (tokenBalance.balance > 0n) {
363
+ const logoUrl = tokenBalance.metadata.logoUrl || await EvmLogoService.getLogoUrl(
364
+ this.chain.name,
365
+ tokenBalance.tokenAddress,
366
+ tokenBalance.metadata.name,
367
+ tokenBalance.metadata.symbol
368
+ );
369
+ assets.push({
370
+ chain: this.chain.name,
371
+ identifier: tokenBalance.tokenAddress,
372
+ name: tokenBalance.metadata.name,
373
+ amount: tokenBalance.balance,
374
+ decimals: tokenBalance.metadata.decimals,
375
+ logoUrl: logoUrl || ""
376
+ });
377
+ }
378
+ }
379
+ return assets;
380
+ } catch (error) {
381
+ throw new Error(`Failed to get account assets for ${address}: ${error}`);
382
+ }
256
383
  }
257
- addAction(action) {
258
- this.actions.push(action);
259
- return this;
384
+ async getAccountActions(address, options) {
385
+ return [];
260
386
  }
261
- async build() {
262
- if (!this.warp.title) {
263
- throw new Error("Warp title is required");
387
+ async getERC20TokenBalances(address) {
388
+ const tokenBalances = [];
389
+ const knownTokens = KNOWN_TOKENS[this.chain.name] || {};
390
+ for (const [tokenAddress, metadata] of Object.entries(knownTokens)) {
391
+ try {
392
+ const balance = await this.getTokenBalance(address, tokenAddress);
393
+ if (balance > 0n) {
394
+ tokenBalances.push({
395
+ tokenAddress,
396
+ balance,
397
+ metadata
398
+ });
399
+ }
400
+ } catch (error) {
401
+ }
264
402
  }
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()
403
+ const additionalTokens = await this.detectTokensFromEvents(address);
404
+ for (const tokenAddress of additionalTokens) {
405
+ if (!knownTokens[tokenAddress]) {
406
+ try {
407
+ const metadata = await this.getTokenMetadata(tokenAddress);
408
+ const balance = await this.getTokenBalance(address, tokenAddress);
409
+ if (balance > 0n) {
410
+ tokenBalances.push({
411
+ tokenAddress,
412
+ balance,
413
+ metadata
414
+ });
415
+ }
416
+ } catch (error) {
417
+ }
277
418
  }
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
- };
419
+ }
420
+ return tokenBalances;
286
421
  }
287
- async createFromTransaction(tx, validate) {
288
- if (!tx.data || tx.data === "0x") {
289
- throw new Error("Transaction has no data");
422
+ async getTokenBalance(address, tokenAddress) {
423
+ try {
424
+ const contract = new import_ethers.ethers.Contract(tokenAddress, ERC20_ABI, this.provider);
425
+ const balance = await contract.balanceOf(address);
426
+ return balance;
427
+ } catch (error) {
428
+ throw new Error(`Failed to get token balance: ${error}`);
290
429
  }
430
+ }
431
+ async getTokenMetadata(tokenAddress) {
291
432
  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
- }
433
+ const tokenInfo = await EvmLogoService.getTokenInfo(this.chain.name, tokenAddress);
434
+ if (tokenInfo.name && tokenInfo.symbol && tokenInfo.decimals !== void 0) {
435
+ return {
436
+ name: tokenInfo.name,
437
+ symbol: tokenInfo.symbol,
438
+ decimals: tokenInfo.decimals,
439
+ logoUrl: tokenInfo.logoURI
440
+ };
301
441
  }
302
- return warp;
442
+ const contract = new import_ethers.ethers.Contract(tokenAddress, ERC20_ABI, this.provider);
443
+ const [name, symbol, decimals] = await Promise.all([
444
+ contract.name().catch(() => tokenInfo.name || "Unknown Token"),
445
+ contract.symbol().catch(() => tokenInfo.symbol || "UNKNOWN"),
446
+ contract.decimals().catch(() => tokenInfo.decimals || 18)
447
+ ]);
448
+ return {
449
+ name: name || tokenInfo.name || "Unknown Token",
450
+ symbol: symbol || tokenInfo.symbol || "UNKNOWN",
451
+ decimals: decimals || tokenInfo.decimals || 18,
452
+ logoUrl: tokenInfo.logoURI
453
+ };
303
454
  } catch (error) {
304
- throw new Error(`Failed to create warp from transaction: ${error}`);
455
+ throw new Error(`Failed to get token metadata: ${error}`);
305
456
  }
306
457
  }
307
- async createFromTransactionHash(hash, cache) {
458
+ async detectTokensFromEvents(address) {
308
459
  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;
460
+ const currentBlock = await this.provider.getBlockNumber();
461
+ const fromBlock = Math.max(0, currentBlock - 1e4);
462
+ const filter = {
463
+ fromBlock,
464
+ toBlock: currentBlock,
465
+ topics: [
466
+ import_ethers.ethers.id("Transfer(address,address,uint256)"),
467
+ null,
468
+ // from address (any)
469
+ import_ethers.ethers.zeroPadValue(address, 32)
470
+ // to address (our target)
471
+ ]
472
+ };
473
+ const logs = await this.provider.getLogs(filter);
474
+ const tokenAddresses = /* @__PURE__ */ new Set();
475
+ for (const log of logs) {
476
+ tokenAddresses.add(log.address);
313
477
  }
314
- return await this.createFromTransaction(tx);
478
+ return Array.from(tokenAddresses);
479
+ } catch (error) {
480
+ return [];
481
+ }
482
+ }
483
+ // Additional utility methods for enhanced token support
484
+ async getTokenInfo(tokenAddress) {
485
+ try {
486
+ return await this.getTokenMetadata(tokenAddress);
315
487
  } catch (error) {
316
488
  return null;
317
489
  }
318
490
  }
491
+ async getTokenBalanceForAddress(address, tokenAddress) {
492
+ try {
493
+ return await this.getTokenBalance(address, tokenAddress);
494
+ } catch (error) {
495
+ throw new Error(`Failed to get token balance for ${tokenAddress}: ${error}`);
496
+ }
497
+ }
498
+ async getMultipleTokenBalances(address, tokenAddresses) {
499
+ const balances = /* @__PURE__ */ new Map();
500
+ await Promise.all(
501
+ tokenAddresses.map(async (tokenAddress) => {
502
+ try {
503
+ const balance = await this.getTokenBalance(address, tokenAddress);
504
+ balances.set(tokenAddress, balance);
505
+ } catch (error) {
506
+ balances.set(tokenAddress, 0n);
507
+ }
508
+ })
509
+ );
510
+ return balances;
511
+ }
512
+ async getAccountTokens(address) {
513
+ return this.getAccountAssets(address);
514
+ }
515
+ async getTokenMetadataPublic(tokenAddress) {
516
+ try {
517
+ return await this.getTokenMetadata(tokenAddress);
518
+ } catch (error) {
519
+ return null;
520
+ }
521
+ }
522
+ async getChainInfo() {
523
+ try {
524
+ const network = await this.provider.getNetwork();
525
+ const latestBlock = await this.provider.getBlock("latest");
526
+ return {
527
+ chainId: network.chainId.toString(),
528
+ blockTime: latestBlock?.timestamp ? Date.now() / 1e3 - latestBlock.timestamp : 12
529
+ };
530
+ } catch (error) {
531
+ throw new Error(`Failed to get chain info: ${error}`);
532
+ }
533
+ }
319
534
  };
320
535
 
321
536
  // src/WarpEvmExecutor.ts
322
- var import_warps3 = require("@vleap/warps");
323
- var import_ethers3 = require("ethers");
537
+ var import_warps4 = require("@vleap/warps");
538
+ var import_ethers4 = require("ethers");
539
+
540
+ // src/constants.ts
541
+ var WarpEvmConstants = {
542
+ GasLimit: {
543
+ Default: 21e3,
544
+ ContractCall: 1e5,
545
+ ContractDeploy: 5e5,
546
+ Transfer: 21e3,
547
+ TokenTransfer: 65e3,
548
+ // ERC-20 transfer gas limit
549
+ Approve: 46e3,
550
+ Swap: 2e5
551
+ },
552
+ GasPrice: {
553
+ Default: "20000000000"
554
+ },
555
+ Validation: {
556
+ MinGasLimit: 21e3,
557
+ MaxGasLimit: 3e7
558
+ }
559
+ };
560
+ var EthereumExplorers = /* @__PURE__ */ ((EthereumExplorers2) => {
561
+ EthereumExplorers2["Etherscan"] = "etherscan";
562
+ EthereumExplorers2["EtherscanSepolia"] = "etherscan_sepolia";
563
+ EthereumExplorers2["Ethplorer"] = "ethplorer";
564
+ EthereumExplorers2["Blockscout"] = "blockscout";
565
+ EthereumExplorers2["BlockscoutSepolia"] = "blockscout_sepolia";
566
+ return EthereumExplorers2;
567
+ })(EthereumExplorers || {});
568
+ var ArbitrumExplorers = /* @__PURE__ */ ((ArbitrumExplorers2) => {
569
+ ArbitrumExplorers2["Arbiscan"] = "arbiscan";
570
+ ArbitrumExplorers2["ArbiscanSepolia"] = "arbiscan_sepolia";
571
+ ArbitrumExplorers2["BlockscoutArbitrum"] = "blockscout_arbitrum";
572
+ ArbitrumExplorers2["BlockscoutArbitrumSepolia"] = "blockscout_arbitrum_sepolia";
573
+ return ArbitrumExplorers2;
574
+ })(ArbitrumExplorers || {});
575
+ var BaseExplorers = /* @__PURE__ */ ((BaseExplorers2) => {
576
+ BaseExplorers2["Basescan"] = "basescan";
577
+ BaseExplorers2["BasescanSepolia"] = "basescan_sepolia";
578
+ BaseExplorers2["BlockscoutBase"] = "blockscout_base";
579
+ BaseExplorers2["BlockscoutBaseSepolia"] = "blockscout_base_sepolia";
580
+ return BaseExplorers2;
581
+ })(BaseExplorers || {});
582
+ var EvmExplorers = {
583
+ ethereum: {
584
+ mainnet: ["etherscan" /* Etherscan */, "ethplorer" /* Ethplorer */, "blockscout" /* Blockscout */],
585
+ testnet: ["etherscan_sepolia" /* EtherscanSepolia */, "blockscout_sepolia" /* BlockscoutSepolia */],
586
+ devnet: ["etherscan_sepolia" /* EtherscanSepolia */, "blockscout_sepolia" /* BlockscoutSepolia */]
587
+ },
588
+ arbitrum: {
589
+ mainnet: ["arbiscan" /* Arbiscan */, "blockscout_arbitrum" /* BlockscoutArbitrum */],
590
+ testnet: ["arbiscan_sepolia" /* ArbiscanSepolia */, "blockscout_arbitrum_sepolia" /* BlockscoutArbitrumSepolia */],
591
+ devnet: ["arbiscan_sepolia" /* ArbiscanSepolia */, "blockscout_arbitrum_sepolia" /* BlockscoutArbitrumSepolia */]
592
+ },
593
+ base: {
594
+ mainnet: ["basescan" /* Basescan */, "blockscout_base" /* BlockscoutBase */],
595
+ testnet: ["basescan_sepolia" /* BasescanSepolia */, "blockscout_base_sepolia" /* BlockscoutBaseSepolia */],
596
+ devnet: ["basescan_sepolia" /* BasescanSepolia */, "blockscout_base_sepolia" /* BlockscoutBaseSepolia */]
597
+ }
598
+ };
599
+ var ExplorerUrls = {
600
+ ["etherscan" /* Etherscan */]: "https://etherscan.io",
601
+ ["etherscan_sepolia" /* EtherscanSepolia */]: "https://sepolia.etherscan.io",
602
+ ["ethplorer" /* Ethplorer */]: "https://ethplorer.io",
603
+ ["blockscout" /* Blockscout */]: "https://eth.blockscout.com",
604
+ ["blockscout_sepolia" /* BlockscoutSepolia */]: "https://sepolia.blockscout.com",
605
+ ["arbiscan" /* Arbiscan */]: "https://arbiscan.io",
606
+ ["arbiscan_sepolia" /* ArbiscanSepolia */]: "https://sepolia.arbiscan.io",
607
+ ["blockscout_arbitrum" /* BlockscoutArbitrum */]: "https://arbitrum.blockscout.com",
608
+ ["blockscout_arbitrum_sepolia" /* BlockscoutArbitrumSepolia */]: "https://sepolia.blockscout.com",
609
+ ["basescan" /* Basescan */]: "https://basescan.org",
610
+ ["basescan_sepolia" /* BasescanSepolia */]: "https://sepolia.basescan.org",
611
+ ["blockscout_base" /* BlockscoutBase */]: "https://base.blockscout.com",
612
+ ["blockscout_base_sepolia" /* BlockscoutBaseSepolia */]: "https://sepolia.blockscout.com"
613
+ };
324
614
 
325
615
  // src/WarpEvmResults.ts
326
- var import_warps2 = require("@vleap/warps");
616
+ var import_warps3 = require("@vleap/warps");
617
+ var import_ethers3 = require("ethers");
327
618
 
328
619
  // src/WarpEvmSerializer.ts
329
- var import_warps = require("@vleap/warps");
620
+ var import_warps2 = require("@vleap/warps");
330
621
  var import_ethers2 = require("ethers");
331
- var SplitParamsRegex = new RegExp(`${import_warps.WarpConstants.ArgParamsSeparator}(.*)`);
622
+ var SplitParamsRegex = new RegExp(`${import_warps2.WarpConstants.ArgParamsSeparator}(.*)`);
332
623
  var WarpEvmSerializer = class {
333
624
  constructor() {
334
- this.coreSerializer = new import_warps.WarpSerializer();
625
+ this.coreSerializer = new import_warps2.WarpSerializer();
335
626
  }
336
627
  typedToString(value) {
337
628
  if (typeof value === "string") {
@@ -360,9 +651,9 @@ var WarpEvmSerializer = class {
360
651
  }
361
652
  if (Array.isArray(value)) {
362
653
  if (value.length === 0) return `list:string:`;
363
- const types = value.map((item) => this.typedToString(item).split(import_warps.WarpConstants.ArgParamsSeparator)[0]);
654
+ const types = value.map((item) => this.typedToString(item).split(import_warps2.WarpConstants.ArgParamsSeparator)[0]);
364
655
  const type = types[0];
365
- const values = value.map((item) => this.typedToString(item).split(import_warps.WarpConstants.ArgParamsSeparator)[1]);
656
+ const values = value.map((item) => this.typedToString(item).split(import_warps2.WarpConstants.ArgParamsSeparator)[1]);
366
657
  return `list:${type}:${values.join(",")}`;
367
658
  }
368
659
  if (value === null || value === void 0) {
@@ -372,8 +663,8 @@ var WarpEvmSerializer = class {
372
663
  }
373
664
  typedToNative(value) {
374
665
  const stringValue = this.typedToString(value);
375
- const [type, ...valueParts] = stringValue.split(import_warps.WarpConstants.ArgParamsSeparator);
376
- const nativeValue = valueParts.join(import_warps.WarpConstants.ArgParamsSeparator);
666
+ const [type, ...valueParts] = stringValue.split(import_warps2.WarpConstants.ArgParamsSeparator);
667
+ const nativeValue = valueParts.join(import_warps2.WarpConstants.ArgParamsSeparator);
377
668
  return [type, this.parseNativeValue(type, nativeValue)];
378
669
  }
379
670
  nativeToTyped(type, value) {
@@ -424,7 +715,7 @@ var WarpEvmSerializer = class {
424
715
  }
425
716
  }
426
717
  stringToTyped(value) {
427
- const parts = value.split(import_warps.WarpConstants.ArgParamsSeparator, 2);
718
+ const parts = value.split(import_warps2.WarpConstants.ArgParamsSeparator, 2);
428
719
  if (parts.length < 2) {
429
720
  return value;
430
721
  }
@@ -479,9 +770,19 @@ var WarpEvmSerializer = class {
479
770
 
480
771
  // src/WarpEvmResults.ts
481
772
  var WarpEvmResults = class {
482
- constructor(config) {
773
+ constructor(config, chain) {
483
774
  this.config = config;
775
+ this.chain = chain;
484
776
  this.serializer = new WarpEvmSerializer();
777
+ if (this.chain) {
778
+ const apiUrl = (0, import_warps3.getProviderUrl)(this.config, this.chain.name, this.config.env, this.chain.defaultApiUrl);
779
+ const network = new import_ethers3.ethers.Network(this.chain.name, parseInt(this.chain.chainId));
780
+ this.provider = new import_ethers3.ethers.JsonRpcProvider(apiUrl, network);
781
+ } else {
782
+ const apiUrl = (0, import_warps3.getProviderUrl)(this.config, "ethereum", this.config.env, "https://ethereum-rpc.publicnode.com");
783
+ const network = new import_ethers3.ethers.Network("ethereum", 1);
784
+ this.provider = new import_ethers3.ethers.JsonRpcProvider(apiUrl, network);
785
+ }
485
786
  }
486
787
  async getTransactionExecutionResults(warp, tx) {
487
788
  const success = tx.status === 1;
@@ -503,8 +804,10 @@ var WarpEvmResults = class {
503
804
  action: 0,
504
805
  user: this.config.user?.wallets?.evm || null,
505
806
  txHash: transactionHash,
807
+ tx,
506
808
  next: null,
507
809
  values: [transactionHash, blockNumber, gasUsed, gasPrice, ...logs.length > 0 ? logs : []],
810
+ valuesRaw: [transactionHash, blockNumber, gasUsed, gasPrice, ...logs.length > 0 ? logs : []],
508
811
  results: {},
509
812
  messages: {}
510
813
  };
@@ -513,7 +816,7 @@ var WarpEvmResults = class {
513
816
  const values = typedValues.map((t) => this.serializer.typedToString(t));
514
817
  const valuesRaw = typedValues.map((t) => this.serializer.typedToNative(t)[1]);
515
818
  let results = {};
516
- if (!warp.results) return { values, results };
819
+ if (!warp.results) return { values, valuesRaw, results };
517
820
  const getNestedValue = (path) => {
518
821
  const indices = path.split(".").slice(1).map((i) => parseInt(i) - 1);
519
822
  if (indices.length === 0) return void 0;
@@ -525,8 +828,8 @@ var WarpEvmResults = class {
525
828
  return value;
526
829
  };
527
830
  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);
831
+ if (path.startsWith(import_warps3.WarpConstants.Transform.Prefix)) continue;
832
+ const currentActionIndex = (0, import_warps3.parseResultsOutIndex)(path);
530
833
  if (currentActionIndex !== null && currentActionIndex !== actionIndex) {
531
834
  results[key] = null;
532
835
  continue;
@@ -537,20 +840,45 @@ var WarpEvmResults = class {
537
840
  results[key] = path;
538
841
  }
539
842
  }
540
- return { values, results: await (0, import_warps2.evaluateResultsCommon)(warp, results, actionIndex, inputs) };
843
+ return { values, valuesRaw, results: await (0, import_warps3.evaluateResultsCommon)(warp, results, actionIndex, inputs) };
844
+ }
845
+ async getTransactionStatus(txHash) {
846
+ try {
847
+ const receipt = await this.provider.getTransactionReceipt(txHash);
848
+ if (!receipt) {
849
+ return { status: "pending" };
850
+ }
851
+ return {
852
+ status: receipt.status === 1 ? "confirmed" : "failed",
853
+ blockNumber: receipt.blockNumber,
854
+ gasUsed: receipt.gasUsed
855
+ };
856
+ } catch (error) {
857
+ throw new Error(`Failed to get transaction status: ${error}`);
858
+ }
859
+ }
860
+ async getTransactionReceipt(txHash) {
861
+ try {
862
+ return await this.provider.getTransactionReceipt(txHash);
863
+ } catch (error) {
864
+ return null;
865
+ }
541
866
  }
542
867
  };
543
868
 
544
869
  // src/WarpEvmExecutor.ts
545
870
  var WarpEvmExecutor = class {
546
- constructor(config) {
871
+ constructor(config, chain) {
547
872
  this.config = config;
873
+ this.chain = chain;
548
874
  this.serializer = new WarpEvmSerializer();
549
- this.provider = new import_ethers3.ethers.JsonRpcProvider(getEvmApiUrl(config.env));
550
- this.results = new WarpEvmResults(config);
875
+ const apiUrl = (0, import_warps4.getProviderUrl)(this.config, chain.name, this.config.env, this.chain.defaultApiUrl);
876
+ const network = new import_ethers4.ethers.Network(this.chain.name, parseInt(this.chain.chainId));
877
+ this.provider = new import_ethers4.ethers.JsonRpcProvider(apiUrl, network);
878
+ this.results = new WarpEvmResults(config, this.chain);
551
879
  }
552
880
  async createTransaction(executable) {
553
- const action = (0, import_warps3.getWarpActionByIndex)(executable.warp, executable.action);
881
+ const action = (0, import_warps4.getWarpActionByIndex)(executable.warp, executable.action);
554
882
  let tx = null;
555
883
  if (action.type === "transfer") {
556
884
  tx = await this.createTransferTransaction(executable);
@@ -567,11 +895,11 @@ var WarpEvmExecutor = class {
567
895
  async createTransferTransaction(executable) {
568
896
  const userWallet = this.config.user?.wallets?.[executable.chain.name];
569
897
  if (!userWallet) throw new Error("WarpEvmExecutor: createTransfer - user address not set");
570
- if (!import_ethers3.ethers.isAddress(executable.destination)) {
898
+ if (!import_ethers4.ethers.isAddress(executable.destination)) {
571
899
  throw new Error(`WarpEvmExecutor: Invalid destination address: ${executable.destination}`);
572
900
  }
573
- if (executable.value < 0) {
574
- throw new Error(`WarpEvmExecutor: Transfer value cannot be negative: ${executable.value}`);
901
+ if (executable.transfers && executable.transfers.length > 0) {
902
+ return this.createTokenTransferTransaction(executable, userWallet);
575
903
  }
576
904
  const tx = {
577
905
  to: executable.destination,
@@ -583,18 +911,15 @@ var WarpEvmExecutor = class {
583
911
  async createContractCallTransaction(executable) {
584
912
  const userWallet = this.config.user?.wallets?.[executable.chain.name];
585
913
  if (!userWallet) throw new Error("WarpEvmExecutor: createContractCall - user address not set");
586
- const action = (0, import_warps3.getWarpActionByIndex)(executable.warp, executable.action);
914
+ const action = (0, import_warps4.getWarpActionByIndex)(executable.warp, executable.action);
587
915
  if (!action || !("func" in action) || !action.func) {
588
916
  throw new Error("WarpEvmExecutor: Contract action must have a function name");
589
917
  }
590
- if (!import_ethers3.ethers.isAddress(executable.destination)) {
918
+ if (!import_ethers4.ethers.isAddress(executable.destination)) {
591
919
  throw new Error(`WarpEvmExecutor: Invalid contract address: ${executable.destination}`);
592
920
  }
593
- if (executable.value < 0) {
594
- throw new Error(`WarpEvmExecutor: Contract call value cannot be negative: ${executable.value}`);
595
- }
596
921
  try {
597
- const iface = new import_ethers3.ethers.Interface([`function ${action.func}`]);
922
+ const iface = new import_ethers4.ethers.Interface([`function ${action.func}`]);
598
923
  const encodedData = iface.encodeFunctionData(action.func, executable.args);
599
924
  const tx = {
600
925
  to: executable.destination,
@@ -606,19 +931,63 @@ var WarpEvmExecutor = class {
606
931
  throw new Error(`WarpEvmExecutor: Failed to encode function data for ${action.func}: ${error}`);
607
932
  }
608
933
  }
934
+ async createTokenTransferTransaction(executable, userWallet) {
935
+ if (executable.transfers.length === 0) {
936
+ throw new Error("WarpEvmExecutor: No transfers provided");
937
+ }
938
+ if (!this.chain.nativeToken?.identifier) {
939
+ throw new Error("WarpEvmExecutor: No native token defined for this chain");
940
+ }
941
+ const nativeTokenTransfers = executable.transfers.filter((transfer) => transfer.identifier === this.chain.nativeToken.identifier);
942
+ const erc20Transfers = executable.transfers.filter((transfer) => transfer.identifier !== this.chain.nativeToken.identifier);
943
+ if (nativeTokenTransfers.length === 1 && erc20Transfers.length === 0) {
944
+ const transfer = nativeTokenTransfers[0];
945
+ if (transfer.amount <= 0n) {
946
+ throw new Error("WarpEvmExecutor: Native token transfer amount must be positive");
947
+ }
948
+ const tx = {
949
+ to: executable.destination,
950
+ value: transfer.amount,
951
+ data: "0x"
952
+ };
953
+ return this.estimateGasAndSetDefaults(tx, userWallet);
954
+ }
955
+ if (nativeTokenTransfers.length === 0 && erc20Transfers.length === 1) {
956
+ return this.createSingleTokenTransfer(executable, erc20Transfers[0], userWallet);
957
+ }
958
+ if (executable.transfers.length > 1) {
959
+ throw new Error("WarpEvmExecutor: Multiple token transfers not yet supported");
960
+ }
961
+ throw new Error("WarpEvmExecutor: Invalid transfer configuration");
962
+ }
963
+ async createSingleTokenTransfer(executable, transfer, userWallet) {
964
+ if (!import_ethers4.ethers.isAddress(transfer.identifier)) {
965
+ throw new Error(`WarpEvmExecutor: Invalid token address: ${transfer.identifier}`);
966
+ }
967
+ const transferInterface = new import_ethers4.ethers.Interface(["function transfer(address to, uint256 amount) returns (bool)"]);
968
+ const encodedData = transferInterface.encodeFunctionData("transfer", [executable.destination, transfer.amount]);
969
+ const tx = {
970
+ to: transfer.identifier,
971
+ // Token contract address
972
+ value: 0n,
973
+ // No native token value for ERC-20 transfers
974
+ data: encodedData
975
+ };
976
+ return this.estimateGasAndSetDefaults(tx, userWallet);
977
+ }
609
978
  async executeQuery(executable) {
610
- const action = (0, import_warps3.getWarpActionByIndex)(executable.warp, executable.action);
979
+ const action = (0, import_warps4.getWarpActionByIndex)(executable.warp, executable.action);
611
980
  if (action.type !== "query") {
612
981
  throw new Error(`WarpEvmExecutor: Invalid action type for executeQuery: ${action.type}`);
613
982
  }
614
983
  if (!action.func) {
615
984
  throw new Error("WarpEvmExecutor: Query action must have a function name");
616
985
  }
617
- if (!import_ethers3.ethers.isAddress(executable.destination)) {
986
+ if (!import_ethers4.ethers.isAddress(executable.destination)) {
618
987
  throw new Error(`WarpEvmExecutor: Invalid contract address for query: ${executable.destination}`);
619
988
  }
620
989
  try {
621
- const iface = new import_ethers3.ethers.Interface([`function ${action.func}`]);
990
+ const iface = new import_ethers4.ethers.Interface([`function ${action.func}`]);
622
991
  const encodedData = iface.encodeFunctionData(action.func, executable.args);
623
992
  const result = await this.provider.call({
624
993
  to: executable.destination,
@@ -626,24 +995,25 @@ var WarpEvmExecutor = class {
626
995
  });
627
996
  const decodedResult = iface.decodeFunctionResult(action.func, result);
628
997
  const isSuccess = true;
629
- const { values, results } = await this.results.extractQueryResults(
998
+ const { values, valuesRaw, results } = await this.results.extractQueryResults(
630
999
  executable.warp,
631
1000
  decodedResult,
632
1001
  executable.action,
633
1002
  executable.resolvedInputs
634
1003
  );
635
- const adapter = getEvmAdapter(this.config);
636
- const next = (0, import_warps3.getNextInfo)(this.config, adapter, executable.warp, executable.action, results);
1004
+ const next = (0, import_warps4.getNextInfo)(this.config, [], executable.warp, executable.action, results);
637
1005
  return {
638
1006
  success: isSuccess,
639
1007
  warp: executable.warp,
640
1008
  action: executable.action,
641
1009
  user: this.config.user?.wallets?.[executable.chain.name] || null,
642
1010
  txHash: null,
1011
+ tx: null,
643
1012
  next,
644
1013
  values,
1014
+ valuesRaw,
645
1015
  results,
646
- messages: (0, import_warps3.applyResultsToMessages)(executable.warp, results)
1016
+ messages: (0, import_warps4.applyResultsToMessages)(executable.warp, results)
647
1017
  };
648
1018
  } catch (error) {
649
1019
  return {
@@ -652,39 +1022,17 @@ var WarpEvmExecutor = class {
652
1022
  action: executable.action,
653
1023
  user: this.config.user?.wallets?.[executable.chain.name] || null,
654
1024
  txHash: null,
1025
+ tx: null,
655
1026
  next: null,
656
1027
  values: [],
1028
+ valuesRaw: [],
657
1029
  results: {},
658
1030
  messages: {}
659
1031
  };
660
1032
  }
661
1033
  }
662
1034
  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
- }
1035
+ return input;
688
1036
  }
689
1037
  async estimateGasAndSetDefaults(tx, from) {
690
1038
  try {
@@ -702,6 +1050,7 @@ var WarpEvmExecutor = class {
702
1050
  if (feeData.maxFeePerGas && feeData.maxPriorityFeePerGas) {
703
1051
  return {
704
1052
  ...tx,
1053
+ chainId: BigInt(this.chain.chainId),
705
1054
  gasLimit: gasEstimate,
706
1055
  maxFeePerGas: feeData.maxFeePerGas,
707
1056
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
@@ -709,85 +1058,344 @@ var WarpEvmExecutor = class {
709
1058
  } else if (feeData.gasPrice) {
710
1059
  return {
711
1060
  ...tx,
1061
+ chainId: BigInt(this.chain.chainId),
712
1062
  gasLimit: gasEstimate,
713
1063
  gasPrice: feeData.gasPrice
714
1064
  };
715
1065
  } else {
716
1066
  return {
717
1067
  ...tx,
1068
+ chainId: BigInt(this.chain.chainId),
718
1069
  gasLimit: gasEstimate,
719
- gasPrice: import_ethers3.ethers.parseUnits(WarpEvmConstants.GasPrice.Default, "wei")
1070
+ gasPrice: import_ethers4.ethers.parseUnits(WarpEvmConstants.GasPrice.Default, "wei")
720
1071
  };
721
1072
  }
722
1073
  } catch (error) {
723
1074
  let defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.Default);
724
1075
  if (tx.data && tx.data !== "0x") {
725
- defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.ContractCall);
1076
+ if (tx.data.startsWith("0xa9059cbb")) {
1077
+ defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.TokenTransfer);
1078
+ } else {
1079
+ defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.ContractCall);
1080
+ }
726
1081
  } else {
727
1082
  defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.Transfer);
728
1083
  }
729
1084
  return {
730
1085
  ...tx,
1086
+ chainId: BigInt(this.chain.chainId),
731
1087
  gasLimit: defaultGasLimit,
732
- gasPrice: import_ethers3.ethers.parseUnits(WarpEvmConstants.GasPrice.Default, "wei")
1088
+ gasPrice: import_ethers4.ethers.parseUnits(WarpEvmConstants.GasPrice.Default, "wei")
733
1089
  };
734
1090
  }
735
1091
  }
736
1092
  async signMessage(message, privateKey) {
737
- throw new Error("Not implemented");
1093
+ try {
1094
+ const wallet = new import_ethers4.ethers.Wallet(privateKey);
1095
+ const signature = await wallet.signMessage(message);
1096
+ return signature;
1097
+ } catch (error) {
1098
+ throw new Error(`Failed to sign message: ${error}`);
1099
+ }
1100
+ }
1101
+ async verifyMessage(message, signature) {
1102
+ try {
1103
+ const recoveredAddress = import_ethers4.ethers.verifyMessage(message, signature);
1104
+ return recoveredAddress;
1105
+ } catch (error) {
1106
+ throw new Error(`Failed to verify message: ${error}`);
1107
+ }
738
1108
  }
739
1109
  };
740
1110
 
741
1111
  // src/WarpEvmExplorer.ts
742
1112
  var WarpEvmExplorer = class {
743
- constructor(chainInfo, chainName = "ethereum") {
744
- this.chainInfo = chainInfo;
745
- this.chainName = chainName;
1113
+ constructor(chain, config) {
1114
+ this.chain = chain;
1115
+ this.config = config;
1116
+ }
1117
+ getExplorers() {
1118
+ const chainExplorers = EvmExplorers[this.chain.name];
1119
+ if (!chainExplorers) {
1120
+ return ["Default"];
1121
+ }
1122
+ const explorers = chainExplorers[this.config.env];
1123
+ if (!explorers) {
1124
+ return ["Default"];
1125
+ }
1126
+ return explorers;
1127
+ }
1128
+ getPrimaryExplorer() {
1129
+ const explorers = this.getExplorers();
1130
+ return explorers[0];
746
1131
  }
747
- getAccountUrl(address) {
748
- const baseUrl = this.chainInfo.explorerUrl || getEvmExplorerUrl("mainnet", this.chainName);
1132
+ getExplorerUrlByName(explorer) {
1133
+ const userPreference = this.config.preferences?.explorers?.[this.chain.name];
1134
+ if (userPreference && !explorer) {
1135
+ const url2 = ExplorerUrls[userPreference];
1136
+ if (url2) return url2;
1137
+ }
1138
+ if (explorer) {
1139
+ const url2 = ExplorerUrls[explorer];
1140
+ if (url2) return url2;
1141
+ }
1142
+ const primaryExplorer = this.getPrimaryExplorer();
1143
+ const url = ExplorerUrls[primaryExplorer];
1144
+ return url || ExplorerUrls[primaryExplorer];
1145
+ }
1146
+ getAccountUrl(address, explorer) {
1147
+ const baseUrl = this.getExplorerUrlByName(explorer);
749
1148
  return `${baseUrl}/address/${address}`;
750
1149
  }
751
- getTransactionUrl(hash) {
752
- const baseUrl = this.chainInfo.explorerUrl || getEvmExplorerUrl("mainnet", this.chainName);
1150
+ getTransactionUrl(hash, explorer) {
1151
+ const baseUrl = this.getExplorerUrlByName(explorer);
753
1152
  return `${baseUrl}/tx/${hash}`;
754
1153
  }
1154
+ getBlockUrl(blockNumber, explorer) {
1155
+ const baseUrl = this.getExplorerUrlByName(explorer);
1156
+ return `${baseUrl}/block/${blockNumber}`;
1157
+ }
1158
+ getAssetUrl(identifier, explorer) {
1159
+ const baseUrl = this.getExplorerUrlByName(explorer);
1160
+ return `${baseUrl}/token/${identifier}`;
1161
+ }
1162
+ getContractUrl(address, explorer) {
1163
+ const baseUrl = this.getExplorerUrlByName(explorer);
1164
+ return `${baseUrl}/address/${address}`;
1165
+ }
1166
+ getAllExplorers() {
1167
+ return this.getExplorers();
1168
+ }
1169
+ getExplorerByName(name) {
1170
+ const explorers = this.getExplorers();
1171
+ return explorers.find((explorer) => explorer.toLowerCase() === name.toLowerCase());
1172
+ }
1173
+ getAccountUrls(address) {
1174
+ const explorers = this.getAllExplorers();
1175
+ const urls = {};
1176
+ explorers.forEach((explorer) => {
1177
+ const url = ExplorerUrls[explorer];
1178
+ if (url) {
1179
+ urls[explorer] = `${url}/address/${address}`;
1180
+ }
1181
+ });
1182
+ return urls;
1183
+ }
1184
+ getTransactionUrls(hash) {
1185
+ const explorers = this.getAllExplorers();
1186
+ const urls = {};
1187
+ explorers.forEach((explorer) => {
1188
+ const url = ExplorerUrls[explorer];
1189
+ if (url) {
1190
+ urls[explorer] = `${url}/tx/${hash}`;
1191
+ }
1192
+ });
1193
+ return urls;
1194
+ }
1195
+ getAssetUrls(identifier) {
1196
+ const explorers = this.getAllExplorers();
1197
+ const urls = {};
1198
+ explorers.forEach((explorer) => {
1199
+ const url = ExplorerUrls[explorer];
1200
+ if (url) {
1201
+ urls[explorer] = `${url}/token/${identifier}`;
1202
+ }
1203
+ });
1204
+ return urls;
1205
+ }
1206
+ getContractUrls(address) {
1207
+ const explorers = this.getAllExplorers();
1208
+ const urls = {};
1209
+ explorers.forEach((explorer) => {
1210
+ const url = ExplorerUrls[explorer];
1211
+ if (url) {
1212
+ urls[explorer] = `${url}/address/${address}`;
1213
+ }
1214
+ });
1215
+ return urls;
1216
+ }
1217
+ getBlockUrls(blockNumber) {
1218
+ const explorers = this.getAllExplorers();
1219
+ const urls = {};
1220
+ explorers.forEach((explorer) => {
1221
+ const url = ExplorerUrls[explorer];
1222
+ if (url) {
1223
+ urls[explorer] = `${url}/block/${blockNumber}`;
1224
+ }
1225
+ });
1226
+ return urls;
1227
+ }
755
1228
  };
756
1229
 
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()
1230
+ // src/chains/common.ts
1231
+ var createEvmAdapter = (chainName, chainPrefix, chainInfos) => {
1232
+ return (config, fallback) => {
1233
+ if (!fallback) throw new Error(`${chainName} adapter requires a fallback adapter`);
1234
+ return {
1235
+ chain: chainName,
1236
+ chainInfo: chainInfos[config.env],
1237
+ prefix: chainPrefix,
1238
+ builder: () => fallback.builder(),
1239
+ executor: new WarpEvmExecutor(config, chainInfos[config.env]),
1240
+ results: new WarpEvmResults(config, chainInfos[config.env]),
1241
+ serializer: new WarpEvmSerializer(),
1242
+ registry: fallback.registry,
1243
+ explorer: new WarpEvmExplorer(chainInfos[config.env], config),
1244
+ abiBuilder: () => fallback.abiBuilder(),
1245
+ brandBuilder: () => fallback.brandBuilder(),
1246
+ dataLoader: new WarpEvmDataLoader(config, chainInfos[config.env])
1247
+ };
771
1248
  };
772
1249
  };
1250
+
1251
+ // src/chains/arbitrum.ts
1252
+ var NativeTokenArb = {
1253
+ chain: import_warps5.WarpChainName.Arbitrum,
1254
+ identifier: "ARB",
1255
+ name: "ARB",
1256
+ decimals: 18,
1257
+ logoUrl: "https://vleap.ai/images/tokens/arb.svg"
1258
+ };
1259
+ var getArbitrumAdapter = createEvmAdapter(import_warps5.WarpChainName.Arbitrum, "arb", {
1260
+ mainnet: {
1261
+ name: import_warps5.WarpChainName.Arbitrum,
1262
+ displayName: "Arbitrum",
1263
+ chainId: "42161",
1264
+ blockTime: 1e3,
1265
+ addressHrp: "0x",
1266
+ defaultApiUrl: "https://arb1.arbitrum.io/rpc",
1267
+ nativeToken: NativeTokenArb
1268
+ },
1269
+ testnet: {
1270
+ name: import_warps5.WarpChainName.Arbitrum,
1271
+ displayName: "Arbitrum Sepolia",
1272
+ chainId: "421614",
1273
+ blockTime: 1e3,
1274
+ addressHrp: "0x",
1275
+ defaultApiUrl: "https://sepolia-rollup.arbitrum.io/rpc",
1276
+ nativeToken: NativeTokenArb
1277
+ },
1278
+ devnet: {
1279
+ name: import_warps5.WarpChainName.Arbitrum,
1280
+ displayName: "Arbitrum Sepolia",
1281
+ chainId: "421614",
1282
+ blockTime: 1e3,
1283
+ addressHrp: "0x",
1284
+ defaultApiUrl: "https://sepolia-rollup.arbitrum.io/rpc",
1285
+ nativeToken: NativeTokenArb
1286
+ }
1287
+ });
1288
+
1289
+ // src/chains/base.ts
1290
+ var import_warps6 = require("@vleap/warps");
1291
+ var NativeTokenBase = {
1292
+ chain: import_warps6.WarpChainName.Base,
1293
+ identifier: "ETH",
1294
+ name: "ETH",
1295
+ decimals: 18,
1296
+ logoUrl: "https://vleap.ai/images/tokens/eth.svg"
1297
+ };
1298
+ var getBaseAdapter = createEvmAdapter(import_warps6.WarpChainName.Base, "base", {
1299
+ mainnet: {
1300
+ name: import_warps6.WarpChainName.Base,
1301
+ displayName: "Base",
1302
+ chainId: "8453",
1303
+ blockTime: 2e3,
1304
+ addressHrp: "0x",
1305
+ defaultApiUrl: "https://mainnet.base.org",
1306
+ nativeToken: NativeTokenBase
1307
+ },
1308
+ testnet: {
1309
+ name: import_warps6.WarpChainName.Base,
1310
+ displayName: "Base Sepolia",
1311
+ chainId: "84532",
1312
+ blockTime: 2e3,
1313
+ addressHrp: "0x",
1314
+ defaultApiUrl: "https://sepolia.base.org",
1315
+ nativeToken: NativeTokenBase
1316
+ },
1317
+ devnet: {
1318
+ name: import_warps6.WarpChainName.Base,
1319
+ displayName: "Base Sepolia",
1320
+ chainId: "84532",
1321
+ blockTime: 2e3,
1322
+ addressHrp: "0x",
1323
+ defaultApiUrl: "https://sepolia.base.org",
1324
+ nativeToken: NativeTokenBase
1325
+ }
1326
+ });
1327
+
1328
+ // src/chains/combined.ts
1329
+ var import_warps8 = require("@vleap/warps");
1330
+
1331
+ // src/chains/ethereum.ts
1332
+ var import_warps7 = require("@vleap/warps");
1333
+ var NativeTokenEth = {
1334
+ chain: import_warps7.WarpChainName.Ethereum,
1335
+ identifier: "ETH",
1336
+ name: "ETH",
1337
+ decimals: 18,
1338
+ logoUrl: "https://vleap.ai/images/tokens/eth.svg"
1339
+ };
1340
+ var getEthereumAdapter = createEvmAdapter(import_warps7.WarpChainName.Ethereum, "eth", {
1341
+ mainnet: {
1342
+ name: import_warps7.WarpChainName.Ethereum,
1343
+ displayName: "Ethereum Mainnet",
1344
+ chainId: "1",
1345
+ blockTime: 12e3,
1346
+ addressHrp: "0x",
1347
+ defaultApiUrl: "https://ethereum-rpc.publicnode.com",
1348
+ nativeToken: NativeTokenEth
1349
+ },
1350
+ testnet: {
1351
+ name: import_warps7.WarpChainName.Ethereum,
1352
+ displayName: "Ethereum Sepolia",
1353
+ chainId: "11155111",
1354
+ blockTime: 12e3,
1355
+ addressHrp: "0x",
1356
+ defaultApiUrl: "https://ethereum-sepolia-rpc.publicnode.com",
1357
+ nativeToken: NativeTokenEth
1358
+ },
1359
+ devnet: {
1360
+ name: import_warps7.WarpChainName.Ethereum,
1361
+ displayName: "Ethereum Sepolia",
1362
+ chainId: "11155111",
1363
+ blockTime: 12e3,
1364
+ addressHrp: "0x",
1365
+ defaultApiUrl: "https://ethereum-sepolia-rpc.publicnode.com",
1366
+ nativeToken: NativeTokenEth
1367
+ }
1368
+ });
1369
+
1370
+ // src/chains/combined.ts
1371
+ var getAllEvmAdapters = (config, fallback) => [
1372
+ getEthereumAdapter(config, fallback),
1373
+ getArbitrumAdapter(config, fallback),
1374
+ getBaseAdapter(config, fallback)
1375
+ ];
1376
+ var getAllEvmChainNames = () => [import_warps8.WarpChainName.Ethereum, import_warps8.WarpChainName.Base, import_warps8.WarpChainName.Arbitrum];
773
1377
  // Annotate the CommonJS export names for ESM import in node:
774
1378
  0 && (module.exports = {
775
- EVM_CHAIN_CONFIGS,
776
- WarpEvmBuilder,
1379
+ ArbitrumExplorers,
1380
+ BaseExplorers,
1381
+ EthereumExplorers,
1382
+ EvmExplorers,
1383
+ EvmLogoService,
1384
+ ExplorerUrls,
1385
+ NativeTokenArb,
1386
+ NativeTokenBase,
1387
+ NativeTokenEth,
777
1388
  WarpEvmConstants,
1389
+ WarpEvmDataLoader,
778
1390
  WarpEvmExecutor,
779
1391
  WarpEvmExplorer,
780
1392
  WarpEvmResults,
781
1393
  WarpEvmSerializer,
782
- getEvmAdapter,
783
- getEvmApiUrl,
784
- getEvmBlockTime,
785
- getEvmChainConfig,
786
- getEvmChainId,
787
- getEvmExplorerUrl,
788
- getEvmNativeToken,
789
- getEvmRegistryAddress,
790
- getSupportedEnvironments,
791
- getSupportedEvmChains
1394
+ createEvmAdapter,
1395
+ getAllEvmAdapters,
1396
+ getAllEvmChainNames,
1397
+ getArbitrumAdapter,
1398
+ getBaseAdapter,
1399
+ getEthereumAdapter
792
1400
  });
793
1401
  //# sourceMappingURL=index.js.map