genlayer-js 0.4.8 → 0.6.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
 
2
2
 
3
+ ## 0.6.0 (2025-01-09)
4
+
5
+
6
+ ### Features
7
+
8
+ * add stateStatus in readContract ([#50](https://github.com/yeagerai/genlayer-js/issues/50)) ([a9bcf8d](https://github.com/yeagerai/genlayer-js/commit/a9bcf8d83890448b85282ceb0c33060a19ea4e9a))
9
+
10
+ ## 0.5.0 (2025-01-08)
11
+
12
+
13
+ ### Features
14
+
15
+ * add customtransport to use both wallet and local private keys ([#48](https://github.com/yeagerai/genlayer-js/issues/48)) ([905a123](https://github.com/yeagerai/genlayer-js/commit/905a12358c154e6ae865773b809952c8cc9c75b9))
16
+
3
17
  ## 0.4.8 (2024-12-18)
4
18
 
5
19
 
package/README.md CHANGED
@@ -52,6 +52,7 @@ const result = await client.readContract({
52
52
  address: contractAddress,
53
53
  functionName: 'get_complete_storage',
54
54
  args: []
55
+ stateStatus: "accepted",
55
56
  })
56
57
  ```
57
58
 
package/dist/index.cjs CHANGED
@@ -4,7 +4,7 @@
4
4
  var _chunkIINRDYKFcjs = require('./chunk-IINRDYKF.cjs');
5
5
 
6
6
 
7
- var _chunkYI62SDKVcjs = require('./chunk-YI62SDKV.cjs');
7
+ var _chunkX6WK4DK4cjs = require('./chunk-X6WK4DK4.cjs');
8
8
  require('./chunk-75ZPJI57.cjs');
9
9
 
10
10
  // src/client/client.ts
@@ -22,14 +22,14 @@ function accountActions(client) {
22
22
  params: [address, amount]
23
23
  });
24
24
  },
25
- getCurrentNonce: async ({ address }) => {
25
+ getCurrentNonce: async ({ address, block = "latest" }) => {
26
26
  const addressToUse = address || _optionalChain([client, 'access', _3 => _3.account, 'optionalAccess', _4 => _4.address]);
27
27
  if (!addressToUse) {
28
28
  throw new Error("No address provided and no account is connected");
29
29
  }
30
30
  return client.request({
31
31
  method: "eth_getTransactionCount",
32
- params: [addressToUse]
32
+ params: [addressToUse, block]
33
33
  });
34
34
  }
35
35
  };
@@ -76,7 +76,7 @@ function decodeImpl(data, index) {
76
76
  case BigInt(SPECIAL_ADDR): {
77
77
  const res = data.slice(index.i, index.i + 20);
78
78
  index.i += 20;
79
- return new (0, _chunkYI62SDKVcjs.Address)(res);
79
+ return new (0, _chunkX6WK4DK4cjs.Address)(res);
80
80
  }
81
81
  }
82
82
  const type = Number(cur & 0xffn) & (1 << BITS_IN_TYPE) - 1;
@@ -241,7 +241,7 @@ function encodeImpl(to, data) {
241
241
  }
242
242
  } else if (data instanceof Map) {
243
243
  encodeMap(to, data);
244
- } else if (data instanceof _chunkYI62SDKVcjs.Address) {
244
+ } else if (data instanceof _chunkX6WK4DK4cjs.Address) {
245
245
  to.push(SPECIAL_ADDR);
246
246
  for (const c of data.bytes) {
247
247
  to.push(c);
@@ -265,9 +265,6 @@ function encode(data) {
265
265
  function serialize(data) {
266
266
  return _viem.toRlp.call(void 0, data.map((param) => _viem.toHex.call(void 0, param)));
267
267
  }
268
- function encodeAndSerialize(data) {
269
- return serialize([encode(data)]);
270
- }
271
268
 
272
269
  // src/contracts/actions.ts
273
270
  var contractActions = (client) => {
@@ -290,12 +287,14 @@ var contractActions = (client) => {
290
287
  };
291
288
  var overrideContractActions = (client) => {
292
289
  client.readContract = async (args) => {
293
- const { account, address, functionName, args: params } = args;
294
- const encodedData = encodeAndSerialize({ method: functionName, args: params });
290
+ const { account, address, functionName, args: params, stateStatus = "ACCEPTED" /* ACCEPTED */ } = args;
291
+ const encodedData = [encode({ method: functionName, args: params }), stateStatus];
292
+ const serializedData = serialize(encodedData);
293
+ const senderAddress = _nullishCoalesce(_optionalChain([account, 'optionalAccess', _5 => _5.address]), () => ( _optionalChain([client, 'access', _6 => _6.account, 'optionalAccess', _7 => _7.address])));
295
294
  const requestParams = {
296
295
  to: address,
297
- from: _nullishCoalesce(_optionalChain([account, 'optionalAccess', _5 => _5.address]), () => ( _optionalChain([client, 'access', _6 => _6.account, 'optionalAccess', _7 => _7.address]))),
298
- data: encodedData
296
+ from: senderAddress,
297
+ data: serializedData
299
298
  };
300
299
  const result = await client.request({
301
300
  method: "eth_call",
@@ -313,12 +312,24 @@ var overrideContractActions = (client) => {
313
312
  const data = [encode({ method: functionName, args: params }), leaderOnly];
314
313
  const serializedData = serialize(data);
315
314
  const senderAccount = account || client.account;
315
+ if (_optionalChain([senderAccount, 'optionalAccess', _8 => _8.type]) !== "local") {
316
+ const transaction = {
317
+ from: _optionalChain([senderAccount, 'optionalAccess', _9 => _9.address]),
318
+ to: address,
319
+ data: serializedData,
320
+ value: `0x${value.toString(16)}`
321
+ };
322
+ return await client.request({
323
+ method: "eth_sendTransaction",
324
+ params: [transaction]
325
+ });
326
+ }
316
327
  if (!senderAccount) {
317
328
  throw new Error(
318
329
  "No account set. Configure the client with an account or pass an account to this function."
319
330
  );
320
331
  }
321
- if (!_optionalChain([senderAccount, 'optionalAccess', _8 => _8.signTransaction])) {
332
+ if (!_optionalChain([senderAccount, 'optionalAccess', _10 => _10.signTransaction])) {
322
333
  throw new Error("Account does not support signTransaction");
323
334
  }
324
335
  const nonce = await client.getCurrentNonce({ address: senderAccount.address });
@@ -329,23 +340,34 @@ var overrideContractActions = (client) => {
329
340
  type: "legacy",
330
341
  nonce
331
342
  });
332
- const result = await client.request({
343
+ return await client.request({
333
344
  method: "eth_sendRawTransaction",
334
345
  params: [signedTransaction]
335
346
  });
336
- return result;
337
347
  };
338
348
  client.deployContract = async (args) => {
339
349
  const { account, code, args: constructorArgs, leaderOnly = false } = args;
340
350
  const data = [code, encode({ args: constructorArgs }), leaderOnly];
341
351
  const serializedData = serialize(data);
342
352
  const senderAccount = account || client.account;
353
+ if (_optionalChain([senderAccount, 'optionalAccess', _11 => _11.type]) !== "local") {
354
+ const transaction = {
355
+ from: _optionalChain([senderAccount, 'optionalAccess', _12 => _12.address]),
356
+ to: null,
357
+ data: serializedData,
358
+ value: "0x0"
359
+ };
360
+ return await client.request({
361
+ method: "eth_sendTransaction",
362
+ params: [transaction]
363
+ });
364
+ }
343
365
  if (!senderAccount) {
344
366
  throw new Error(
345
367
  "No account set. Configure the client with an account or pass an account to this function."
346
368
  );
347
369
  }
348
- if (!_optionalChain([senderAccount, 'optionalAccess', _9 => _9.signTransaction])) {
370
+ if (!_optionalChain([senderAccount, 'optionalAccess', _13 => _13.signTransaction])) {
349
371
  throw new Error("Account does not support signTransaction");
350
372
  }
351
373
  const nonce = await client.getCurrentNonce({ address: senderAccount.address });
@@ -354,11 +376,10 @@ var overrideContractActions = (client) => {
354
376
  type: "legacy",
355
377
  nonce
356
378
  });
357
- const result = await client.request({
379
+ return await client.request({
358
380
  method: "eth_sendRawTransaction",
359
381
  params: [signedTransaction]
360
382
  });
361
- return result;
362
383
  };
363
384
  return client;
364
385
  };
@@ -406,13 +427,48 @@ var transactionActions = (client) => ({
406
427
  var createClient = (config = { chain: _chunkIINRDYKFcjs.simulator }) => {
407
428
  const chainConfig = config.chain || _chunkIINRDYKFcjs.simulator;
408
429
  const rpcUrl = config.endpoint || chainConfig.rpcUrls.default.http[0];
430
+ const isAddress = typeof config.account !== "object";
431
+ const customTransport = {
432
+ async request({ method, params }) {
433
+ if (method.startsWith("eth_") && isAddress) {
434
+ try {
435
+ return await _optionalChain([window, 'access', _14 => _14.ethereum, 'optionalAccess', _15 => _15.request, 'call', _16 => _16({ method, params })]);
436
+ } catch (err) {
437
+ console.warn(`Error using window.ethereum for method ${method}:`, err);
438
+ throw err;
439
+ }
440
+ } else {
441
+ try {
442
+ const response = await fetch(rpcUrl, {
443
+ method: "POST",
444
+ headers: {
445
+ "Content-Type": "application/json"
446
+ },
447
+ body: JSON.stringify({
448
+ jsonrpc: "2.0",
449
+ id: Date.now(),
450
+ method,
451
+ params
452
+ })
453
+ });
454
+ const data = await response.json();
455
+ if (data.error) {
456
+ throw new Error(data.error.message);
457
+ }
458
+ return data.result;
459
+ } catch (err) {
460
+ console.error(`Error fetching ${method} from GenLayer RPC:`, err);
461
+ throw err;
462
+ }
463
+ }
464
+ }
465
+ };
409
466
  const baseClient = _viem.createClient.call(void 0, {
410
467
  chain: chainConfig,
411
- transport: _viem.http.call(void 0, rpcUrl),
468
+ transport: _viem.custom.call(void 0, customTransport),
412
469
  ...config.account ? { account: config.account } : {}
413
470
  }).extend(_viem.publicActions).extend((client) => accountActions(client)).extend((client) => transactionActions(client)).extend((client) => contractActions(client));
414
- const genLayerClient = overrideContractActions(baseClient);
415
- return genLayerClient;
471
+ return overrideContractActions(baseClient);
416
472
  };
417
473
 
418
474
  // src/accounts/account.ts
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as viem from 'viem';
2
- import { Account } from 'viem';
2
+ import { Account, Address } from 'viem';
3
3
  import { S as SimulatorChain } from './chains-BV4Glo-M.cjs';
4
4
  import { GenLayerClient } from './types/index.cjs';
5
5
  import * as abitype from 'abitype';
@@ -29,7 +29,7 @@ interface ClientConfig {
29
29
  };
30
30
  };
31
31
  endpoint?: string;
32
- account?: Account;
32
+ account?: Account | Address;
33
33
  }
34
34
  declare const createClient: (config?: ClientConfig) => GenLayerClient<SimulatorChain>;
35
35
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as viem from 'viem';
2
- import { Account } from 'viem';
2
+ import { Account, Address } from 'viem';
3
3
  import { S as SimulatorChain } from './chains-BV4Glo-M.js';
4
4
  import { GenLayerClient } from './types/index.js';
5
5
  import * as abitype from 'abitype';
@@ -29,7 +29,7 @@ interface ClientConfig {
29
29
  };
30
30
  };
31
31
  endpoint?: string;
32
- account?: Account;
32
+ account?: Account | Address;
33
33
  }
34
34
  declare const createClient: (config?: ClientConfig) => GenLayerClient<SimulatorChain>;
35
35
 
package/dist/index.js CHANGED
@@ -4,11 +4,11 @@ import {
4
4
  } from "./chunk-3TYB36DW.js";
5
5
  import {
6
6
  Address
7
- } from "./chunk-M7SA3INM.js";
7
+ } from "./chunk-G7EQ6KPE.js";
8
8
  import "./chunk-MLKGABMK.js";
9
9
 
10
10
  // src/client/client.ts
11
- import { createClient as createViemClient, http, publicActions } from "viem";
11
+ import { createClient as createViemClient, publicActions, custom } from "viem";
12
12
 
13
13
  // src/accounts/actions.ts
14
14
  function accountActions(client) {
@@ -22,14 +22,14 @@ function accountActions(client) {
22
22
  params: [address, amount]
23
23
  });
24
24
  },
25
- getCurrentNonce: async ({ address }) => {
25
+ getCurrentNonce: async ({ address, block = "latest" }) => {
26
26
  const addressToUse = address || client.account?.address;
27
27
  if (!addressToUse) {
28
28
  throw new Error("No address provided and no account is connected");
29
29
  }
30
30
  return client.request({
31
31
  method: "eth_getTransactionCount",
32
- params: [addressToUse]
32
+ params: [addressToUse, block]
33
33
  });
34
34
  }
35
35
  };
@@ -265,9 +265,6 @@ function encode(data) {
265
265
  function serialize(data) {
266
266
  return toRlp(data.map((param) => toHex(param)));
267
267
  }
268
- function encodeAndSerialize(data) {
269
- return serialize([encode(data)]);
270
- }
271
268
 
272
269
  // src/contracts/actions.ts
273
270
  var contractActions = (client) => {
@@ -290,12 +287,14 @@ var contractActions = (client) => {
290
287
  };
291
288
  var overrideContractActions = (client) => {
292
289
  client.readContract = async (args) => {
293
- const { account, address, functionName, args: params } = args;
294
- const encodedData = encodeAndSerialize({ method: functionName, args: params });
290
+ const { account, address, functionName, args: params, stateStatus = "ACCEPTED" /* ACCEPTED */ } = args;
291
+ const encodedData = [encode({ method: functionName, args: params }), stateStatus];
292
+ const serializedData = serialize(encodedData);
293
+ const senderAddress = account?.address ?? client.account?.address;
295
294
  const requestParams = {
296
295
  to: address,
297
- from: account?.address ?? client.account?.address,
298
- data: encodedData
296
+ from: senderAddress,
297
+ data: serializedData
299
298
  };
300
299
  const result = await client.request({
301
300
  method: "eth_call",
@@ -313,6 +312,18 @@ var overrideContractActions = (client) => {
313
312
  const data = [encode({ method: functionName, args: params }), leaderOnly];
314
313
  const serializedData = serialize(data);
315
314
  const senderAccount = account || client.account;
315
+ if (senderAccount?.type !== "local") {
316
+ const transaction = {
317
+ from: senderAccount?.address,
318
+ to: address,
319
+ data: serializedData,
320
+ value: `0x${value.toString(16)}`
321
+ };
322
+ return await client.request({
323
+ method: "eth_sendTransaction",
324
+ params: [transaction]
325
+ });
326
+ }
316
327
  if (!senderAccount) {
317
328
  throw new Error(
318
329
  "No account set. Configure the client with an account or pass an account to this function."
@@ -329,17 +340,28 @@ var overrideContractActions = (client) => {
329
340
  type: "legacy",
330
341
  nonce
331
342
  });
332
- const result = await client.request({
343
+ return await client.request({
333
344
  method: "eth_sendRawTransaction",
334
345
  params: [signedTransaction]
335
346
  });
336
- return result;
337
347
  };
338
348
  client.deployContract = async (args) => {
339
349
  const { account, code, args: constructorArgs, leaderOnly = false } = args;
340
350
  const data = [code, encode({ args: constructorArgs }), leaderOnly];
341
351
  const serializedData = serialize(data);
342
352
  const senderAccount = account || client.account;
353
+ if (senderAccount?.type !== "local") {
354
+ const transaction = {
355
+ from: senderAccount?.address,
356
+ to: null,
357
+ data: serializedData,
358
+ value: "0x0"
359
+ };
360
+ return await client.request({
361
+ method: "eth_sendTransaction",
362
+ params: [transaction]
363
+ });
364
+ }
343
365
  if (!senderAccount) {
344
366
  throw new Error(
345
367
  "No account set. Configure the client with an account or pass an account to this function."
@@ -354,11 +376,10 @@ var overrideContractActions = (client) => {
354
376
  type: "legacy",
355
377
  nonce
356
378
  });
357
- const result = await client.request({
379
+ return await client.request({
358
380
  method: "eth_sendRawTransaction",
359
381
  params: [signedTransaction]
360
382
  });
361
- return result;
362
383
  };
363
384
  return client;
364
385
  };
@@ -406,13 +427,48 @@ var transactionActions = (client) => ({
406
427
  var createClient = (config = { chain: simulator }) => {
407
428
  const chainConfig = config.chain || simulator;
408
429
  const rpcUrl = config.endpoint || chainConfig.rpcUrls.default.http[0];
430
+ const isAddress = typeof config.account !== "object";
431
+ const customTransport = {
432
+ async request({ method, params }) {
433
+ if (method.startsWith("eth_") && isAddress) {
434
+ try {
435
+ return await window.ethereum?.request({ method, params });
436
+ } catch (err) {
437
+ console.warn(`Error using window.ethereum for method ${method}:`, err);
438
+ throw err;
439
+ }
440
+ } else {
441
+ try {
442
+ const response = await fetch(rpcUrl, {
443
+ method: "POST",
444
+ headers: {
445
+ "Content-Type": "application/json"
446
+ },
447
+ body: JSON.stringify({
448
+ jsonrpc: "2.0",
449
+ id: Date.now(),
450
+ method,
451
+ params
452
+ })
453
+ });
454
+ const data = await response.json();
455
+ if (data.error) {
456
+ throw new Error(data.error.message);
457
+ }
458
+ return data.result;
459
+ } catch (err) {
460
+ console.error(`Error fetching ${method} from GenLayer RPC:`, err);
461
+ throw err;
462
+ }
463
+ }
464
+ }
465
+ };
409
466
  const baseClient = createViemClient({
410
467
  chain: chainConfig,
411
- transport: http(rpcUrl),
468
+ transport: custom(customTransport),
412
469
  ...config.account ? { account: config.account } : {}
413
470
  }).extend(publicActions).extend((client) => accountActions(client)).extend((client) => transactionActions(client)).extend((client) => contractActions(client));
414
- const genLayerClient = overrideContractActions(baseClient);
415
- return genLayerClient;
471
+ return overrideContractActions(baseClient);
416
472
  };
417
473
 
418
474
  // src/accounts/account.ts
@@ -1,7 +1,7 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkYI62SDKVcjs = require('../chunk-YI62SDKV.cjs');
3
+ var _chunkX6WK4DK4cjs = require('../chunk-X6WK4DK4.cjs');
4
4
  require('../chunk-75ZPJI57.cjs');
5
5
 
6
6
 
7
- exports.TransactionStatus = _chunkYI62SDKVcjs.TransactionStatus;
7
+ exports.TransactionStatus = _chunkX6WK4DK4cjs.TransactionStatus;
@@ -118,7 +118,7 @@ type GenLayerMethod = {
118
118
  params: [address: string, filter?: "all" | "from" | "to"];
119
119
  } | {
120
120
  method: "eth_getTransactionCount";
121
- params: [address: string];
121
+ params: [address: string, block: string];
122
122
  };
123
123
  type GenLayerClient<TSimulatorChain extends SimulatorChain> = Omit<Client<Transport, TSimulatorChain>, "transport" | "getTransaction" | "readContract"> & Omit<PublicActions<Transport, TSimulatorChain>, "readContract" | "getTransaction" | "waitForTransactionReceipt"> & {
124
124
  request: Client<Transport, TSimulatorChain>["request"] & {
@@ -131,6 +131,7 @@ type GenLayerClient<TSimulatorChain extends SimulatorChain> = Omit<Client<Transp
131
131
  address: Address$1;
132
132
  functionName: string;
133
133
  args: CalldataEncodable[];
134
+ stateStatus?: TransactionStatus;
134
135
  }) => Promise<unknown>;
135
136
  writeContract: (args: {
136
137
  account?: Account;
@@ -118,7 +118,7 @@ type GenLayerMethod = {
118
118
  params: [address: string, filter?: "all" | "from" | "to"];
119
119
  } | {
120
120
  method: "eth_getTransactionCount";
121
- params: [address: string];
121
+ params: [address: string, block: string];
122
122
  };
123
123
  type GenLayerClient<TSimulatorChain extends SimulatorChain> = Omit<Client<Transport, TSimulatorChain>, "transport" | "getTransaction" | "readContract"> & Omit<PublicActions<Transport, TSimulatorChain>, "readContract" | "getTransaction" | "waitForTransactionReceipt"> & {
124
124
  request: Client<Transport, TSimulatorChain>["request"] & {
@@ -131,6 +131,7 @@ type GenLayerClient<TSimulatorChain extends SimulatorChain> = Omit<Client<Transp
131
131
  address: Address$1;
132
132
  functionName: string;
133
133
  args: CalldataEncodable[];
134
+ stateStatus?: TransactionStatus;
134
135
  }) => Promise<unknown>;
135
136
  writeContract: (args: {
136
137
  account?: Account;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TransactionStatus
3
- } from "../chunk-M7SA3INM.js";
3
+ } from "../chunk-G7EQ6KPE.js";
4
4
  import "../chunk-MLKGABMK.js";
5
5
  export {
6
6
  TransactionStatus
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "genlayer-js",
3
3
  "type": "module",
4
- "version": "0.4.8",
4
+ "version": "0.6.0",
5
5
  "description": "GenLayer JavaScript SDK",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -13,16 +13,15 @@ export function accountActions(client: GenLayerClient<SimulatorChain>) {
13
13
  params: [address, amount],
14
14
  }) as Promise<TransactionHash>;
15
15
  },
16
- getCurrentNonce: async ({address}: {address: string}): Promise<number> => {
16
+ getCurrentNonce: async ({address, block = 'latest'}: {address: string, block?: string}): Promise<number> => {
17
17
  const addressToUse = address || client.account?.address;
18
18
 
19
19
  if (!addressToUse) {
20
20
  throw new Error("No address provided and no account is connected");
21
21
  }
22
-
23
22
  return client.request({
24
23
  method: "eth_getTransactionCount",
25
- params: [addressToUse],
24
+ params: [addressToUse, block],
26
25
  }) as Promise<number>;
27
26
  },
28
27
  };
@@ -1,4 +1,4 @@
1
- import {Account, createClient as createViemClient, http, publicActions} from "viem";
1
+ import {Account, createClient as createViemClient, publicActions, custom, Address} from "viem";
2
2
  import {simulator} from "../chains/simulator";
3
3
  import {accountActions} from "../accounts/actions";
4
4
  import {contractActions, overrideContractActions} from "../contracts/actions";
@@ -10,24 +10,62 @@ interface ClientConfig {
10
10
  chain?: {
11
11
  id: number;
12
12
  name: string;
13
- rpcUrls: {default: {http: readonly string[]}};
14
- nativeCurrency: {name: string; symbol: string; decimals: number};
15
- blockExplorers?: {default: {name: string; url: string}};
13
+ rpcUrls: { default: { http: readonly string[] } };
14
+ nativeCurrency: { name: string; symbol: string; decimals: number };
15
+ blockExplorers?: { default: { name: string; url: string } };
16
16
  };
17
- endpoint?: string; // Optional: Custom RPC endpoint override
18
- account?: Account;
17
+ endpoint?: string; // Custom RPC endpoint
18
+ account?: Account | Address;
19
19
  }
20
20
 
21
- // Extend Viem client to work with GenLayer-specific chains (simulator, testnet, etc.)
22
- export const createClient = (config: ClientConfig = {chain: simulator}) => {
23
- // Determine the RPC URL based on the provided configuration or default to the simulator's RPC UR
21
+ export const createClient = (config: ClientConfig = { chain: simulator }) => {
24
22
  const chainConfig = config.chain || simulator;
25
23
  const rpcUrl = config.endpoint || chainConfig.rpcUrls.default.http[0];
24
+ const isAddress = typeof config.account !== "object";
25
+
26
+ const customTransport = {
27
+ async request({method, params}: {method: string; params: any[]}) {
28
+ if (method.startsWith('eth_') && isAddress) {
29
+ try {
30
+ return await window.ethereum?.request({method, params});
31
+ } catch (err) {
32
+ console.warn(`Error using window.ethereum for method ${method}:`, err);
33
+ throw err;
34
+ }
35
+ } else {
36
+ try {
37
+ const response = await fetch(rpcUrl, {
38
+ method: 'POST',
39
+ headers: {
40
+ 'Content-Type': 'application/json',
41
+ },
42
+ body: JSON.stringify({
43
+ jsonrpc: '2.0',
44
+ id: Date.now(),
45
+ method,
46
+ params,
47
+ }),
48
+ });
49
+
50
+ const data = await response.json();
51
+
52
+ if (data.error) {
53
+ throw new Error(data.error.message);
54
+ }
55
+
56
+ return data.result;
57
+ } catch (err) {
58
+ console.error(`Error fetching ${method} from GenLayer RPC:`, err);
59
+ throw err;
60
+ }
61
+ }
62
+ },
63
+ }
64
+
26
65
 
27
- // Create a Viem client connected to the GenLayer Simulator (or custom chain)
28
66
  const baseClient = createViemClient({
29
67
  chain: chainConfig,
30
- transport: http(rpcUrl),
68
+ transport: custom(customTransport),
31
69
  ...(config.account ? {account: config.account} : {}),
32
70
  })
33
71
  .extend(publicActions)
@@ -35,7 +73,7 @@ export const createClient = (config: ClientConfig = {chain: simulator}) => {
35
73
  .extend(client => transactionActions(client as unknown as GenLayerClient<SimulatorChain>))
36
74
  .extend(client => contractActions(client as unknown as GenLayerClient<SimulatorChain>));
37
75
 
38
- const genLayerClient = overrideContractActions(baseClient as unknown as GenLayerClient<SimulatorChain>);
76
+ return overrideContractActions(baseClient as unknown as GenLayerClient<SimulatorChain>);
39
77
 
40
- return genLayerClient;
41
78
  };
79
+
@@ -1,6 +1,14 @@
1
1
  import {decode} from "@/abi/calldata/decoder";
2
- import {encode, serialize, encodeAndSerialize} from "@/abi/calldata/encoder";
3
- import {Account, ContractSchema, SimulatorChain, GenLayerClient, CalldataEncodable, Address} from "@/types";
2
+ import {encode, serialize} from "@/abi/calldata/encoder";
3
+ import {
4
+ Account,
5
+ ContractSchema,
6
+ SimulatorChain,
7
+ GenLayerClient,
8
+ CalldataEncodable,
9
+ Address,
10
+ TransactionStatus,
11
+ } from "@/types";
4
12
 
5
13
  export const contractActions = (client: GenLayerClient<SimulatorChain>) => {
6
14
  return {
@@ -27,14 +35,18 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
27
35
  address: Address;
28
36
  functionName: string;
29
37
  args: CalldataEncodable[];
38
+ stateStatus?: TransactionStatus;
30
39
  }): Promise<unknown> => {
31
- const {account, address, functionName, args: params} = args;
32
- const encodedData = encodeAndSerialize({method: functionName, args: params});
40
+ const {account, address, functionName, args: params, stateStatus = TransactionStatus.ACCEPTED} = args;
41
+ const encodedData = [encode({method: functionName, args: params}), stateStatus];
42
+ const serializedData = serialize(encodedData);
43
+
44
+ const senderAddress = account?.address ?? client.account?.address;
33
45
 
34
46
  const requestParams = {
35
47
  to: address,
36
- from: account?.address ?? client.account?.address,
37
- data: encodedData,
48
+ from: senderAddress,
49
+ data: serializedData,
38
50
  };
39
51
  const result = await client.request({
40
52
  method: "eth_call",
@@ -60,8 +72,22 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
60
72
  const {account, address, functionName, args: params, value = 0n, leaderOnly = false} = args;
61
73
  const data = [encode({method: functionName, args: params}), leaderOnly];
62
74
  const serializedData = serialize(data);
63
-
64
75
  const senderAccount = account || client.account;
76
+
77
+ if (senderAccount?.type !== "local") {
78
+ const transaction = {
79
+ from: senderAccount?.address,
80
+ to: address,
81
+ data: serializedData,
82
+ value: `0x${value.toString(16)}`,
83
+ };
84
+
85
+ return await client.request({
86
+ method: "eth_sendTransaction",
87
+ params: [transaction as any],
88
+ });
89
+ }
90
+
65
91
  if (!senderAccount) {
66
92
  throw new Error(
67
93
  "No account set. Configure the client with an account or pass an account to this function.",
@@ -81,11 +107,11 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
81
107
  type: "legacy",
82
108
  nonce,
83
109
  });
84
- const result = await client.request({
110
+
111
+ return await client.request({
85
112
  method: "eth_sendRawTransaction",
86
113
  params: [signedTransaction],
87
114
  });
88
- return result;
89
115
  };
90
116
 
91
117
  client.deployContract = async (args: {
@@ -97,8 +123,22 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
97
123
  const {account, code, args: constructorArgs, leaderOnly = false} = args;
98
124
  const data = [code, encode({args: constructorArgs}), leaderOnly];
99
125
  const serializedData = serialize(data);
100
-
101
126
  const senderAccount = account || client.account;
127
+
128
+ if (senderAccount?.type !== "local") {
129
+ const transaction = {
130
+ from: senderAccount?.address,
131
+ to: null,
132
+ data: serializedData,
133
+ value: "0x0",
134
+ };
135
+
136
+ return await client.request({
137
+ method: "eth_sendTransaction",
138
+ params: [transaction as any],
139
+ });
140
+ }
141
+
102
142
  if (!senderAccount) {
103
143
  throw new Error(
104
144
  "No account set. Configure the client with an account or pass an account to this function.",
@@ -117,11 +157,10 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
117
157
  nonce,
118
158
  });
119
159
 
120
- const result = await client.request({
160
+ return await client.request({
121
161
  method: "eth_sendRawTransaction",
122
162
  params: [signedTransaction],
123
163
  });
124
- return result;
125
164
  };
126
165
 
127
166
  return client;
@@ -0,0 +1,7 @@
1
+ // global.d.ts
2
+ interface Window {
3
+ ethereum?: {
4
+ isMetaMask?: boolean;
5
+ request: (args: { method: string; params?: unknown[] }) => Promise<unknown>;
6
+ };
7
+ }
@@ -13,7 +13,7 @@ export type GenLayerMethod =
13
13
  | {method: "gen_getContractSchema"; params: [address: string]}
14
14
  | {method: "gen_getContractSchemaForCode"; params: [contractCode: string]}
15
15
  | {method: "sim_getTransactionsForAddress"; params: [address: string, filter?: "all" | "from" | "to"]}
16
- | {method: "eth_getTransactionCount"; params: [address: string]};
16
+ | {method: "eth_getTransactionCount"; params: [address: string, block: string]};
17
17
 
18
18
  /*
19
19
  Take all the properties from PublicActions<Transport, TSimulatorChain>
@@ -39,6 +39,7 @@ export type GenLayerClient<TSimulatorChain extends SimulatorChain> = Omit<
39
39
  address: Address;
40
40
  functionName: string;
41
41
  args: CalldataEncodable[];
42
+ stateStatus?: TransactionStatus;
42
43
  }) => Promise<unknown>;
43
44
  writeContract: (args: {
44
45
  account?: Account;
@@ -4,6 +4,7 @@ import {simulator} from "../src/chains/simulator";
4
4
  import {Address} from "../src/types/accounts";
5
5
  import {createAccount, generatePrivateKey} from "../src/accounts/account";
6
6
  import {vi} from "vitest";
7
+ import {TransactionStatus} from "../src/types/transactions";
7
8
 
8
9
  describe("Client Creation", () => {
9
10
  it("should create a client for the simulator", () => {
@@ -18,7 +19,7 @@ describe("Client Overrides", () => {
18
19
  const account = createAccount(generatePrivateKey());
19
20
  const client = createClient({
20
21
  chain: simulator,
21
- account,
22
+ account: account,
22
23
  });
23
24
 
24
25
  // Mock the client.request method
@@ -29,6 +30,7 @@ describe("Client Overrides", () => {
29
30
  address: contractAddress as Address,
30
31
  functionName: "testFunction",
31
32
  args: ["arg1", "arg2"],
33
+ stateStatus: TransactionStatus.ACCEPTED,
32
34
  });
33
35
 
34
36
  expect(client.request).toHaveBeenCalledWith({
@@ -62,6 +64,7 @@ describe("Client Overrides", () => {
62
64
  address: contractAddress as Address,
63
65
  functionName: "testFunction",
64
66
  args: ["arg1", "arg2"],
67
+ stateStatus: TransactionStatus.ACCEPTED,
65
68
  });
66
69
 
67
70
  expect(client.request).toHaveBeenCalledWith({
@@ -76,4 +79,33 @@ describe("Client Overrides", () => {
76
79
  ],
77
80
  });
78
81
  });
82
+ it("should override client account if address is provided", async () => {
83
+ const account = "0x65e03a3e916CF1dC92d3C8E8186a89CfAB0D2bc2";
84
+ const client = createClient({
85
+ chain: simulator,
86
+ account,
87
+ });
88
+
89
+ // Mock the client.request method
90
+ vi.spyOn(client, "request").mockResolvedValue(undefined);
91
+
92
+ const contractAddress = "0x1234567890123456789012345678901234567890";
93
+ await client.readContract({
94
+ address: contractAddress as Address,
95
+ functionName: "testFunction",
96
+ args: ["arg1", "arg2"],
97
+ });
98
+
99
+ expect(client.request).toHaveBeenCalledWith({
100
+ method: "eth_call",
101
+ params: [
102
+ {
103
+ to: contractAddress,
104
+ from: account,
105
+ data: expect.any(String),
106
+ },
107
+ "latest",
108
+ ],
109
+ });
110
+ });
79
111
  });
package/tsconfig.json CHANGED
@@ -115,5 +115,5 @@
115
115
  // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
116
116
  "skipLibCheck": true /* Skip type checking all .d.ts files. */
117
117
  },
118
- "include": ["src/**/*", "tests/**/*"]
118
+ "include": ["src/**/*", "tests/**/*", "src/global.d.ts"]
119
119
  }
File without changes
File without changes