genlayer-js 0.4.7 → 0.5.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.5.0 (2025-01-08)
4
+
5
+
6
+ ### Features
7
+
8
+ * 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))
9
+
10
+ ## 0.4.8 (2024-12-18)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * added GenVM decoder to readContract method ([#42](https://github.com/yeagerai/genlayer-js/issues/42)) ([096d36d](https://github.com/yeagerai/genlayer-js/commit/096d36de06d3f4d341f6532ddead694c1882651d))
16
+
3
17
  ## 0.4.7 (2024-12-03)
4
18
 
5
19
  ## 0.4.6 (2024-12-02)
package/dist/index.cjs CHANGED
@@ -22,21 +22,20 @@ 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
  };
36
36
  }
37
37
 
38
- // src/abi/calldata/encoder.ts
39
-
38
+ // src/abi/calldata/consts.ts
40
39
  var BITS_IN_TYPE = 3;
41
40
  var TYPE_SPECIAL = 0;
42
41
  var TYPE_PINT = 1;
@@ -49,6 +48,92 @@ var SPECIAL_NULL = 0 << BITS_IN_TYPE | TYPE_SPECIAL;
49
48
  var SPECIAL_FALSE = 1 << BITS_IN_TYPE | TYPE_SPECIAL;
50
49
  var SPECIAL_TRUE = 2 << BITS_IN_TYPE | TYPE_SPECIAL;
51
50
  var SPECIAL_ADDR = 3 << BITS_IN_TYPE | TYPE_SPECIAL;
51
+
52
+ // src/abi/calldata/decoder.ts
53
+ function readULeb128(data, index) {
54
+ let res = 0n;
55
+ let accum = 0n;
56
+ let shouldContinue = true;
57
+ while (shouldContinue) {
58
+ const byte = data[index.i];
59
+ index.i++;
60
+ const rest = byte & 127;
61
+ res += BigInt(rest) * (1n << accum);
62
+ accum += 7n;
63
+ shouldContinue = byte >= 128;
64
+ }
65
+ return res;
66
+ }
67
+ function decodeImpl(data, index) {
68
+ const cur = readULeb128(data, index);
69
+ switch (cur) {
70
+ case BigInt(SPECIAL_NULL):
71
+ return null;
72
+ case BigInt(SPECIAL_TRUE):
73
+ return true;
74
+ case BigInt(SPECIAL_FALSE):
75
+ return false;
76
+ case BigInt(SPECIAL_ADDR): {
77
+ const res = data.slice(index.i, index.i + 20);
78
+ index.i += 20;
79
+ return new (0, _chunkYI62SDKVcjs.Address)(res);
80
+ }
81
+ }
82
+ const type = Number(cur & 0xffn) & (1 << BITS_IN_TYPE) - 1;
83
+ const rest = cur >> BigInt(BITS_IN_TYPE);
84
+ switch (type) {
85
+ case TYPE_BYTES: {
86
+ const ret = data.slice(index.i, index.i + Number(rest));
87
+ index.i += Number(rest);
88
+ return ret;
89
+ }
90
+ case TYPE_PINT:
91
+ return rest;
92
+ case TYPE_NINT:
93
+ return -1n - rest;
94
+ case TYPE_STR: {
95
+ const ret = data.slice(index.i, index.i + Number(rest));
96
+ index.i += Number(rest);
97
+ return new TextDecoder("utf-8").decode(ret);
98
+ }
99
+ case TYPE_ARR: {
100
+ const ret = [];
101
+ let elems = rest;
102
+ while (elems > 0) {
103
+ elems--;
104
+ ret.push(decodeImpl(data, index));
105
+ }
106
+ return ret;
107
+ }
108
+ case TYPE_MAP: {
109
+ const ret = /* @__PURE__ */ new Map();
110
+ let elems = rest;
111
+ while (elems > 0) {
112
+ elems--;
113
+ const strLen = Number(readULeb128(data, index));
114
+ const key = data.slice(index.i, index.i + strLen);
115
+ index.i += strLen;
116
+ const keyStr = new TextDecoder("utf-8").decode(key);
117
+ ret.set(keyStr, decodeImpl(data, index));
118
+ }
119
+ return ret;
120
+ }
121
+ default:
122
+ throw new Error(`can't decode type from ${type} rest is ${rest} at pos ${index.i}`);
123
+ }
124
+ }
125
+ function decode(data) {
126
+ const index = { i: 0 };
127
+ const res = decodeImpl(data, index);
128
+ if (index.i !== data.length) {
129
+ throw new Error("some data left");
130
+ }
131
+ return res;
132
+ }
133
+
134
+ // src/abi/calldata/encoder.ts
135
+
136
+
52
137
  function reportError(msg, data) {
53
138
  throw new Error(`invalid calldata input '${data}'`);
54
139
  }
@@ -162,10 +247,7 @@ function encodeImpl(to, data) {
162
247
  to.push(c);
163
248
  }
164
249
  } else if (Object.getPrototypeOf(data) === Object.prototype) {
165
- encodeMap(
166
- to,
167
- Object.keys(data).map((k) => [k, data[k]])
168
- );
250
+ encodeMap(to, Object.entries(data));
169
251
  } else {
170
252
  reportError("unknown object type", data);
171
253
  }
