genlayer-js 0.4.8 → 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 +7 -0
- package/dist/index.cjs +70 -12
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +69 -11
- package/dist/types/index.d.cts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/accounts/actions.ts +2 -3
- package/src/client/client.ts +51 -13
- package/src/contracts/actions.ts +50 -17
- package/src/global.d.ts +7 -0
- package/src/types/clients.ts +1 -1
- package/tests/client.test.ts +31 -1
- package/tsconfig.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
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
|
+
|
|
3
10
|
## 0.4.8 (2024-12-18)
|
|
4
11
|
|
|
5
12
|
|
package/dist/index.cjs
CHANGED
|
@@ -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
|
};
|
|
@@ -292,9 +292,10 @@ var overrideContractActions = (client) => {
|
|
|
292
292
|
client.readContract = async (args) => {
|
|
293
293
|
const { account, address, functionName, args: params } = args;
|
|
294
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])));
|
|
295
296
|
const requestParams = {
|
|
296
297
|
to: address,
|
|
297
|
-
from:
|
|
298
|
+
from: senderAddress,
|
|
298
299
|
data: encodedData
|
|
299
300
|
};
|
|
300
301
|
const result = await client.request({
|
|
@@ -313,12 +314,24 @@ var overrideContractActions = (client) => {
|
|
|
313
314
|
const data = [encode({ method: functionName, args: params }), leaderOnly];
|
|
314
315
|
const serializedData = serialize(data);
|
|
315
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
|
+
}
|
|
316
329
|
if (!senderAccount) {
|
|
317
330
|
throw new Error(
|
|
318
331
|
"No account set. Configure the client with an account or pass an account to this function."
|
|
319
332
|
);
|
|
320
333
|
}
|
|
321
|
-
if (!_optionalChain([senderAccount, 'optionalAccess',
|
|
334
|
+
if (!_optionalChain([senderAccount, 'optionalAccess', _10 => _10.signTransaction])) {
|
|
322
335
|
throw new Error("Account does not support signTransaction");
|
|
323
336
|
}
|
|
324
337
|
const nonce = await client.getCurrentNonce({ address: senderAccount.address });
|
|
@@ -329,23 +342,34 @@ var overrideContractActions = (client) => {
|
|
|
329
342
|
type: "legacy",
|
|
330
343
|
nonce
|
|
331
344
|
});
|
|
332
|
-
|
|
345
|
+
return await client.request({
|
|
333
346
|
method: "eth_sendRawTransaction",
|
|
334
347
|
params: [signedTransaction]
|
|
335
348
|
});
|
|
336
|
-
return result;
|
|
337
349
|
};
|
|
338
350
|
client.deployContract = async (args) => {
|
|
339
351
|
const { account, code, args: constructorArgs, leaderOnly = false } = args;
|
|
340
352
|
const data = [code, encode({ args: constructorArgs }), leaderOnly];
|
|
341
353
|
const serializedData = serialize(data);
|
|
342
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
|
+
}
|
|
343
367
|
if (!senderAccount) {
|
|
344
368
|
throw new Error(
|
|
345
369
|
"No account set. Configure the client with an account or pass an account to this function."
|
|
346
370
|
);
|
|
347
371
|
}
|
|
348
|
-
if (!_optionalChain([senderAccount, 'optionalAccess',
|
|
372
|
+
if (!_optionalChain([senderAccount, 'optionalAccess', _13 => _13.signTransaction])) {
|
|
349
373
|
throw new Error("Account does not support signTransaction");
|
|
350
374
|
}
|
|
351
375
|
const nonce = await client.getCurrentNonce({ address: senderAccount.address });
|
|
@@ -354,11 +378,10 @@ var overrideContractActions = (client) => {
|
|
|
354
378
|
type: "legacy",
|
|
355
379
|
nonce
|
|
356
380
|
});
|
|
357
|
-
|
|
381
|
+
return await client.request({
|
|
358
382
|
method: "eth_sendRawTransaction",
|
|
359
383
|
params: [signedTransaction]
|
|
360
384
|
});
|
|
361
|
-
return result;
|
|
362
385
|
};
|
|
363
386
|
return client;
|
|
364
387
|
};
|
|
@@ -406,13 +429,48 @@ var transactionActions = (client) => ({
|
|
|
406
429
|
var createClient = (config = { chain: _chunkIINRDYKFcjs.simulator }) => {
|
|
407
430
|
const chainConfig = config.chain || _chunkIINRDYKFcjs.simulator;
|
|
408
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
|
+
};
|
|
409
468
|
const baseClient = _viem.createClient.call(void 0, {
|
|
410
469
|
chain: chainConfig,
|
|
411
|
-
transport: _viem.
|
|
470
|
+
transport: _viem.custom.call(void 0, customTransport),
|
|
412
471
|
...config.account ? { account: config.account } : {}
|
|
413
472
|
}).extend(_viem.publicActions).extend((client) => accountActions(client)).extend((client) => transactionActions(client)).extend((client) => contractActions(client));
|
|
414
|
-
|
|
415
|
-
return genLayerClient;
|
|
473
|
+
return overrideContractActions(baseClient);
|
|
416
474
|
};
|
|
417
475
|
|
|
418
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,
|
|
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
|
};
|
|
@@ -292,9 +292,10 @@ var overrideContractActions = (client) => {
|
|
|
292
292
|
client.readContract = async (args) => {
|
|
293
293
|
const { account, address, functionName, args: params } = args;
|
|
294
294
|
const encodedData = encodeAndSerialize({ method: functionName, args: params });
|
|
295
|
+
let senderAddress = account?.address ?? client.account?.address;
|
|
295
296
|
const requestParams = {
|
|
296
297
|
to: address,
|
|
297
|
-
from:
|
|
298
|
+
from: senderAddress,
|
|
298
299
|
data: encodedData
|
|
299
300
|
};
|
|
300
301
|
const result = await client.request({
|
|
@@ -313,6 +314,18 @@ var overrideContractActions = (client) => {
|
|
|
313
314
|
const data = [encode({ method: functionName, args: params }), leaderOnly];
|
|
314
315
|
const serializedData = serialize(data);
|
|
315
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
|
+
}
|
|
316
329
|
if (!senderAccount) {
|
|
317
330
|
throw new Error(
|
|
318
331
|
"No account set. Configure the client with an account or pass an account to this function."
|
|
@@ -329,17 +342,28 @@ var overrideContractActions = (client) => {
|
|
|
329
342
|
type: "legacy",
|
|
330
343
|
nonce
|
|
331
344
|
});
|
|
332
|
-
|
|
345
|
+
return await client.request({
|
|
333
346
|
method: "eth_sendRawTransaction",
|
|
334
347
|
params: [signedTransaction]
|
|
335
348
|
});
|
|
336
|
-
return result;
|
|
337
349
|
};
|
|
338
350
|
client.deployContract = async (args) => {
|
|
339
351
|
const { account, code, args: constructorArgs, leaderOnly = false } = args;
|
|
340
352
|
const data = [code, encode({ args: constructorArgs }), leaderOnly];
|
|
341
353
|
const serializedData = serialize(data);
|
|
342
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
|
+
}
|
|
343
367
|
if (!senderAccount) {
|
|
344
368
|
throw new Error(
|
|
345
369
|
"No account set. Configure the client with an account or pass an account to this function."
|
|
@@ -354,11 +378,10 @@ var overrideContractActions = (client) => {
|
|
|
354
378
|
type: "legacy",
|
|
355
379
|
nonce
|
|
356
380
|
});
|
|
357
|
-
|
|
381
|
+
return await client.request({
|
|
358
382
|
method: "eth_sendRawTransaction",
|
|
359
383
|
params: [signedTransaction]
|
|
360
384
|
});
|
|
361
|
-
return result;
|
|
362
385
|
};
|
|
363
386
|
return client;
|
|
364
387
|
};
|
|
@@ -406,13 +429,48 @@ var transactionActions = (client) => ({
|
|
|
406
429
|
var createClient = (config = { chain: simulator }) => {
|
|
407
430
|
const chainConfig = config.chain || simulator;
|
|
408
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
|
+
};
|
|
409
468
|
const baseClient = createViemClient({
|
|
410
469
|
chain: chainConfig,
|
|
411
|
-
transport:
|
|
470
|
+
transport: custom(customTransport),
|
|
412
471
|
...config.account ? { account: config.account } : {}
|
|
413
472
|
}).extend(publicActions).extend((client) => accountActions(client)).extend((client) => transactionActions(client)).extend((client) => contractActions(client));
|
|
414
|
-
|
|
415
|
-
return genLayerClient;
|
|
473
|
+
return overrideContractActions(baseClient);
|
|
416
474
|
};
|
|
417
475
|
|
|
418
476
|
// src/accounts/account.ts
|
package/dist/types/index.d.cts
CHANGED
|
@@ -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/dist/types/index.d.ts
CHANGED
|
@@ -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
package/src/accounts/actions.ts
CHANGED
|
@@ -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
|
};
|
package/src/client/client.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {Account, createClient as createViemClient,
|
|
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; //
|
|
18
|
-
account?: Account;
|
|
17
|
+
endpoint?: string; // Custom RPC endpoint
|
|
18
|
+
account?: Account | Address;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
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:
|
|
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
|
-
|
|
76
|
+
return overrideContractActions(baseClient as unknown as GenLayerClient<SimulatorChain>);
|
|
39
77
|
|
|
40
|
-
return genLayerClient;
|
|
41
78
|
};
|
|
79
|
+
|
package/src/contracts/actions.ts
CHANGED
|
@@ -28,12 +28,14 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
|
|
|
28
28
|
functionName: string;
|
|
29
29
|
args: CalldataEncodable[];
|
|
30
30
|
}): Promise<unknown> => {
|
|
31
|
-
const {account, address, functionName, args: params} = args;
|
|
32
|
-
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;
|
|
33
35
|
|
|
34
36
|
const requestParams = {
|
|
35
37
|
to: address,
|
|
36
|
-
from:
|
|
38
|
+
from: senderAddress,
|
|
37
39
|
data: encodedData,
|
|
38
40
|
};
|
|
39
41
|
const result = await client.request({
|
|
@@ -49,6 +51,7 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
|
|
|
49
51
|
}
|
|
50
52
|
};
|
|
51
53
|
|
|
54
|
+
|
|
52
55
|
client.writeContract = async (args: {
|
|
53
56
|
account?: Account;
|
|
54
57
|
address: Address;
|
|
@@ -57,14 +60,30 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
|
|
|
57
60
|
value: bigint;
|
|
58
61
|
leaderOnly?: boolean;
|
|
59
62
|
}): Promise<`0x${string}`> => {
|
|
60
|
-
const {account, address, functionName, args: params, value = 0n, leaderOnly = false} = args;
|
|
61
|
-
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];
|
|
62
65
|
const serializedData = serialize(data);
|
|
63
|
-
|
|
64
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
|
+
|
|
65
84
|
if (!senderAccount) {
|
|
66
85
|
throw new Error(
|
|
67
|
-
|
|
86
|
+
"No account set. Configure the client with an account or pass an account to this function."
|
|
68
87
|
);
|
|
69
88
|
}
|
|
70
89
|
|
|
@@ -72,7 +91,7 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
|
|
|
72
91
|
throw new Error("Account does not support signTransaction");
|
|
73
92
|
}
|
|
74
93
|
|
|
75
|
-
const nonce = await client.getCurrentNonce({address: senderAccount.address});
|
|
94
|
+
const nonce = await client.getCurrentNonce({ address: senderAccount.address });
|
|
76
95
|
|
|
77
96
|
const signedTransaction = await senderAccount.signTransaction({
|
|
78
97
|
data: serializedData,
|
|
@@ -81,11 +100,11 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
|
|
|
81
100
|
type: "legacy",
|
|
82
101
|
nonce,
|
|
83
102
|
});
|
|
84
|
-
|
|
103
|
+
|
|
104
|
+
return await client.request({
|
|
85
105
|
method: "eth_sendRawTransaction",
|
|
86
106
|
params: [signedTransaction],
|
|
87
107
|
});
|
|
88
|
-
return result;
|
|
89
108
|
};
|
|
90
109
|
|
|
91
110
|
client.deployContract = async (args: {
|
|
@@ -94,14 +113,29 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
|
|
|
94
113
|
args: CalldataEncodable[];
|
|
95
114
|
leaderOnly?: boolean;
|
|
96
115
|
}) => {
|
|
97
|
-
const {account, code, args: constructorArgs, leaderOnly = false} = args;
|
|
98
|
-
const data = [code, encode({args: constructorArgs}), leaderOnly];
|
|
116
|
+
const { account, code, args: constructorArgs, leaderOnly = false } = args;
|
|
117
|
+
const data = [code, encode({ args: constructorArgs }), leaderOnly];
|
|
99
118
|
const serializedData = serialize(data);
|
|
100
|
-
|
|
101
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
|
+
|
|
102
136
|
if (!senderAccount) {
|
|
103
137
|
throw new Error(
|
|
104
|
-
|
|
138
|
+
"No account set. Configure the client with an account or pass an account to this function."
|
|
105
139
|
);
|
|
106
140
|
}
|
|
107
141
|
|
|
@@ -109,7 +143,7 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
|
|
|
109
143
|
throw new Error("Account does not support signTransaction");
|
|
110
144
|
}
|
|
111
145
|
|
|
112
|
-
const nonce = await client.getCurrentNonce({address: senderAccount.address});
|
|
146
|
+
const nonce = await client.getCurrentNonce({ address: senderAccount.address });
|
|
113
147
|
|
|
114
148
|
const signedTransaction = await senderAccount.signTransaction({
|
|
115
149
|
data: serializedData,
|
|
@@ -117,11 +151,10 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
|
|
|
117
151
|
nonce,
|
|
118
152
|
});
|
|
119
153
|
|
|
120
|
-
|
|
154
|
+
return await client.request({
|
|
121
155
|
method: "eth_sendRawTransaction",
|
|
122
156
|
params: [signedTransaction],
|
|
123
157
|
});
|
|
124
|
-
return result;
|
|
125
158
|
};
|
|
126
159
|
|
|
127
160
|
return client;
|
package/src/global.d.ts
ADDED
package/src/types/clients.ts
CHANGED
|
@@ -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>
|
package/tests/client.test.ts
CHANGED
|
@@ -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
|
}
|