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