@@ -210,28 +292,46 @@ var overrideContractActions = (client) => {
210
292
  client.readContract = async (args) => {
211
293
  const { account, address, functionName, args: params } = args;
212
294
  const encodedData = encodeAndSerialize({ method: functionName, args: params });
295
+ let senderAddress = _nullishCoalesce(_optionalChain([account, 'optionalAccess', _5 => _5.address]), () => ( _optionalChain([client, 'access', _6 => _6.account, 'optionalAccess', _7 => _7.address])));
213
296
  const requestParams = {
214
297
  to: address,
215
- from: _nullishCoalesce(_optionalChain([account, 'optionalAccess', _5 => _5.address]), () => ( _optionalChain([client, 'access', _6 => _6.account, 'optionalAccess', _7 => _7.address]))),
298
+ from: senderAddress,
216
299
  data: encodedData
217
300
  };
218
301
  const result = await client.request({
219
302
  method: "eth_call",
220
303
  params: [requestParams, "latest"]
221
304
  });
222
- return result;
305
+ if (typeof result === "string") {
306
+ const val = Uint8Array.from(atob(result), (c) => c.charCodeAt(0));
307
+ return decode(val);
308
+ } else {
309
+ return "<unknown>";
310
+ }
223
311
  };
224
312
  client.writeContract = async (args) => {
225
313
  const { account, address, functionName, args: params, value = 0n, leaderOnly = false } = args;
226
314
  const data = [encode({ method: functionName, args: params }), leaderOnly];
227
315
  const serializedData = serialize(data);
228
316
  const senderAccount = account || client.account;
317
+ if (_optionalChain([senderAccount, 'optionalAccess', _8 => _8.type]) !== "local") {
318
+ const transaction = {
319
+ from: _optionalChain([senderAccount, 'optionalAccess', _9 => _9.address]),
320
+ to: address,
321
+ data: serializedData,
322
+ value: `0x${value.toString(16)}`
323
+ };
324
+ return await client.request({
325
+ method: "eth_sendTransaction",
326
+ params: [transaction]
327
+ });
328
+ }
229
329
  if (!senderAccount) {
230
330
  throw new Error(
231
331
  "No account set. Configure the client with an account or pass an account to this function."
232
332
  );
233
333
  }
234
- if (!_optionalChain([senderAccount, 'optionalAccess', _8 => _8.signTransaction])) {
334
+ if (!_optionalChain([senderAccount, 'optionalAccess', _10 => _10.signTransaction])) {
235
335
  throw new Error("Account does not support signTransaction");
236
336
  }
237
337
  const nonce = await client.getCurrentNonce({ address: senderAccount.address });
@@ -242,23 +342,34 @@ var overrideContractActions = (client) => {
242
342
  type: "legacy",
243
343
  nonce
244
344
  });
245
- const result = await client.request({
345
+ return await client.request({
246
346
  method: "eth_sendRawTransaction",
247
347
  params: [signedTransaction]
248
348
  });
249
- return result;
250
349
  };
251
350
  client.deployContract = async (args) => {
252
351
  const { account, code, args: constructorArgs, leaderOnly = false } = args;
253
352
  const data = [code, encode({ args: constructorArgs }), leaderOnly];
254
353
  const serializedData = serialize(data);
255
354
  const senderAccount = account || client.account;
355
+ if (_optionalChain([senderAccount, 'optionalAccess', _11 => _11.type]) !== "local") {
356
+ const transaction = {
357
+ from: _optionalChain([senderAccount, 'optionalAccess', _12 => _12.address]),
358
+ to: null,
359
+ data: serializedData,
360
+ value: "0x0"
361
+ };
362
+ return await client.request({
363
+ method: "eth_sendTransaction",
364
+ params: [transaction]
365
+ });
366
+ }
256
367
  if (!senderAccount) {
257
368
  throw new Error(
258
369
  "No account set. Configure the client with an account or pass an account to this function."
259
370
  );
260
371
  }
261
- if (!_optionalChain([senderAccount, 'optionalAccess', _9 => _9.signTransaction])) {
372
+ if (!_optionalChain([senderAccount, 'optionalAccess', _13 => _13.signTransaction])) {
262
373
  throw new Error("Account does not support signTransaction");
263
374
  }
264
375
  const nonce = await client.getCurrentNonce({ address: senderAccount.address });
@@ -267,11 +378,10 @@ var overrideContractActions = (client) => {
267
378
  type: "legacy",
268
379
  nonce
269
380
  });
270
- const result = await client.request({
381
+ return await client.request({
271
382
  method: "eth_sendRawTransaction",
272
383
  params: [signedTransaction]
273
384
  });
274
- return result;
275
385
  };
276
386
  return client;
277
387
  };
@@ -319,13 +429,48 @@ var transactionActions = (client) => ({
319
429
  var createClient = (config = { chain: _chunkIINRDYKFcjs.simulator }) => {
320
430
  const chainConfig = config.chain || _chunkIINRDYKFcjs.simulator;
321
431
  const rpcUrl = config.endpoint || chainConfig.rpcUrls.default.http[0];
432
+ const isAddress = typeof config.account !== "object";
433
+ const customTransport = {
434
+ async request({ method, params }) {
435
+ if (method.startsWith("eth_") && isAddress) {
436
+ try {
437
+ return await _optionalChain([window, 'access', _14 => _14.ethereum, 'optionalAccess', _15 => _15.request, 'call', _16 => _16({ method, params })]);
438
+ } catch (err) {
439
+ console.warn(`Error using window.ethereum for method ${method}:`, err);
440
+ throw err;
441
+ }
442
+ } else {
443
+ try {
444
+ const response = await fetch(rpcUrl, {
445
+ method: "POST",
446
+ headers: {
447
+ "Content-Type": "application/json"
448
+ },
449
+ body: JSON.stringify({
450
+ jsonrpc: "2.0",
451
+ id: Date.now(),
452
+ method,
453
+ params
454
+ })
455
+ });
456
+ const data = await response.json();
457
+ if (data.error) {
458
+ throw new Error(data.error.message);
459
+ }
460
+ return data.result;
461
+ } catch (err) {
462
+ console.error(`Error fetching ${method} from GenLayer RPC:`, err);
463
+ throw err;
464
+ }
465
+ }
466
+ }
467
+ };
322
468
  const baseClient = _viem.createClient.call(void 0, {
323
469
  chain: chainConfig,
324
- transport: _viem.http.call(void 0, rpcUrl),
470
+ transport: _viem.custom.call(void 0, customTransport),
325
471
  ...config.account ? { account: config.account } : {}
326
472
  }).extend(_viem.publicActions).extend((client) => accountActions(client)).extend((client) => transactionActions(client)).extend((client) => contractActions(client));
327
- const genLayerClient = overrideContractActions(baseClient);
328
- return genLayerClient;
473
+ return overrideContractActions(baseClient);
329
474
  };
330
475
 
331
476
  // 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
@@ -8,7 +8,7 @@ import {
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,21 +22,20 @@ 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
  };
36
36
  }
37
37
 
38
- // src/abi/calldata/encoder.ts
39
- import { toHex, toRlp } from "viem";
38
+ // src/abi/calldata/consts.ts
40
39
  var BITS_IN_TYPE = 3;
41
40
  var TYPE_SPECIAL = 0;
42
41
  var TYPE_PINT = 1;
@@ -49,6 +48,92 @@ var SPECIAL_NULL = 0 << BITS_IN_TYPE | TYPE_SPECIAL;
49
48
  var SPECIAL_FALSE = 1 << BITS_IN_TYPE | TYPE_SPECIAL;
50
49
  var SPECIAL_TRUE = 2 << BITS_IN_TYPE | TYPE_SPECIAL;
51
50
  var SPECIAL_ADDR = 3 << BITS_IN_TYPE | TYPE_SPECIAL;
51
+
52
+ // src/abi/calldata/decoder.ts
53
+ function readULeb128(data, index) {
54
+ let res = 0n;
55
+ let accum = 0n;
56
+ let shouldContinue = true;
57
+ while (shouldContinue) {
58
+ const byte = data[index.i];
59
+ index.i++;
60
+ const rest = byte & 127;
61
+ res += BigInt(rest) * (1n << accum);
62
+ accum += 7n;
63
+ shouldContinue = byte >= 128;
64
+ }
65
+ return res;
66
+ }
67
+ function decodeImpl(data, index) {
68
+ const cur = readULeb128(data, index);
69
+ switch (cur) {
70
+ case BigInt(SPECIAL_NULL):
71
+ return null;
72
+ case BigInt(SPECIAL_TRUE):
73
+ return true;
74
+ case BigInt(SPECIAL_FALSE):
75
+ return false;
76
+ case BigInt(SPECIAL_ADDR): {
77
+ const res = data.slice(index.i, index.i + 20);
78
+ index.i += 20;
79
+ return new Address(res);
80
+ }
81
+ }
82
+ const type = Number(cur & 0xffn) & (1 << BITS_IN_TYPE) - 1;
83
+ const rest = cur >> BigInt(BITS_IN_TYPE);
84
+ switch (type) {
85
+ case TYPE_BYTES: {
86
+ const ret = data.slice(index.i, index.i + Number(rest));
87
+ index.i += Number(rest);
88
+ return ret;
89
+ }
90
+ case TYPE_PINT:
91
+ return rest;
92
+ case TYPE_NINT:
93
+ return -1n - rest;
94
+ case TYPE_STR: {
95
+ const ret = data.slice(index.i, index.i + Number(rest));
96
+ index.i += Number(rest);
97
+ return new TextDecoder("utf-8").decode(ret);
98
+ }
99
+ case TYPE_ARR: {
100
+ const ret = [];
101
+ let elems = rest;
102
+ while (elems > 0) {
103
+ elems--;
104
+ ret.push(decodeImpl(data, index));
105
+ }
106
+ return ret;
107
+ }
108
+ case TYPE_MAP: {
109
+ const ret = /* @__PURE__ */ new Map();
110
+ let elems = rest;
111
+ while (elems > 0) {
112
+ elems--;
113
+ const strLen = Number(readULeb128(data, index));
114
+ const key = data.slice(index.i, index.i + strLen);
115
+ index.i += strLen;
116
+ const keyStr = new TextDecoder("utf-8").decode(key);
117
+ ret.set(keyStr, decodeImpl(data, index));
118
+ }
119
+ return ret;
120
+ }
121
+ default:
122
+ throw new Error(`can't decode type from ${type} rest is ${rest} at pos ${index.i}`);
123
+ }
124
+ }
125
+ function decode(data) {
126
+ const index = { i: 0 };
127
+ const res = decodeImpl(data, index);
128
+ if (index.i !== data.length) {
129
+ throw new Error("some data left");
130
+ }
131
+ return res;
132
+ }
133
+
134
+ // src/abi/calldata/encoder.ts
135
+ import { toHex } from "viem";
136
+ import { toRlp } from "viem";
52
137
  function reportError(msg, data) {
53
138
  throw new Error(`invalid calldata input '${data}'`);
54
139
  }
@@ -162,10 +247,7 @@ function encodeImpl(to, data) {
162
247
  to.push(c);
163
248
  }
164
249
  } else if (Object.getPrototypeOf(data) === Object.prototype) {
165
- encodeMap(
166
- to,
167
- Object.keys(data).map((k) => [k, data[k]])
168
- );
250
+ encodeMap(to, Object.entries(data));
169
251
  } else {
170
252
  reportError("unknown object type", data);
171
253
  }
@@ -210,22 +292,40 @@ var overrideContractActions = (client) => {
210
292
  client.readContract = async (args) => {
211
293
  const { account, address, functionName, args: params } = args;
212
294
  const encodedData = encodeAndSerialize({ method: functionName, args: params });
295
+ let senderAddress = account?.address ?? client.account?.address;
213
296
  const requestParams = {
214
297
  to: address,
215
- from: account?.address ?? client.account?.address,
298
+ from: senderAddress,
216
299
  data: encodedData
217
300
  };
218
301
  const result = await client.request({
219
302
  method: "eth_call",
220
303
  params: [requestParams, "latest"]
221
304
  });
222
- return result;
305
+ if (typeof result === "string") {
306
+ const val = Uint8Array.from(atob(result), (c) => c.charCodeAt(0));
307
+ return decode(val);
308
+ } else {
309
+ return "<unknown>";
310
+ }
223
311
  };
224
312
  client.writeContract = async (args) => {
225
313
  const { account, address, functionName, args: params, value = 0n, leaderOnly = false } = args;
226
314
  const data = [encode({ method: functionName, args: params }), leaderOnly];
227
315
  const serializedData = serialize(data);
228
316
  const senderAccount = account || client.account;
317
+ if (senderAccount?.type !== "local") {
318
+ const transaction = {
319
+ from: senderAccount?.address,
320
+ to: address,
321
+ data: serializedData,
322
+ value: `0x${value.toString(16)}`
323
+ };
324
+ return await client.request({
325
+ method: "eth_sendTransaction",
326
+ params: [transaction]
327
+ });
328
+ }
229
329
  if (!senderAccount) {
230
330
  throw new Error(
231
331
  "No account set. Configure the client with an account or pass an account to this function."
@@ -242,17 +342,28 @@ var overrideContractActions = (client) => {
242
342
  type: "legacy",
243
343
  nonce
244
344
  });
245
- const result = await client.request({
345
+ return await client.request({
246
346
  method: "eth_sendRawTransaction",
247
347
  params: [signedTransaction]
248
348
  });
249
- return result;
250
349
  };
251
350
  client.deployContract = async (args) => {
252
351
  const { account, code, args: constructorArgs, leaderOnly = false } = args;
253
352
  const data = [code, encode({ args: constructorArgs }), leaderOnly];
254
353
  const serializedData = serialize(data);
255
354
  const senderAccount = account || client.account;
355
+ if (senderAccount?.type !== "local") {
356
+ const transaction = {
357
+ from: senderAccount?.address,
358
+ to: null,
359
+ data: serializedData,
360
+ value: "0x0"
361
+ };
362
+ return await client.request({
363
+ method: "eth_sendTransaction",
364
+ params: [transaction]
365
+ });
366
+ }
256
367
  if (!senderAccount) {
257
368
  throw new Error(
258
369
  "No account set. Configure the client with an account or pass an account to this function."
@@ -267,11 +378,10 @@ var overrideContractActions = (client) => {
267
378
  type: "legacy",
268
379
  nonce
269
380
  });
270
- const result = await client.request({
381
+ return await client.request({
271
382
  method: "eth_sendRawTransaction",
272
383
  params: [signedTransaction]
273
384
  });
274
- return result;
275
385
  };
276
386
  return client;
277
387
  };
@@ -319,13 +429,48 @@ var transactionActions = (client) => ({
319
429
  var createClient = (config = { chain: simulator }) => {
320
430
  const chainConfig = config.chain || simulator;
321
431
  const rpcUrl = config.endpoint || chainConfig.rpcUrls.default.http[0];
432
+ const isAddress = typeof config.account !== "object";
433
+ const customTransport = {
434
+ async request({ method, params }) {
435
+ if (method.startsWith("eth_") && isAddress) {
436
+ try {
437
+ return await window.ethereum?.request({ method, params });
438
+ } catch (err) {
439
+ console.warn(`Error using window.ethereum for method ${method}:`, err);
440
+ throw err;
441
+ }
442
+ } else {
443
+ try {
444
+ const response = await fetch(rpcUrl, {
445
+ method: "POST",
446
+ headers: {
447
+ "Content-Type": "application/json"
448
+ },
449
+ body: JSON.stringify({
450
+ jsonrpc: "2.0",
451
+ id: Date.now(),
452
+ method,
453
+ params
454
+ })
455
+ });
456
+ const data = await response.json();
457
+ if (data.error) {
458
+ throw new Error(data.error.message);
459
+ }
460
+ return data.result;
461
+ } catch (err) {
462
+ console.error(`Error fetching ${method} from GenLayer RPC:`, err);
463
+ throw err;
464
+ }
465
+ }
466
+ }
467
+ };
322
468
  const baseClient = createViemClient({
323
469
  chain: chainConfig,
324
- transport: http(rpcUrl),
470
+ transport: custom(customTransport),
325
471
  ...config.account ? { account: config.account } : {}
326
472
  }).extend(publicActions).extend((client) => accountActions(client)).extend((client) => transactionActions(client)).extend((client) => contractActions(client));
327
- const genLayerClient = overrideContractActions(baseClient);
328
- return genLayerClient;
473
+ return overrideContractActions(baseClient);
329
474
  };
330
475
 
331
476
  // src/accounts/account.ts
@@ -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"] & {
@@ -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"] & {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "genlayer-js",
3
3
  "type": "module",
4
- "version": "0.4.7",
4
+ "version": "0.5.0",
5
5
  "description": "GenLayer JavaScript SDK",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -0,0 +1,14 @@
1
+ export const BITS_IN_TYPE = 3;
2
+
3
+ export const TYPE_SPECIAL = 0;
4
+ export const TYPE_PINT = 1;
5
+ export const TYPE_NINT = 2;
6
+ export const TYPE_BYTES = 3;
7
+ export const TYPE_STR = 4;
8
+ export const TYPE_ARR = 5;
9
+ export const TYPE_MAP = 6;
10
+
11
+ export const SPECIAL_NULL = (0 << BITS_IN_TYPE) | TYPE_SPECIAL;
12
+ export const SPECIAL_FALSE = (1 << BITS_IN_TYPE) | TYPE_SPECIAL;
13
+ export const SPECIAL_TRUE = (2 << BITS_IN_TYPE) | TYPE_SPECIAL;
14
+ export const SPECIAL_ADDR = (3 << BITS_IN_TYPE) | TYPE_SPECIAL;
@@ -0,0 +1,86 @@
1
+ import type {CalldataEncodable} from "../../types/calldata";
2
+ import {Address} from "../../types/calldata";
3
+ import * as consts from "./consts";
4
+
5
+ function readULeb128(data: Uint8Array, index: {i: number}): bigint {
6
+ let res: bigint = 0n;
7
+ let accum = 0n;
8
+ let shouldContinue = true;
9
+ while (shouldContinue) {
10
+ const byte = data[index.i];
11
+ index.i++;
12
+ const rest = byte & 0x7f;
13
+ res += BigInt(rest) * (1n << accum);
14
+ accum += 7n;
15
+ shouldContinue = byte >= 128;
16
+ }
17
+ return res;
18
+ }
19
+
20
+ function decodeImpl(data: Uint8Array, index: {i: number}): CalldataEncodable {
21
+ const cur = readULeb128(data, index);
22
+ switch (cur) {
23
+ case BigInt(consts.SPECIAL_NULL):
24
+ return null;
25
+ case BigInt(consts.SPECIAL_TRUE):
26
+ return true;
27
+ case BigInt(consts.SPECIAL_FALSE):
28
+ return false;
29
+ case BigInt(consts.SPECIAL_ADDR): {
30
+ const res = data.slice(index.i, index.i + 20);
31
+ index.i += 20;
32
+ return new Address(res);
33
+ }
34
+ }
35
+ const type = Number(cur & 0xffn) & ((1 << consts.BITS_IN_TYPE) - 1);
36
+ const rest = cur >> BigInt(consts.BITS_IN_TYPE);
37
+ switch (type) {
38
+ case consts.TYPE_BYTES: {
39
+ const ret = data.slice(index.i, index.i + Number(rest));
40
+ index.i += Number(rest);
41
+ return ret;
42
+ }
43
+ case consts.TYPE_PINT:
44
+ return rest;
45
+ case consts.TYPE_NINT:
46
+ return -1n - rest;
47
+ case consts.TYPE_STR: {
48
+ const ret = data.slice(index.i, index.i + Number(rest));
49
+ index.i += Number(rest);
50
+ return new TextDecoder("utf-8").decode(ret);
51
+ }
52
+ case consts.TYPE_ARR: {
53
+ const ret = [] as CalldataEncodable[];
54
+ let elems = rest;
55
+ while (elems > 0) {
56
+ elems--;
57
+ ret.push(decodeImpl(data, index));
58
+ }
59
+ return ret;
60
+ }
61
+ case consts.TYPE_MAP: {
62
+ const ret = new Map<string, CalldataEncodable>();
63
+ let elems = rest;
64
+ while (elems > 0) {
65
+ elems--;
66
+ const strLen = Number(readULeb128(data, index));
67
+ const key = data.slice(index.i, index.i + strLen);
68
+ index.i += strLen;
69
+ const keyStr = new TextDecoder("utf-8").decode(key);
70
+ ret.set(keyStr, decodeImpl(data, index));
71
+ }
72
+ return ret;
73
+ }
74
+ default:
75
+ throw new Error(`can't decode type from ${type} rest is ${rest} at pos ${index.i}`);
76
+ }
77
+ }
78
+
79
+ export function decode(data: Uint8Array): CalldataEncodable {
80
+ const index = {i: 0};
81
+ const res = decodeImpl(data, index);
82
+ if (index.i !== data.length) {
83
+ throw new Error("some data left");
84
+ }
85
+ return res;
86
+ }
@@ -1,21 +1,8 @@
1
- import {toHex, toRlp} from "viem";
1
+ import {toHex} from "viem";
2
+ import {toRlp} from "viem";
2
3
  import type {CalldataEncodable, TransactionDataElement} from "../../types/calldata";
3
4
  import {Address} from "../../types/calldata";
4
-
5
- const BITS_IN_TYPE = 3;
6
-
7
- const TYPE_SPECIAL = 0;
8
- const TYPE_PINT = 1;
9
- const TYPE_NINT = 2;
10
- const TYPE_BYTES = 3;
11
- const TYPE_STR = 4;
12
- const TYPE_ARR = 5;
13
- const TYPE_MAP = 6;
14
-
15
- const SPECIAL_NULL = (0 << BITS_IN_TYPE) | TYPE_SPECIAL;
16
- const SPECIAL_FALSE = (1 << BITS_IN_TYPE) | TYPE_SPECIAL;
17
- const SPECIAL_TRUE = (2 << BITS_IN_TYPE) | TYPE_SPECIAL;
18
- const SPECIAL_ADDR = (3 << BITS_IN_TYPE) | TYPE_SPECIAL;
5
+ import * as consts from "./consts";
19
6
 
20
7
  function reportError(msg: string, data: CalldataEncodable): never {
21
8
  throw new Error(`invalid calldata input '${data}'`);
@@ -37,15 +24,15 @@ function writeNum(to: number[], data: bigint) {
37
24
  }
38
25
 
39
26
  function encodeNumWithType(to: number[], data: bigint, type: number) {
40
- const res = (data << BigInt(BITS_IN_TYPE)) | BigInt(type);
27
+ const res = (data << BigInt(consts.BITS_IN_TYPE)) | BigInt(type);
41
28
  writeNum(to, res);
42
29
  }
43
30
 
44
31
  function encodeNum(to: number[], data: bigint) {
45
32
  if (data >= 0n) {
46
- encodeNumWithType(to, data, TYPE_PINT);
33
+ encodeNumWithType(to, data, consts.TYPE_PINT);
47
34
  } else {
48
- encodeNumWithType(to, -data - 1n, TYPE_NINT);
35
+ encodeNumWithType(to, -data - 1n, consts.TYPE_NINT);
49
36
  }
50
37
  }
51
38
 
@@ -76,7 +63,7 @@ function encodeMap(to: number[], arr: Iterable<[string, CalldataEncodable]>) {
76
63
  }
77
64
  }
78
65
 
79
- encodeNumWithType(to, BigInt(newEntries.length), TYPE_MAP);
66
+ encodeNumWithType(to, BigInt(newEntries.length), consts.TYPE_MAP);
80
67
  for (const [, k, v] of newEntries) {
81
68
  writeNum(to, BigInt(k.length));
82
69
  for (const c of k) {
@@ -88,15 +75,15 @@ function encodeMap(to: number[], arr: Iterable<[string, CalldataEncodable]>) {
88
75
 
89
76
  function encodeImpl(to: number[], data: CalldataEncodable) {
90
77
  if (data === null || data === undefined) {
91
- to.push(SPECIAL_NULL);
78
+ to.push(consts.SPECIAL_NULL);
92
79
  return;
93
80
  }
94
81
  if (data === true) {
95
- to.push(SPECIAL_TRUE);
82
+ to.push(consts.SPECIAL_TRUE);
96
83
  return;
97
84
  }
98
85
  if (data === false) {
99
- to.push(SPECIAL_FALSE);
86
+ to.push(consts.SPECIAL_FALSE);
100
87
  return;
101
88
  }
102
89
  switch (typeof data) {
@@ -113,7 +100,7 @@ function encodeImpl(to: number[], data: CalldataEncodable) {
113
100
  }
114
101
  case "string": {
115
102
  const str = new TextEncoder().encode(data);
116
- encodeNumWithType(to, BigInt(str.length), TYPE_STR);
103
+ encodeNumWithType(to, BigInt(str.length), consts.TYPE_STR);
117
104
  for (const c of str) {
118
105
  to.push(c);
119
106
  }
@@ -121,27 +108,24 @@ function encodeImpl(to: number[], data: CalldataEncodable) {
121
108
  }
122
109
  case "object": {
123
110
  if (data instanceof Uint8Array) {
124
- encodeNumWithType(to, BigInt(data.length), TYPE_BYTES);
111
+ encodeNumWithType(to, BigInt(data.length), consts.TYPE_BYTES);
125
112
  for (const c of data) {
126
113
  to.push(c);
127
114
  }
128
115
  } else if (data instanceof Array) {
129
- encodeNumWithType(to, BigInt(data.length), TYPE_ARR);
116
+ encodeNumWithType(to, BigInt(data.length), consts.TYPE_ARR);
130
117
  for (const c of data) {
131
118
  encodeImpl(to, c);
132
119
  }
133
120
  } else if (data instanceof Map) {
134
121
  encodeMap(to, data);
135
122
  } else if (data instanceof Address) {
136
- to.push(SPECIAL_ADDR);
123
+ to.push(consts.SPECIAL_ADDR);
137
124
  for (const c of data.bytes) {
138
125
  to.push(c);
139
126
  }
140
127
  } else if (Object.getPrototypeOf(data) === Object.prototype) {
141
- encodeMap(
142
- to,
143
- Object.keys(data).map((k): [string, CalldataEncodable] => [k, data[k]]),
144
- );
128
+ encodeMap(to, Object.entries(data));
145
129
  } else {
146
130
  reportError("unknown object type", data);
147
131
  }
@@ -159,6 +143,83 @@ export function encode(data: CalldataEncodable): Uint8Array {
159
143
  return new Uint8Array(arr);
160
144
  }
161
145
 
146
+ function toStringImplMap(data: Iterable<[string, CalldataEncodable]>, to: string[]) {
147
+ to.push("{");
148
+ for (const [k, v] of data) {
149
+ to.push(JSON.stringify(k));
150
+ to.push(":");
151
+ toStringImpl(v, to);
152
+ }
153
+ to.push("}");
154
+ }
155
+
156
+ function toStringImpl(data: CalldataEncodable, to: string[]) {
157
+ if (data === null || data === undefined) {
158
+ to.push("null");
159
+ return;
160
+ }
161
+ if (data === true) {
162
+ to.push("true");
163
+ return;
164
+ }
165
+ if (data === false) {
166
+ to.push("false");
167
+ return;
168
+ }
169
+ switch (typeof data) {
170
+ case "number": {
171
+ if (!Number.isInteger(data)) {
172
+ reportError("floats are not supported", data);
173
+ }
174
+ to.push(data.toString());
175
+ return;
176
+ }
177
+ case "bigint": {
178
+ to.push(data.toString());
179
+ return;
180
+ }
181
+ case "string": {
182
+ to.push(JSON.stringify(data));
183
+ return;
184
+ }
185
+ case "object": {
186
+ if (data instanceof Uint8Array) {
187
+ to.push("b#");
188
+ for (const b of data) {
189
+ to.push(b.toString(16));
190
+ }
191
+ } else if (data instanceof Array) {
192
+ to.push("[");
193
+ for (const c of data) {
194
+ toStringImpl(c, to);
195
+ to.push(",");
196
+ }
197
+ to.push("]");
198
+ } else if (data instanceof Map) {
199
+ toStringImplMap(data.entries(), to);
200
+ } else if (data instanceof Address) {
201
+ to.push("addr#");
202
+ for (const c of data.bytes) {
203
+ to.push(c.toString(16));
204
+ }
205
+ } else if (Object.getPrototypeOf(data) === Object.prototype) {
206
+ toStringImplMap(Object.entries(data), to);
207
+ } else {
208
+ reportError("unknown object type", data);
209
+ }
210
+ return;
211
+ }
212
+ default:
213
+ reportError("unknown base type", data);
214
+ }
215
+ }
216
+
217
+ export function toString(data: CalldataEncodable): string {
218
+ const to: string[] = [];
219
+ toStringImpl(data, to);
220
+ return to.join("");
221
+ }
222
+
162
223
  export function serialize(data: TransactionDataElement[]): `0x${string}` {
163
224
  return toRlp(data.map(param => toHex(param)));
164
225
  }
@@ -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,3 +1,4 @@
1
+ import {decode} from "@/abi/calldata/decoder";
1
2
  import {encode, serialize, encodeAndSerialize} from "@/abi/calldata/encoder";
2
3
  import {Account, ContractSchema, SimulatorChain, GenLayerClient, CalldataEncodable, Address} from "@/types";
3
4
 
@@ -27,21 +28,30 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
27
28
  functionName: string;
28
29
  args: CalldataEncodable[];
29
30
  }): Promise<unknown> => {
30
- const {account, address, functionName, args: params} = args;
31
- const encodedData = encodeAndSerialize({method: functionName, args: params});
31
+ const { account, address, functionName, args: params } = args;
32
+ const encodedData = encodeAndSerialize({ method: functionName, args: params });
33
+
34
+ let senderAddress = account?.address ?? client.account?.address;
32
35
 
33
36
  const requestParams = {
34
37
  to: address,
35
- from: account?.address ?? client.account?.address,
38
+ from: senderAddress,
36
39
  data: encodedData,
37
40
  };
38
41
  const result = await client.request({
39
42
  method: "eth_call",
40
43
  params: [requestParams, "latest"],
41
44
  });
42
- return result;
45
+
46
+ if (typeof result === "string") {
47
+ const val = Uint8Array.from(atob(result), c => c.charCodeAt(0));
48
+ return decode(val);
49
+ } else {
50
+ return "<unknown>";
51
+ }
43
52
  };
44
53
 
54
+
45
55
  client.writeContract = async (args: {
46
56
  account?: Account;
47
57
  address: Address;
@@ -50,14 +60,30 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
50
60
  value: bigint;
51
61
  leaderOnly?: boolean;
52
62
  }): Promise<`0x${string}`> => {
53
- const {account, address, functionName, args: params, value = 0n, leaderOnly = false} = args;
54
- const data = [encode({method: functionName, args: params}), leaderOnly];
63
+ const { account, address, functionName, args: params, value = 0n, leaderOnly = false } = args;
64
+ const data = [encode({ method: functionName, args: params }), leaderOnly];
55
65
  const serializedData = serialize(data);
56
-
57
66
  const senderAccount = account || client.account;
67
+
68
+
69
+ if (senderAccount?.type !== "local") {
70
+
71
+ const transaction = {
72
+ from: senderAccount?.address,
73
+ to: address,
74
+ data: serializedData,
75
+ value: `0x${value.toString(16)}`,
76
+ };
77
+
78
+ return await client.request({
79
+ method: "eth_sendTransaction",
80
+ params: [transaction as any],
81
+ });
82
+ }
83
+
58
84
  if (!senderAccount) {
59
85
  throw new Error(
60
- "No account set. Configure the client with an account or pass an account to this function.",
86
+ "No account set. Configure the client with an account or pass an account to this function."
61
87
  );
62
88
  }
63
89
 
@@ -65,7 +91,7 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
65
91
  throw new Error("Account does not support signTransaction");
66
92
  }
67
93
 
68
- const nonce = await client.getCurrentNonce({address: senderAccount.address});
94
+ const nonce = await client.getCurrentNonce({ address: senderAccount.address });
69
95
 
70
96
  const signedTransaction = await senderAccount.signTransaction({
71
97
  data: serializedData,
@@ -74,11 +100,11 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
74
100
  type: "legacy",
75
101
  nonce,
76
102
  });
77
- const result = await client.request({
103
+
104
+ return await client.request({
78
105
  method: "eth_sendRawTransaction",
79
106
  params: [signedTransaction],
80
107
  });
81
- return result;
82
108
  };
83
109
 
84
110
  client.deployContract = async (args: {
@@ -87,14 +113,29 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
87
113
  args: CalldataEncodable[];
88
114
  leaderOnly?: boolean;
89
115
  }) => {
90
- const {account, code, args: constructorArgs, leaderOnly = false} = args;
91
- const data = [code, encode({args: constructorArgs}), leaderOnly];
116
+ const { account, code, args: constructorArgs, leaderOnly = false } = args;
117
+ const data = [code, encode({ args: constructorArgs }), leaderOnly];
92
118
  const serializedData = serialize(data);
93
-
94
119
  const senderAccount = account || client.account;
120
+
121
+ if (senderAccount?.type !== "local") {
122
+
123
+ const transaction = {
124
+ from: senderAccount?.address,
125
+ to: null,
126
+ data: serializedData,
127
+ value: "0x0",
128
+ };
129
+
130
+ return await client.request({
131
+ method: "eth_sendTransaction",
132
+ params: [transaction as any],
133
+ });
134
+ }
135
+
95
136
  if (!senderAccount) {
96
137
  throw new Error(
97
- "No account set. Configure the client with an account or pass an account to this function.",
138
+ "No account set. Configure the client with an account or pass an account to this function."
98
139
  );
99
140
  }
100
141
 
@@ -102,7 +143,7 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
102
143
  throw new Error("Account does not support signTransaction");
103
144
  }
104
145
 
105
- const nonce = await client.getCurrentNonce({address: senderAccount.address});
146
+ const nonce = await client.getCurrentNonce({ address: senderAccount.address });
106
147
 
107
148
  const signedTransaction = await senderAccount.signTransaction({
108
149
  data: serializedData,
@@ -110,11 +151,10 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
110
151
  nonce,
111
152
  });
112
153
 
113
- const result = await client.request({
154
+ return await client.request({
114
155
  method: "eth_sendRawTransaction",
115
156
  params: [signedTransaction],
116
157
  });
117
- return result;
118
158
  };
119
159
 
120
160
  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>
@@ -18,7 +18,7 @@ describe("Client Overrides", () => {
18
18
  const account = createAccount(generatePrivateKey());
19
19
  const client = createClient({
20
20
  chain: simulator,
21
- account,
21
+ account: account,
22
22
  });
23
23
 
24
24
  // Mock the client.request method
@@ -76,4 +76,34 @@ describe("Client Overrides", () => {
76
76
  ],
77
77
  });
78
78
  });
79
+ it("should override client account if address is provided", async () => {
80
+ const account = '0x65e03a3e916CF1dC92d3C8E8186a89CfAB0D2bc2';
81
+ const client = createClient({
82
+ chain: simulator,
83
+ account,
84
+ });
85
+
86
+ // Mock the client.request method
87
+ vi.spyOn(client, "request").mockResolvedValue(undefined);
88
+
89
+ const contractAddress = "0x1234567890123456789012345678901234567890";
90
+ await client.readContract({
91
+ address: contractAddress as Address,
92
+ functionName: "testFunction",
93
+ args: ["arg1", "arg2"],
94
+ });
95
+
96
+ expect(client.request).toHaveBeenCalledWith({
97
+ method: "eth_call",
98
+ params: [
99
+ {
100
+ to: contractAddress,
101
+ from: account,
102
+ data: expect.any(String),
103
+ },
104
+ "latest",
105
+ ],
106
+ });
107
+ });
108
+
79
109
  });
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
  }