@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.mjs CHANGED
@@ -1,295 +1,586 @@
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 accountReq = this.getAccount(address);
311
+ const tokenBalancesReq = this.getERC20TokenBalances(address);
312
+ const [account, tokenBalances] = await Promise.all([accountReq, tokenBalancesReq]);
313
+ const assets = [];
314
+ if (account.balance > 0n) {
315
+ assets.push({ ...this.chain.nativeToken, amount: account.balance });
316
+ }
317
+ for (const tokenBalance of tokenBalances) {
318
+ if (tokenBalance.balance > 0n) {
319
+ const logoUrl = tokenBalance.metadata.logoUrl || await EvmLogoService.getLogoUrl(
320
+ this.chain.name,
321
+ tokenBalance.tokenAddress,
322
+ tokenBalance.metadata.name,
323
+ tokenBalance.metadata.symbol
324
+ );
325
+ assets.push({
326
+ chain: this.chain.name,
327
+ identifier: tokenBalance.tokenAddress,
328
+ name: tokenBalance.metadata.name,
329
+ amount: tokenBalance.balance,
330
+ decimals: tokenBalance.metadata.decimals,
331
+ logoUrl: logoUrl || ""
332
+ });
333
+ }
334
+ }
335
+ return assets;
336
+ } catch (error) {
337
+ throw new Error(`Failed to get account assets for ${address}: ${error}`);
338
+ }
214
339
  }
215
- addAction(action) {
216
- this.actions.push(action);
217
- return this;
340
+ async getAccountActions(address, options) {
341
+ return [];
218
342
  }
219
- async build() {
220
- if (!this.warp.title) {
221
- throw new Error("Warp title is required");
343
+ async getERC20TokenBalances(address) {
344
+ const tokenBalances = [];
345
+ const knownTokens = KNOWN_TOKENS[this.chain.name] || {};
346
+ for (const [tokenAddress, metadata] of Object.entries(knownTokens)) {
347
+ try {
348
+ const balance = await this.getTokenBalance(address, tokenAddress);
349
+ if (balance > 0n) {
350
+ tokenBalances.push({
351
+ tokenAddress,
352
+ balance,
353
+ metadata
354
+ });
355
+ }
356
+ } catch (error) {
357
+ }
222
358
  }
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()
359
+ const additionalTokens = await this.detectTokensFromEvents(address);
360
+ for (const tokenAddress of additionalTokens) {
361
+ if (!knownTokens[tokenAddress]) {
362
+ try {
363
+ const metadata = await this.getTokenMetadata(tokenAddress);
364
+ const balance = await this.getTokenBalance(address, tokenAddress);
365
+ if (balance > 0n) {
366
+ tokenBalances.push({
367
+ tokenAddress,
368
+ balance,
369
+ metadata
370
+ });
371
+ }
372
+ } catch (error) {
373
+ }
235
374
  }
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
- };
375
+ }
376
+ return tokenBalances;
244
377
  }
245
- async createFromTransaction(tx, validate) {
246
- if (!tx.data || tx.data === "0x") {
247
- throw new Error("Transaction has no data");
378
+ async getTokenBalance(address, tokenAddress) {
379
+ try {
380
+ const contract = new ethers.Contract(tokenAddress, ERC20_ABI, this.provider);
381
+ const balance = await contract.balanceOf(address);
382
+ return balance;
383
+ } catch (error) {
384
+ throw new Error(`Failed to get token balance: ${error}`);
248
385
  }
386
+ }
387
+ async getTokenMetadata(tokenAddress) {
249
388
  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
- }
389
+ const tokenInfo = await EvmLogoService.getTokenInfo(this.chain.name, tokenAddress);
390
+ if (tokenInfo.name && tokenInfo.symbol && tokenInfo.decimals !== void 0) {
391
+ return {
392
+ name: tokenInfo.name,
393
+ symbol: tokenInfo.symbol,
394
+ decimals: tokenInfo.decimals,
395
+ logoUrl: tokenInfo.logoURI
396
+ };
259
397
  }
260
- return warp;
398
+ const contract = new ethers.Contract(tokenAddress, ERC20_ABI, this.provider);
399
+ const [name, symbol, decimals] = await Promise.all([
400
+ contract.name().catch(() => tokenInfo.name || "Unknown Token"),
401
+ contract.symbol().catch(() => tokenInfo.symbol || "UNKNOWN"),
402
+ contract.decimals().catch(() => tokenInfo.decimals || 18)
403
+ ]);
404
+ return {
405
+ name: name || tokenInfo.name || "Unknown Token",
406
+ symbol: symbol || tokenInfo.symbol || "UNKNOWN",
407
+ decimals: decimals || tokenInfo.decimals || 18,
408
+ logoUrl: tokenInfo.logoURI
409
+ };
261
410
  } catch (error) {
262
- throw new Error(`Failed to create warp from transaction: ${error}`);
411
+ throw new Error(`Failed to get token metadata: ${error}`);
263
412
  }
264
413
  }
265
- async createFromTransactionHash(hash, cache) {
414
+ async detectTokensFromEvents(address) {
266
415
  try {
267
- const provider = new ethers.JsonRpcProvider(getEvmApiUrl(this.config.env));
268
- const tx = await provider.getTransaction(hash);
269
- if (!tx) {
270
- return null;
416
+ const currentBlock = await this.provider.getBlockNumber();
417
+ const fromBlock = Math.max(0, currentBlock - 1e4);
418
+ const filter = {
419
+ fromBlock,
420
+ toBlock: currentBlock,
421
+ topics: [
422
+ ethers.id("Transfer(address,address,uint256)"),
423
+ null,
424
+ // from address (any)
425
+ ethers.zeroPadValue(address, 32)
426
+ // to address (our target)
427
+ ]
428
+ };
429
+ const logs = await this.provider.getLogs(filter);
430
+ const tokenAddresses = /* @__PURE__ */ new Set();
431
+ for (const log of logs) {
432
+ tokenAddresses.add(log.address);
271
433
  }
272
- return await this.createFromTransaction(tx);
434
+ return Array.from(tokenAddresses);
435
+ } catch (error) {
436
+ return [];
437
+ }
438
+ }
439
+ // Additional utility methods for enhanced token support
440
+ async getTokenInfo(tokenAddress) {
441
+ try {
442
+ return await this.getTokenMetadata(tokenAddress);
443
+ } catch (error) {
444
+ return null;
445
+ }
446
+ }
447
+ async getTokenBalanceForAddress(address, tokenAddress) {
448
+ try {
449
+ return await this.getTokenBalance(address, tokenAddress);
450
+ } catch (error) {
451
+ throw new Error(`Failed to get token balance for ${tokenAddress}: ${error}`);
452
+ }
453
+ }
454
+ async getMultipleTokenBalances(address, tokenAddresses) {
455
+ const balances = /* @__PURE__ */ new Map();
456
+ await Promise.all(
457
+ tokenAddresses.map(async (tokenAddress) => {
458
+ try {
459
+ const balance = await this.getTokenBalance(address, tokenAddress);
460
+ balances.set(tokenAddress, balance);
461
+ } catch (error) {
462
+ balances.set(tokenAddress, 0n);
463
+ }
464
+ })
465
+ );
466
+ return balances;
467
+ }
468
+ async getAccountTokens(address) {
469
+ return this.getAccountAssets(address);
470
+ }
471
+ async getTokenMetadataPublic(tokenAddress) {
472
+ try {
473
+ return await this.getTokenMetadata(tokenAddress);
273
474
  } catch (error) {
274
475
  return null;
275
476
  }
276
477
  }
478
+ async getChainInfo() {
479
+ try {
480
+ const network = await this.provider.getNetwork();
481
+ const latestBlock = await this.provider.getBlock("latest");
482
+ return {
483
+ chainId: network.chainId.toString(),
484
+ blockTime: latestBlock?.timestamp ? Date.now() / 1e3 - latestBlock.timestamp : 12
485
+ };
486
+ } catch (error) {
487
+ throw new Error(`Failed to get chain info: ${error}`);
488
+ }
489
+ }
277
490
  };
278
491
 
279
492
  // src/WarpEvmExecutor.ts
280
493
  import {
281
494
  applyResultsToMessages,
282
495
  getNextInfo,
496
+ getProviderUrl as getProviderUrl3,
283
497
  getWarpActionByIndex
284
498
  } from "@vleap/warps";
285
- import { ethers as ethers3 } from "ethers";
499
+ import { ethers as ethers4 } from "ethers";
500
+
501
+ // src/constants.ts
502
+ var WarpEvmConstants = {
503
+ GasLimit: {
504
+ Default: 21e3,
505
+ ContractCall: 1e5,
506
+ ContractDeploy: 5e5,
507
+ Transfer: 21e3,
508
+ TokenTransfer: 65e3,
509
+ // ERC-20 transfer gas limit
510
+ Approve: 46e3,
511
+ Swap: 2e5
512
+ },
513
+ GasPrice: {
514
+ Default: "20000000000"
515
+ },
516
+ Validation: {
517
+ MinGasLimit: 21e3,
518
+ MaxGasLimit: 3e7
519
+ }
520
+ };
521
+ var EthereumExplorers = /* @__PURE__ */ ((EthereumExplorers2) => {
522
+ EthereumExplorers2["Etherscan"] = "etherscan";
523
+ EthereumExplorers2["EtherscanSepolia"] = "etherscan_sepolia";
524
+ EthereumExplorers2["Ethplorer"] = "ethplorer";
525
+ EthereumExplorers2["Blockscout"] = "blockscout";
526
+ EthereumExplorers2["BlockscoutSepolia"] = "blockscout_sepolia";
527
+ return EthereumExplorers2;
528
+ })(EthereumExplorers || {});
529
+ var ArbitrumExplorers = /* @__PURE__ */ ((ArbitrumExplorers2) => {
530
+ ArbitrumExplorers2["Arbiscan"] = "arbiscan";
531
+ ArbitrumExplorers2["ArbiscanSepolia"] = "arbiscan_sepolia";
532
+ ArbitrumExplorers2["BlockscoutArbitrum"] = "blockscout_arbitrum";
533
+ ArbitrumExplorers2["BlockscoutArbitrumSepolia"] = "blockscout_arbitrum_sepolia";
534
+ return ArbitrumExplorers2;
535
+ })(ArbitrumExplorers || {});
536
+ var BaseExplorers = /* @__PURE__ */ ((BaseExplorers2) => {
537
+ BaseExplorers2["Basescan"] = "basescan";
538
+ BaseExplorers2["BasescanSepolia"] = "basescan_sepolia";
539
+ BaseExplorers2["BlockscoutBase"] = "blockscout_base";
540
+ BaseExplorers2["BlockscoutBaseSepolia"] = "blockscout_base_sepolia";
541
+ return BaseExplorers2;
542
+ })(BaseExplorers || {});
543
+ var EvmExplorers = {
544
+ ethereum: {
545
+ mainnet: ["etherscan" /* Etherscan */, "ethplorer" /* Ethplorer */, "blockscout" /* Blockscout */],
546
+ testnet: ["etherscan_sepolia" /* EtherscanSepolia */, "blockscout_sepolia" /* BlockscoutSepolia */],
547
+ devnet: ["etherscan_sepolia" /* EtherscanSepolia */, "blockscout_sepolia" /* BlockscoutSepolia */]
548
+ },
549
+ arbitrum: {
550
+ mainnet: ["arbiscan" /* Arbiscan */, "blockscout_arbitrum" /* BlockscoutArbitrum */],
551
+ testnet: ["arbiscan_sepolia" /* ArbiscanSepolia */, "blockscout_arbitrum_sepolia" /* BlockscoutArbitrumSepolia */],
552
+ devnet: ["arbiscan_sepolia" /* ArbiscanSepolia */, "blockscout_arbitrum_sepolia" /* BlockscoutArbitrumSepolia */]
553
+ },
554
+ base: {
555
+ mainnet: ["basescan" /* Basescan */, "blockscout_base" /* BlockscoutBase */],
556
+ testnet: ["basescan_sepolia" /* BasescanSepolia */, "blockscout_base_sepolia" /* BlockscoutBaseSepolia */],
557
+ devnet: ["basescan_sepolia" /* BasescanSepolia */, "blockscout_base_sepolia" /* BlockscoutBaseSepolia */]
558
+ }
559
+ };
560
+ var ExplorerUrls = {
561
+ ["etherscan" /* Etherscan */]: "https://etherscan.io",
562
+ ["etherscan_sepolia" /* EtherscanSepolia */]: "https://sepolia.etherscan.io",
563
+ ["ethplorer" /* Ethplorer */]: "https://ethplorer.io",
564
+ ["blockscout" /* Blockscout */]: "https://eth.blockscout.com",
565
+ ["blockscout_sepolia" /* BlockscoutSepolia */]: "https://sepolia.blockscout.com",
566
+ ["arbiscan" /* Arbiscan */]: "https://arbiscan.io",
567
+ ["arbiscan_sepolia" /* ArbiscanSepolia */]: "https://sepolia.arbiscan.io",
568
+ ["blockscout_arbitrum" /* BlockscoutArbitrum */]: "https://arbitrum.blockscout.com",
569
+ ["blockscout_arbitrum_sepolia" /* BlockscoutArbitrumSepolia */]: "https://sepolia.blockscout.com",
570
+ ["basescan" /* Basescan */]: "https://basescan.org",
571
+ ["basescan_sepolia" /* BasescanSepolia */]: "https://sepolia.basescan.org",
572
+ ["blockscout_base" /* BlockscoutBase */]: "https://base.blockscout.com",
573
+ ["blockscout_base_sepolia" /* BlockscoutBaseSepolia */]: "https://sepolia.blockscout.com"
574
+ };
286
575
 
287
576
  // src/WarpEvmResults.ts
288
577
  import {
289
578
  evaluateResultsCommon,
579
+ getProviderUrl as getProviderUrl2,
290
580
  parseResultsOutIndex,
291
581
  WarpConstants as WarpConstants2
292
582
  } from "@vleap/warps";
583
+ import { ethers as ethers3 } from "ethers";
293
584
 
294
585
  // src/WarpEvmSerializer.ts
295
586
  import {
@@ -448,9 +739,19 @@ var WarpEvmSerializer = class {
448
739
 
449
740
  // src/WarpEvmResults.ts
450
741
  var WarpEvmResults = class {
451
- constructor(config) {
742
+ constructor(config, chain) {
452
743
  this.config = config;
744
+ this.chain = chain;
453
745
  this.serializer = new WarpEvmSerializer();
746
+ if (this.chain) {
747
+ const apiUrl = getProviderUrl2(this.config, this.chain.name, this.config.env, this.chain.defaultApiUrl);
748
+ const network = new ethers3.Network(this.chain.name, parseInt(this.chain.chainId));
749
+ this.provider = new ethers3.JsonRpcProvider(apiUrl, network);
750
+ } else {
751
+ const apiUrl = getProviderUrl2(this.config, "ethereum", this.config.env, "https://ethereum-rpc.publicnode.com");
752
+ const network = new ethers3.Network("ethereum", 1);
753
+ this.provider = new ethers3.JsonRpcProvider(apiUrl, network);
754
+ }
454
755
  }
455
756
  async getTransactionExecutionResults(warp, tx) {
456
757
  const success = tx.status === 1;
@@ -472,8 +773,10 @@ var WarpEvmResults = class {
472
773
  action: 0,
473
774
  user: this.config.user?.wallets?.evm || null,
474
775
  txHash: transactionHash,
776
+ tx,
475
777
  next: null,
476
778
  values: [transactionHash, blockNumber, gasUsed, gasPrice, ...logs.length > 0 ? logs : []],
779
+ valuesRaw: [transactionHash, blockNumber, gasUsed, gasPrice, ...logs.length > 0 ? logs : []],
477
780
  results: {},
478
781
  messages: {}
479
782
  };
@@ -482,7 +785,7 @@ var WarpEvmResults = class {
482
785
  const values = typedValues.map((t) => this.serializer.typedToString(t));
483
786
  const valuesRaw = typedValues.map((t) => this.serializer.typedToNative(t)[1]);
484
787
  let results = {};
485
- if (!warp.results) return { values, results };
788
+ if (!warp.results) return { values, valuesRaw, results };
486
789
  const getNestedValue = (path) => {
487
790
  const indices = path.split(".").slice(1).map((i) => parseInt(i) - 1);
488
791
  if (indices.length === 0) return void 0;
@@ -506,17 +809,42 @@ var WarpEvmResults = class {
506
809
  results[key] = path;
507
810
  }
508
811
  }
509
- return { values, results: await evaluateResultsCommon(warp, results, actionIndex, inputs) };
812
+ return { values, valuesRaw, results: await evaluateResultsCommon(warp, results, actionIndex, inputs) };
813
+ }
814
+ async getTransactionStatus(txHash) {
815
+ try {
816
+ const receipt = await this.provider.getTransactionReceipt(txHash);
817
+ if (!receipt) {
818
+ return { status: "pending" };
819
+ }
820
+ return {
821
+ status: receipt.status === 1 ? "confirmed" : "failed",
822
+ blockNumber: receipt.blockNumber,
823
+ gasUsed: receipt.gasUsed
824
+ };
825
+ } catch (error) {
826
+ throw new Error(`Failed to get transaction status: ${error}`);
827
+ }
828
+ }
829
+ async getTransactionReceipt(txHash) {
830
+ try {
831
+ return await this.provider.getTransactionReceipt(txHash);
832
+ } catch (error) {
833
+ return null;
834
+ }
510
835
  }
511
836
  };
512
837
 
513
838
  // src/WarpEvmExecutor.ts
514
839
  var WarpEvmExecutor = class {
515
- constructor(config) {
840
+ constructor(config, chain) {
516
841
  this.config = config;
842
+ this.chain = chain;
517
843
  this.serializer = new WarpEvmSerializer();
518
- this.provider = new ethers3.JsonRpcProvider(getEvmApiUrl(config.env));
519
- this.results = new WarpEvmResults(config);
844
+ const apiUrl = getProviderUrl3(this.config, chain.name, this.config.env, this.chain.defaultApiUrl);
845
+ const network = new ethers4.Network(this.chain.name, parseInt(this.chain.chainId));
846
+ this.provider = new ethers4.JsonRpcProvider(apiUrl, network);
847
+ this.results = new WarpEvmResults(config, this.chain);
520
848
  }
521
849
  async createTransaction(executable) {
522
850
  const action = getWarpActionByIndex(executable.warp, executable.action);
@@ -536,11 +864,11 @@ var WarpEvmExecutor = class {
536
864
  async createTransferTransaction(executable) {
537
865
  const userWallet = this.config.user?.wallets?.[executable.chain.name];
538
866
  if (!userWallet) throw new Error("WarpEvmExecutor: createTransfer - user address not set");
539
- if (!ethers3.isAddress(executable.destination)) {
867
+ if (!ethers4.isAddress(executable.destination)) {
540
868
  throw new Error(`WarpEvmExecutor: Invalid destination address: ${executable.destination}`);
541
869
  }
542
- if (executable.value < 0) {
543
- throw new Error(`WarpEvmExecutor: Transfer value cannot be negative: ${executable.value}`);
870
+ if (executable.transfers && executable.transfers.length > 0) {
871
+ return this.createTokenTransferTransaction(executable, userWallet);
544
872
  }
545
873
  const tx = {
546
874
  to: executable.destination,
@@ -556,14 +884,11 @@ var WarpEvmExecutor = class {
556
884
  if (!action || !("func" in action) || !action.func) {
557
885
  throw new Error("WarpEvmExecutor: Contract action must have a function name");
558
886
  }
559
- if (!ethers3.isAddress(executable.destination)) {
887
+ if (!ethers4.isAddress(executable.destination)) {
560
888
  throw new Error(`WarpEvmExecutor: Invalid contract address: ${executable.destination}`);
561
889
  }
562
- if (executable.value < 0) {
563
- throw new Error(`WarpEvmExecutor: Contract call value cannot be negative: ${executable.value}`);
564
- }
565
890
  try {
566
- const iface = new ethers3.Interface([`function ${action.func}`]);
891
+ const iface = new ethers4.Interface([`function ${action.func}`]);
567
892
  const encodedData = iface.encodeFunctionData(action.func, executable.args);
568
893
  const tx = {
569
894
  to: executable.destination,
@@ -575,6 +900,50 @@ var WarpEvmExecutor = class {
575
900
  throw new Error(`WarpEvmExecutor: Failed to encode function data for ${action.func}: ${error}`);
576
901
  }
577
902
  }
903
+ async createTokenTransferTransaction(executable, userWallet) {
904
+ if (executable.transfers.length === 0) {
905
+ throw new Error("WarpEvmExecutor: No transfers provided");
906
+ }
907
+ if (!this.chain.nativeToken?.identifier) {
908
+ throw new Error("WarpEvmExecutor: No native token defined for this chain");
909
+ }
910
+ const nativeTokenTransfers = executable.transfers.filter((transfer) => transfer.identifier === this.chain.nativeToken.identifier);
911
+ const erc20Transfers = executable.transfers.filter((transfer) => transfer.identifier !== this.chain.nativeToken.identifier);
912
+ if (nativeTokenTransfers.length === 1 && erc20Transfers.length === 0) {
913
+ const transfer = nativeTokenTransfers[0];
914
+ if (transfer.amount <= 0n) {
915
+ throw new Error("WarpEvmExecutor: Native token transfer amount must be positive");
916
+ }
917
+ const tx = {
918
+ to: executable.destination,
919
+ value: transfer.amount,
920
+ data: "0x"
921
+ };
922
+ return this.estimateGasAndSetDefaults(tx, userWallet);
923
+ }
924
+ if (nativeTokenTransfers.length === 0 && erc20Transfers.length === 1) {
925
+ return this.createSingleTokenTransfer(executable, erc20Transfers[0], userWallet);
926
+ }
927
+ if (executable.transfers.length > 1) {
928
+ throw new Error("WarpEvmExecutor: Multiple token transfers not yet supported");
929
+ }
930
+ throw new Error("WarpEvmExecutor: Invalid transfer configuration");
931
+ }
932
+ async createSingleTokenTransfer(executable, transfer, userWallet) {
933
+ if (!ethers4.isAddress(transfer.identifier)) {
934
+ throw new Error(`WarpEvmExecutor: Invalid token address: ${transfer.identifier}`);
935
+ }
936
+ const transferInterface = new ethers4.Interface(["function transfer(address to, uint256 amount) returns (bool)"]);
937
+ const encodedData = transferInterface.encodeFunctionData("transfer", [executable.destination, transfer.amount]);
938
+ const tx = {
939
+ to: transfer.identifier,
940
+ // Token contract address
941
+ value: 0n,
942
+ // No native token value for ERC-20 transfers
943
+ data: encodedData
944
+ };
945
+ return this.estimateGasAndSetDefaults(tx, userWallet);
946
+ }
578
947
  async executeQuery(executable) {
579
948
  const action = getWarpActionByIndex(executable.warp, executable.action);
580
949
  if (action.type !== "query") {
@@ -583,11 +952,11 @@ var WarpEvmExecutor = class {
583
952
  if (!action.func) {
584
953
  throw new Error("WarpEvmExecutor: Query action must have a function name");
585
954
  }
586
- if (!ethers3.isAddress(executable.destination)) {
955
+ if (!ethers4.isAddress(executable.destination)) {
587
956
  throw new Error(`WarpEvmExecutor: Invalid contract address for query: ${executable.destination}`);
588
957
  }
589
958
  try {
590
- const iface = new ethers3.Interface([`function ${action.func}`]);
959
+ const iface = new ethers4.Interface([`function ${action.func}`]);
591
960
  const encodedData = iface.encodeFunctionData(action.func, executable.args);
592
961
  const result = await this.provider.call({
593
962
  to: executable.destination,
@@ -595,22 +964,23 @@ var WarpEvmExecutor = class {
595
964
  });
596
965
  const decodedResult = iface.decodeFunctionResult(action.func, result);
597
966
  const isSuccess = true;
598
- const { values, results } = await this.results.extractQueryResults(
967
+ const { values, valuesRaw, results } = await this.results.extractQueryResults(
599
968
  executable.warp,
600
969
  decodedResult,
601
970
  executable.action,
602
971
  executable.resolvedInputs
603
972
  );
604
- const adapter = getEvmAdapter(this.config);
605
- const next = getNextInfo(this.config, adapter, executable.warp, executable.action, results);
973
+ const next = getNextInfo(this.config, [], executable.warp, executable.action, results);
606
974
  return {
607
975
  success: isSuccess,
608
976
  warp: executable.warp,
609
977
  action: executable.action,
610
978
  user: this.config.user?.wallets?.[executable.chain.name] || null,
611
979
  txHash: null,
980
+ tx: null,
612
981
  next,
613
982
  values,
983
+ valuesRaw,
614
984
  results,
615
985
  messages: applyResultsToMessages(executable.warp, results)
616
986
  };
@@ -621,39 +991,17 @@ var WarpEvmExecutor = class {
621
991
  action: executable.action,
622
992
  user: this.config.user?.wallets?.[executable.chain.name] || null,
623
993
  txHash: null,
994
+ tx: null,
624
995
  next: null,
625
996
  values: [],
997
+ valuesRaw: [],
626
998
  results: {},
627
999
  messages: {}
628
1000
  };
629
1001
  }
630
1002
  }
631
1003
  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
- }
1004
+ return input;
657
1005
  }
658
1006
  async estimateGasAndSetDefaults(tx, from) {
659
1007
  try {
@@ -671,6 +1019,7 @@ var WarpEvmExecutor = class {
671
1019
  if (feeData.maxFeePerGas && feeData.maxPriorityFeePerGas) {
672
1020
  return {
673
1021
  ...tx,
1022
+ chainId: BigInt(this.chain.chainId),
674
1023
  gasLimit: gasEstimate,
675
1024
  maxFeePerGas: feeData.maxFeePerGas,
676
1025
  maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
@@ -678,84 +1027,343 @@ var WarpEvmExecutor = class {
678
1027
  } else if (feeData.gasPrice) {
679
1028
  return {
680
1029
  ...tx,
1030
+ chainId: BigInt(this.chain.chainId),
681
1031
  gasLimit: gasEstimate,
682
1032
  gasPrice: feeData.gasPrice
683
1033
  };
684
1034
  } else {
685
1035
  return {
686
1036
  ...tx,
1037
+ chainId: BigInt(this.chain.chainId),
687
1038
  gasLimit: gasEstimate,
688
- gasPrice: ethers3.parseUnits(WarpEvmConstants.GasPrice.Default, "wei")
1039
+ gasPrice: ethers4.parseUnits(WarpEvmConstants.GasPrice.Default, "wei")
689
1040
  };
690
1041
  }
691
1042
  } catch (error) {
692
1043
  let defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.Default);
693
1044
  if (tx.data && tx.data !== "0x") {
694
- defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.ContractCall);
1045
+ if (tx.data.startsWith("0xa9059cbb")) {
1046
+ defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.TokenTransfer);
1047
+ } else {
1048
+ defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.ContractCall);
1049
+ }
695
1050
  } else {
696
1051
  defaultGasLimit = BigInt(WarpEvmConstants.GasLimit.Transfer);
697
1052
  }
698
1053
  return {
699
1054
  ...tx,
1055
+ chainId: BigInt(this.chain.chainId),
700
1056
  gasLimit: defaultGasLimit,
701
- gasPrice: ethers3.parseUnits(WarpEvmConstants.GasPrice.Default, "wei")
1057
+ gasPrice: ethers4.parseUnits(WarpEvmConstants.GasPrice.Default, "wei")
702
1058
  };
703
1059
  }
704
1060
  }
705
1061
  async signMessage(message, privateKey) {
706
- throw new Error("Not implemented");
1062
+ try {
1063
+ const wallet = new ethers4.Wallet(privateKey);
1064
+ const signature = await wallet.signMessage(message);
1065
+ return signature;
1066
+ } catch (error) {
1067
+ throw new Error(`Failed to sign message: ${error}`);
1068
+ }
1069
+ }
1070
+ async verifyMessage(message, signature) {
1071
+ try {
1072
+ const recoveredAddress = ethers4.verifyMessage(message, signature);
1073
+ return recoveredAddress;
1074
+ } catch (error) {
1075
+ throw new Error(`Failed to verify message: ${error}`);
1076
+ }
707
1077
  }
708
1078
  };
709
1079
 
710
1080
  // src/WarpEvmExplorer.ts
711
1081
  var WarpEvmExplorer = class {
712
- constructor(chainInfo, chainName = "ethereum") {
713
- this.chainInfo = chainInfo;
714
- this.chainName = chainName;
1082
+ constructor(chain, config) {
1083
+ this.chain = chain;
1084
+ this.config = config;
1085
+ }
1086
+ getExplorers() {
1087
+ const chainExplorers = EvmExplorers[this.chain.name];
1088
+ if (!chainExplorers) {
1089
+ return ["Default"];
1090
+ }
1091
+ const explorers = chainExplorers[this.config.env];
1092
+ if (!explorers) {
1093
+ return ["Default"];
1094
+ }
1095
+ return explorers;
1096
+ }
1097
+ getPrimaryExplorer() {
1098
+ const explorers = this.getExplorers();
1099
+ return explorers[0];
1100
+ }
1101
+ getExplorerUrlByName(explorer) {
1102
+ const userPreference = this.config.preferences?.explorers?.[this.chain.name];
1103
+ if (userPreference && !explorer) {
1104
+ const url2 = ExplorerUrls[userPreference];
1105
+ if (url2) return url2;
1106
+ }
1107
+ if (explorer) {
1108
+ const url2 = ExplorerUrls[explorer];
1109
+ if (url2) return url2;
1110
+ }
1111
+ const primaryExplorer = this.getPrimaryExplorer();
1112
+ const url = ExplorerUrls[primaryExplorer];
1113
+ return url || ExplorerUrls[primaryExplorer];
715
1114
  }
716
- getAccountUrl(address) {
717
- const baseUrl = this.chainInfo.explorerUrl || getEvmExplorerUrl("mainnet", this.chainName);
1115
+ getAccountUrl(address, explorer) {
1116
+ const baseUrl = this.getExplorerUrlByName(explorer);
718
1117
  return `${baseUrl}/address/${address}`;
719
1118
  }
720
- getTransactionUrl(hash) {
721
- const baseUrl = this.chainInfo.explorerUrl || getEvmExplorerUrl("mainnet", this.chainName);
1119
+ getTransactionUrl(hash, explorer) {
1120
+ const baseUrl = this.getExplorerUrlByName(explorer);
722
1121
  return `${baseUrl}/tx/${hash}`;
723
1122
  }
1123
+ getBlockUrl(blockNumber, explorer) {
1124
+ const baseUrl = this.getExplorerUrlByName(explorer);
1125
+ return `${baseUrl}/block/${blockNumber}`;
1126
+ }
1127
+ getAssetUrl(identifier, explorer) {
1128
+ const baseUrl = this.getExplorerUrlByName(explorer);
1129
+ return `${baseUrl}/token/${identifier}`;
1130
+ }
1131
+ getContractUrl(address, explorer) {
1132
+ const baseUrl = this.getExplorerUrlByName(explorer);
1133
+ return `${baseUrl}/address/${address}`;
1134
+ }
1135
+ getAllExplorers() {
1136
+ return this.getExplorers();
1137
+ }
1138
+ getExplorerByName(name) {
1139
+ const explorers = this.getExplorers();
1140
+ return explorers.find((explorer) => explorer.toLowerCase() === name.toLowerCase());
1141
+ }
1142
+ getAccountUrls(address) {
1143
+ const explorers = this.getAllExplorers();
1144
+ const urls = {};
1145
+ explorers.forEach((explorer) => {
1146
+ const url = ExplorerUrls[explorer];
1147
+ if (url) {
1148
+ urls[explorer] = `${url}/address/${address}`;
1149
+ }
1150
+ });
1151
+ return urls;
1152
+ }
1153
+ getTransactionUrls(hash) {
1154
+ const explorers = this.getAllExplorers();
1155
+ const urls = {};
1156
+ explorers.forEach((explorer) => {
1157
+ const url = ExplorerUrls[explorer];
1158
+ if (url) {
1159
+ urls[explorer] = `${url}/tx/${hash}`;
1160
+ }
1161
+ });
1162
+ return urls;
1163
+ }
1164
+ getAssetUrls(identifier) {
1165
+ const explorers = this.getAllExplorers();
1166
+ const urls = {};
1167
+ explorers.forEach((explorer) => {
1168
+ const url = ExplorerUrls[explorer];
1169
+ if (url) {
1170
+ urls[explorer] = `${url}/token/${identifier}`;
1171
+ }
1172
+ });
1173
+ return urls;
1174
+ }
1175
+ getContractUrls(address) {
1176
+ const explorers = this.getAllExplorers();
1177
+ const urls = {};
1178
+ explorers.forEach((explorer) => {
1179
+ const url = ExplorerUrls[explorer];
1180
+ if (url) {
1181
+ urls[explorer] = `${url}/address/${address}`;
1182
+ }
1183
+ });
1184
+ return urls;
1185
+ }
1186
+ getBlockUrls(blockNumber) {
1187
+ const explorers = this.getAllExplorers();
1188
+ const urls = {};
1189
+ explorers.forEach((explorer) => {
1190
+ const url = ExplorerUrls[explorer];
1191
+ if (url) {
1192
+ urls[explorer] = `${url}/block/${blockNumber}`;
1193
+ }
1194
+ });
1195
+ return urls;
1196
+ }
724
1197
  };
725
1198
 
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()
1199
+ // src/chains/common.ts
1200
+ var createEvmAdapter = (chainName, chainPrefix, chainInfos) => {
1201
+ return (config, fallback) => {
1202
+ if (!fallback) throw new Error(`${chainName} adapter requires a fallback adapter`);
1203
+ return {
1204
+ chain: chainName,
1205
+ chainInfo: chainInfos[config.env],
1206
+ prefix: chainPrefix,
1207
+ builder: () => fallback.builder(),
1208
+ executor: new WarpEvmExecutor(config, chainInfos[config.env]),
1209
+ results: new WarpEvmResults(config, chainInfos[config.env]),
1210
+ serializer: new WarpEvmSerializer(),
1211
+ registry: fallback.registry,
1212
+ explorer: new WarpEvmExplorer(chainInfos[config.env], config),
1213
+ abiBuilder: () => fallback.abiBuilder(),
1214
+ brandBuilder: () => fallback.brandBuilder(),
1215
+ dataLoader: new WarpEvmDataLoader(config, chainInfos[config.env])
1216
+ };
740
1217
  };
741
1218
  };
1219
+
1220
+ // src/chains/arbitrum.ts
1221
+ var NativeTokenArb = {
1222
+ chain: WarpChainName.Arbitrum,
1223
+ identifier: "ARB",
1224
+ name: "ARB",
1225
+ decimals: 18,
1226
+ logoUrl: "https://vleap.ai/images/tokens/arb.svg"
1227
+ };
1228
+ var getArbitrumAdapter = createEvmAdapter(WarpChainName.Arbitrum, "arb", {
1229
+ mainnet: {
1230
+ name: WarpChainName.Arbitrum,
1231
+ displayName: "Arbitrum",
1232
+ chainId: "42161",
1233
+ blockTime: 1e3,
1234
+ addressHrp: "0x",
1235
+ defaultApiUrl: "https://arb1.arbitrum.io/rpc",
1236
+ nativeToken: NativeTokenArb
1237
+ },
1238
+ testnet: {
1239
+ name: WarpChainName.Arbitrum,
1240
+ displayName: "Arbitrum Sepolia",
1241
+ chainId: "421614",
1242
+ blockTime: 1e3,
1243
+ addressHrp: "0x",
1244
+ defaultApiUrl: "https://sepolia-rollup.arbitrum.io/rpc",
1245
+ nativeToken: NativeTokenArb
1246
+ },
1247
+ devnet: {
1248
+ name: WarpChainName.Arbitrum,
1249
+ displayName: "Arbitrum Sepolia",
1250
+ chainId: "421614",
1251
+ blockTime: 1e3,
1252
+ addressHrp: "0x",
1253
+ defaultApiUrl: "https://sepolia-rollup.arbitrum.io/rpc",
1254
+ nativeToken: NativeTokenArb
1255
+ }
1256
+ });
1257
+
1258
+ // src/chains/base.ts
1259
+ import { WarpChainName as WarpChainName2 } from "@vleap/warps";
1260
+ var NativeTokenBase = {
1261
+ chain: WarpChainName2.Base,
1262
+ identifier: "ETH",
1263
+ name: "ETH",
1264
+ decimals: 18,
1265
+ logoUrl: "https://vleap.ai/images/tokens/eth.svg"
1266
+ };
1267
+ var getBaseAdapter = createEvmAdapter(WarpChainName2.Base, "base", {
1268
+ mainnet: {
1269
+ name: WarpChainName2.Base,
1270
+ displayName: "Base",
1271
+ chainId: "8453",
1272
+ blockTime: 2e3,
1273
+ addressHrp: "0x",
1274
+ defaultApiUrl: "https://mainnet.base.org",
1275
+ nativeToken: NativeTokenBase
1276
+ },
1277
+ testnet: {
1278
+ name: WarpChainName2.Base,
1279
+ displayName: "Base Sepolia",
1280
+ chainId: "84532",
1281
+ blockTime: 2e3,
1282
+ addressHrp: "0x",
1283
+ defaultApiUrl: "https://sepolia.base.org",
1284
+ nativeToken: NativeTokenBase
1285
+ },
1286
+ devnet: {
1287
+ name: WarpChainName2.Base,
1288
+ displayName: "Base Sepolia",
1289
+ chainId: "84532",
1290
+ blockTime: 2e3,
1291
+ addressHrp: "0x",
1292
+ defaultApiUrl: "https://sepolia.base.org",
1293
+ nativeToken: NativeTokenBase
1294
+ }
1295
+ });
1296
+
1297
+ // src/chains/combined.ts
1298
+ import { WarpChainName as WarpChainName4 } from "@vleap/warps";
1299
+
1300
+ // src/chains/ethereum.ts
1301
+ import { WarpChainName as WarpChainName3 } from "@vleap/warps";
1302
+ var NativeTokenEth = {
1303
+ chain: WarpChainName3.Ethereum,
1304
+ identifier: "ETH",
1305
+ name: "ETH",
1306
+ decimals: 18,
1307
+ logoUrl: "https://vleap.ai/images/tokens/eth.svg"
1308
+ };
1309
+ var getEthereumAdapter = createEvmAdapter(WarpChainName3.Ethereum, "eth", {
1310
+ mainnet: {
1311
+ name: WarpChainName3.Ethereum,
1312
+ displayName: "Ethereum Mainnet",
1313
+ chainId: "1",
1314
+ blockTime: 12e3,
1315
+ addressHrp: "0x",
1316
+ defaultApiUrl: "https://ethereum-rpc.publicnode.com",
1317
+ nativeToken: NativeTokenEth
1318
+ },
1319
+ testnet: {
1320
+ name: WarpChainName3.Ethereum,
1321
+ displayName: "Ethereum Sepolia",
1322
+ chainId: "11155111",
1323
+ blockTime: 12e3,
1324
+ addressHrp: "0x",
1325
+ defaultApiUrl: "https://ethereum-sepolia-rpc.publicnode.com",
1326
+ nativeToken: NativeTokenEth
1327
+ },
1328
+ devnet: {
1329
+ name: WarpChainName3.Ethereum,
1330
+ displayName: "Ethereum Sepolia",
1331
+ chainId: "11155111",
1332
+ blockTime: 12e3,
1333
+ addressHrp: "0x",
1334
+ defaultApiUrl: "https://ethereum-sepolia-rpc.publicnode.com",
1335
+ nativeToken: NativeTokenEth
1336
+ }
1337
+ });
1338
+
1339
+ // src/chains/combined.ts
1340
+ var getAllEvmAdapters = (config, fallback) => [
1341
+ getEthereumAdapter(config, fallback),
1342
+ getArbitrumAdapter(config, fallback),
1343
+ getBaseAdapter(config, fallback)
1344
+ ];
1345
+ var getAllEvmChainNames = () => [WarpChainName4.Ethereum, WarpChainName4.Base, WarpChainName4.Arbitrum];
742
1346
  export {
743
- EVM_CHAIN_CONFIGS,
744
- WarpEvmBuilder,
1347
+ ArbitrumExplorers,
1348
+ BaseExplorers,
1349
+ EthereumExplorers,
1350
+ EvmExplorers,
1351
+ EvmLogoService,
1352
+ ExplorerUrls,
1353
+ NativeTokenArb,
1354
+ NativeTokenBase,
1355
+ NativeTokenEth,
745
1356
  WarpEvmConstants,
1357
+ WarpEvmDataLoader,
746
1358
  WarpEvmExecutor,
747
1359
  WarpEvmExplorer,
748
1360
  WarpEvmResults,
749
1361
  WarpEvmSerializer,
750
- getEvmAdapter,
751
- getEvmApiUrl,
752
- getEvmBlockTime,
753
- getEvmChainConfig,
754
- getEvmChainId,
755
- getEvmExplorerUrl,
756
- getEvmNativeToken,
757
- getEvmRegistryAddress,
758
- getSupportedEnvironments,
759
- getSupportedEvmChains
1362
+ createEvmAdapter,
1363
+ getAllEvmAdapters,
1364
+ getAllEvmChainNames,
1365
+ getArbitrumAdapter,
1366
+ getBaseAdapter,
1367
+ getEthereumAdapter
760
1368
  };
761
1369
  //# sourceMappingURL=index.mjs.map