genlayer-js 0.1.2 → 0.3.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.3.0 (2024-10-25)
4
+
5
+
6
+ ### Features
7
+
8
+ * add deploy contract action ([#17](https://github.com/yeagerai/genlayer-js/issues/17)) ([23d5bc2](https://github.com/yeagerai/genlayer-js/commit/23d5bc28fb58c73d64b1fd629185a0565d84cb91))
9
+
10
+ ## 0.2.0 (2024-10-17)
11
+
12
+
13
+ ### Features
14
+
15
+ * implement genvm calldata ([#14](https://github.com/yeagerai/genlayer-js/issues/14)) ([d9a1abd](https://github.com/yeagerai/genlayer-js/commit/d9a1abdfb5eef13e5c77433db546953369087e04))
16
+
3
17
  ## 0.1.2 (2024-10-03)
4
18
 
5
19
  ## 0.1.1 (2024-10-03)
@@ -1,3 +1,14 @@
1
+ // src/types/calldata.ts
2
+ var Address = class {
3
+ bytes;
4
+ constructor(addr) {
5
+ if (addr.length != 32) {
6
+ throw new Error(`invalid address length ${addr}`);
7
+ }
8
+ this.bytes = addr;
9
+ }
10
+ };
11
+
1
12
  // src/types/transactions.ts
2
13
  var TransactionStatus = /* @__PURE__ */ ((TransactionStatus2) => {
3
14
  TransactionStatus2["PENDING"] = "PENDING";
@@ -12,5 +23,6 @@ var TransactionStatus = /* @__PURE__ */ ((TransactionStatus2) => {
12
23
  })(TransactionStatus || {});
13
24
 
14
25
  export {
26
+ Address,
15
27
  TransactionStatus
16
28
  };
@@ -1,4 +1,15 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/types/transactions.ts
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/types/calldata.ts
2
+ var Address = class {
3
+
4
+ constructor(addr) {
5
+ if (addr.length != 32) {
6
+ throw new Error(`invalid address length ${addr}`);
7
+ }
8
+ this.bytes = addr;
9
+ }
10
+ };
11
+
12
+ // src/types/transactions.ts
2
13
  var TransactionStatus = /* @__PURE__ */ ((TransactionStatus2) => {
3
14
  TransactionStatus2["PENDING"] = "PENDING";
4
15
  TransactionStatus2["CANCELED"] = "CANCELED";
@@ -13,4 +24,5 @@ var TransactionStatus = /* @__PURE__ */ ((TransactionStatus2) => {
13
24
 
14
25
 
15
26
 
16
- exports.TransactionStatus = TransactionStatus;
27
+
28
+ exports.Address = Address; exports.TransactionStatus = TransactionStatus;
@@ -1,10 +1,26 @@
1
1
  import { Transport, Account, Client } from 'viem';
2
2
  import { S as SimulatorChain } from './chains-CtZJFz4Q.cjs';
3
3
 
4
- type Address = `0x${string}` & {
4
+ type Address$1 = `0x${string}` & {
5
5
  length: 42;
6
6
  };
7
7
 
8
+ declare class Address {
9
+ bytes: Uint8Array;
10
+ constructor(addr: Uint8Array);
11
+ }
12
+ type CalldataEncodable = null | boolean | Address | number | bigint | string | Uint8Array | Address | Array<CalldataEncodable> | Map<string, CalldataEncodable> | {
13
+ [key: string]: CalldataEncodable;
14
+ };
15
+ type MethodDescription = {
16
+ method: string;
17
+ args: Array<CalldataEncodable>;
18
+ };
19
+ type TransactionData = {
20
+ method: string;
21
+ args: CalldataEncodable[];
22
+ };
23
+
8
24
  type TransactionHash = `0x${string}` & {
9
25
  length: 66;
10
26
  };
@@ -34,6 +50,7 @@ type GenLayerTransaction = {
34
50
  s?: number;
35
51
  v?: number;
36
52
  };
53
+ type TransactionDataElement = string | number | bigint | boolean | Uint8Array;
37
54
 
38
55
  type GenLayerMethod = {
39
56
  method: "sim_fundAccount";
@@ -53,6 +70,9 @@ type GenLayerMethod = {
53
70
  } | {
54
71
  method: "gen_getContractSchemaForCode";
55
72
  params: [contractCode: string];
73
+ } | {
74
+ method: "eth_getTransactionCount";
75
+ params: [address: string];
56
76
  };
57
77
  type GenLayerClient<TTransport extends Transport, TSimulatorChain extends SimulatorChain, TAccount extends Account> = Client<TTransport, TSimulatorChain, TAccount> & {
58
78
  request: Client<TTransport, TSimulatorChain, TAccount>["request"] & {
@@ -62,20 +82,28 @@ type GenLayerClient<TTransport extends Transport, TSimulatorChain extends Simula
62
82
  };
63
83
  readContract: (args: {
64
84
  account: Account;
65
- address: Address;
85
+ address: Address$1;
66
86
  functionName: string;
67
87
  args: any[];
68
88
  }) => Promise<any>;
69
89
  writeContract: (args: {
70
90
  account: Account;
71
- address: Address;
91
+ address: Address$1;
72
92
  functionName: string;
73
93
  args: any[];
74
94
  value: bigint;
75
95
  }) => Promise<any>;
96
+ deployContract: (args: {
97
+ account: Account;
98
+ code: string;
99
+ args: CalldataEncodable[];
100
+ }) => Promise<any>;
76
101
  getTransaction: (args: {
77
102
  hash: TransactionHash;
78
103
  }) => Promise<GenLayerTransaction>;
104
+ getCurrentNonce: (args: {
105
+ address: string;
106
+ }) => Promise<number>;
79
107
  };
80
108
 
81
- export { type Address as A, type GenLayerClient as G, type TransactionHash as T, type GenLayerMethod as a, TransactionStatus as b, type GenLayerTransaction as c };
109
+ export { type Address$1 as A, type CalldataEncodable as C, type GenLayerClient as G, type MethodDescription as M, type TransactionData as T, type GenLayerMethod as a, type TransactionHash as b, TransactionStatus as c, type GenLayerTransaction as d, type TransactionDataElement as e };
@@ -1,10 +1,26 @@
1
1
  import { Transport, Account, Client } from 'viem';
2
2
  import { S as SimulatorChain } from './chains-CtZJFz4Q.js';
3
3
 
4
- type Address = `0x${string}` & {
4
+ type Address$1 = `0x${string}` & {
5
5
  length: 42;
6
6
  };
7
7
 
8
+ declare class Address {
9
+ bytes: Uint8Array;
10
+ constructor(addr: Uint8Array);
11
+ }
12
+ type CalldataEncodable = null | boolean | Address | number | bigint | string | Uint8Array | Address | Array<CalldataEncodable> | Map<string, CalldataEncodable> | {
13
+ [key: string]: CalldataEncodable;
14
+ };
15
+ type MethodDescription = {
16
+ method: string;
17
+ args: Array<CalldataEncodable>;
18
+ };
19
+ type TransactionData = {
20
+ method: string;
21
+ args: CalldataEncodable[];
22
+ };
23
+
8
24
  type TransactionHash = `0x${string}` & {
9
25
  length: 66;
10
26
  };
@@ -34,6 +50,7 @@ type GenLayerTransaction = {
34
50
  s?: number;
35
51
  v?: number;
36
52
  };
53
+ type TransactionDataElement = string | number | bigint | boolean | Uint8Array;
37
54
 
38
55
  type GenLayerMethod = {
39
56
  method: "sim_fundAccount";
@@ -53,6 +70,9 @@ type GenLayerMethod = {
53
70
  } | {
54
71
  method: "gen_getContractSchemaForCode";
55
72
  params: [contractCode: string];
73
+ } | {
74
+ method: "eth_getTransactionCount";
75
+ params: [address: string];
56
76
  };
57
77
  type GenLayerClient<TTransport extends Transport, TSimulatorChain extends SimulatorChain, TAccount extends Account> = Client<TTransport, TSimulatorChain, TAccount> & {
58
78
  request: Client<TTransport, TSimulatorChain, TAccount>["request"] & {
@@ -62,20 +82,28 @@ type GenLayerClient<TTransport extends Transport, TSimulatorChain extends Simula
62
82
  };
63
83
  readContract: (args: {
64
84
  account: Account;
65
- address: Address;
85
+ address: Address$1;
66
86
  functionName: string;
67
87
  args: any[];
68
88
  }) => Promise<any>;
69
89
  writeContract: (args: {
70
90
  account: Account;
71
- address: Address;
91
+ address: Address$1;
72
92
  functionName: string;
73
93
  args: any[];
74
94
  value: bigint;
75
95
  }) => Promise<any>;
96
+ deployContract: (args: {
97
+ account: Account;
98
+ code: string;
99
+ args: CalldataEncodable[];
100
+ }) => Promise<any>;
76
101
  getTransaction: (args: {
77
102
  hash: TransactionHash;
78
103
  }) => Promise<GenLayerTransaction>;
104
+ getCurrentNonce: (args: {
105
+ address: string;
106
+ }) => Promise<number>;
79
107
  };
80
108
 
81
- export { type Address as A, type GenLayerClient as G, type TransactionHash as T, type GenLayerMethod as a, TransactionStatus as b, type GenLayerTransaction as c };
109
+ export { type Address$1 as A, type CalldataEncodable as C, type GenLayerClient as G, type MethodDescription as M, type TransactionData as T, type GenLayerMethod as a, type TransactionHash as b, TransactionStatus as c, type GenLayerTransaction as d, type TransactionDataElement as e };
package/dist/index.cjs CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
 
4
4
  var _chunkBAGFDCQEcjs = require('./chunk-BAGFDCQE.cjs');
5
- require('./chunk-AR7OM4HI.cjs');
5
+
6
+
7
+ var _chunkYI62SDKVcjs = require('./chunk-YI62SDKV.cjs');
6
8
  require('./chunk-75ZPJI57.cjs');
7
9
 
8
10
  // src/client/client.ts
@@ -19,12 +21,169 @@ function accountActions(client) {
19
21
  method: "sim_fundAccount",
20
22
  params: [address, amount]
21
23
  });
24
+ },
25
+ getCurrentNonce: async ({ address }) => {
26
+ return client.request({
27
+ method: "eth_getTransactionCount",
28
+ params: [address || _optionalChain([client, 'access', _3 => _3.account, 'optionalAccess', _4 => _4.address])]
29
+ });
22
30
  }
23
31
  };
24
32
  }
25
33
 
26
- // src/contracts/actions.ts
34
+ // src/abi/calldata/encoder.ts
35
+
36
+ var BITS_IN_TYPE = 3;
37
+ var TYPE_SPECIAL = 0;
38
+ var TYPE_PINT = 1;
39
+ var TYPE_NINT = 2;
40
+ var TYPE_BYTES = 3;
41
+ var TYPE_STR = 4;
42
+ var TYPE_ARR = 5;
43
+ var TYPE_MAP = 6;
44
+ var SPECIAL_NULL = 0 << BITS_IN_TYPE | TYPE_SPECIAL;
45
+ var SPECIAL_FALSE = 1 << BITS_IN_TYPE | TYPE_SPECIAL;
46
+ var SPECIAL_TRUE = 2 << BITS_IN_TYPE | TYPE_SPECIAL;
47
+ var SPECIAL_ADDR = 3 << BITS_IN_TYPE | TYPE_SPECIAL;
48
+ function reportError(msg, data) {
49
+ throw new Error(`invalid calldata input '${data}'`);
50
+ }
51
+ function writeNum(to, data) {
52
+ if (data === 0n) {
53
+ to.push(0);
54
+ return;
55
+ }
56
+ while (data > 0) {
57
+ let cur = Number(data & 0x7fn);
58
+ data >>= 7n;
59
+ if (data > 0) {
60
+ cur |= 128;
61
+ }
62
+ to.push(cur);
63
+ }
64
+ }
65
+ function encodeNumWithType(to, data, type) {
66
+ const res = data << BigInt(BITS_IN_TYPE) | BigInt(type);
67
+ writeNum(to, res);
68
+ }
69
+ function encodeNum(to, data) {
70
+ if (data >= 0n) {
71
+ encodeNumWithType(to, data, TYPE_PINT);
72
+ } else {
73
+ encodeNumWithType(to, -data - 1n, TYPE_NINT);
74
+ }
75
+ }
76
+ function compareString(l, r) {
77
+ for (let index = 0; index < l.length && index < r.length; index++) {
78
+ const cur = l[index] - r[index];
79
+ if (cur !== 0) {
80
+ return cur;
81
+ }
82
+ }
83
+ return l.length - r.length;
84
+ }
85
+ function encodeMap(to, arr) {
86
+ const newEntries = Array.from(
87
+ arr,
88
+ ([k, v]) => [
89
+ Array.from(k, (x) => x.codePointAt(0)),
90
+ new TextEncoder().encode(k),
91
+ v
92
+ ]
93
+ );
94
+ newEntries.sort((v1, v2) => compareString(v1[0], v2[0]));
95
+ for (let i = 1; i < newEntries.length; i++) {
96
+ if (compareString(newEntries[i - 1][0], newEntries[i][0]) === 0) {
97
+ throw new Error(`duplicate key '${new TextDecoder().decode(newEntries[i][1])}'`);
98
+ }
99
+ }
100
+ encodeNumWithType(to, BigInt(newEntries.length), TYPE_MAP);
101
+ for (const [_k, k, v] of newEntries) {
102
+ writeNum(to, BigInt(k.length));
103
+ for (const c of k) {
104
+ to.push(c);
105
+ }
106
+ encodeImpl(to, v);
107
+ }
108
+ }
109
+ function encodeImpl(to, data) {
110
+ if (data === null || data === void 0) {
111
+ to.push(SPECIAL_NULL);
112
+ return;
113
+ }
114
+ if (data === true) {
115
+ to.push(SPECIAL_TRUE);
116
+ return;
117
+ }
118
+ if (data === false) {
119
+ to.push(SPECIAL_FALSE);
120
+ return;
121
+ }
122
+ switch (typeof data) {
123
+ case "number": {
124
+ if (!Number.isInteger(data)) {
125
+ reportError("floats are not supported", data);
126
+ }
127
+ encodeNum(to, BigInt(data));
128
+ return;
129
+ }
130
+ case "bigint": {
131
+ encodeNum(to, data);
132
+ return;
133
+ }
134
+ case "string": {
135
+ const str = new TextEncoder().encode(data);
136
+ encodeNumWithType(to, BigInt(str.length), TYPE_STR);
137
+ for (const c of str) {
138
+ to.push(c);
139
+ }
140
+ return;
141
+ }
142
+ case "object": {
143
+ if (data instanceof Uint8Array) {
144
+ encodeNumWithType(to, BigInt(data.length), TYPE_BYTES);
145
+ for (const c of data) {
146
+ to.push(c);
147
+ }
148
+ } else if (data instanceof Array) {
149
+ encodeNumWithType(to, BigInt(data.length), TYPE_ARR);
150
+ for (const c of data) {
151
+ encodeImpl(to, c);
152
+ }
153
+ } else if (data instanceof Map) {
154
+ encodeMap(to, data);
155
+ } else if (data instanceof _chunkYI62SDKVcjs.Address) {
156
+ to.push(SPECIAL_ADDR);
157
+ for (const c of data.bytes) {
158
+ to.push(c);
159
+ }
160
+ } else if (Object.getPrototypeOf(data) === Object.prototype) {
161
+ encodeMap(
162
+ to,
163
+ Object.keys(data).map((k) => [k, data[k]])
164
+ );
165
+ } else {
166
+ reportError("unknown object type", data);
167
+ }
168
+ return;
169
+ }
170
+ default:
171
+ reportError("unknown base type", data);
172
+ }
173
+ }
174
+ function encode(data) {
175
+ const arr = [];
176
+ encodeImpl(arr, data);
177
+ return new Uint8Array(arr);
178
+ }
179
+ function serialize(data) {
180
+ return _viem.toRlp.call(void 0, data.map((param) => _viem.toHex.call(void 0, param)));
181
+ }
182
+ function encodeAndSerialize(data) {
183
+ return serialize([encode(data)]);
184
+ }
27
185
 
186
+ // src/contracts/actions.ts
28
187
  var contractActions = (client) => {
29
188
  return {
30
189
  getContractSchema: async (address) => {
@@ -46,12 +205,10 @@ var contractActions = (client) => {
46
205
  var overrideContractActions = (client) => {
47
206
  client.readContract = async (args) => {
48
207
  const { account, address, functionName, args: params } = args;
49
- const methodParamsAsString = JSON.stringify(params);
50
- const data = [functionName, methodParamsAsString];
51
- const encodedData = _viem.toRlp.call(void 0, data.map((param) => _viem.toHex.call(void 0, param)));
208
+ const encodedData = encodeAndSerialize({ method: functionName, args: params });
52
209
  const requestParams = {
53
210
  to: address,
54
- from: _optionalChain([account, 'optionalAccess', _3 => _3.address]) || _optionalChain([client, 'access', _4 => _4.account, 'optionalAccess', _5 => _5.address]),
211
+ from: _optionalChain([account, 'optionalAccess', _5 => _5.address]) || _optionalChain([client, 'access', _6 => _6.account, 'optionalAccess', _7 => _7.address]),
55
212
  data: encodedData
56
213
  };
57
214
  const result = await client.request({
@@ -62,23 +219,48 @@ var overrideContractActions = (client) => {
62
219
  };
63
220
  client.writeContract = async (args) => {
64
221
  const { account, address, functionName, args: params, value = 0n } = args;
65
- const methodParamsAsString = JSON.stringify(params);
66
- const data = [functionName, methodParamsAsString];
67
- const encodedData = _viem.toRlp.call(void 0, data.map((param) => _viem.toHex.call(void 0, param)));
222
+ const encodedData = encodeAndSerialize({ method: functionName, args: params });
68
223
  const senderAccount = account || client.account;
69
224
  if (!senderAccount) {
70
225
  throw new Error(
71
226
  "No account set. Configure the client with an account or pass an account to this function."
72
227
  );
73
228
  }
74
- if (!_optionalChain([senderAccount, 'optionalAccess', _6 => _6.signTransaction])) {
229
+ if (!_optionalChain([senderAccount, 'optionalAccess', _8 => _8.signTransaction])) {
75
230
  throw new Error("Account does not support signTransaction");
76
231
  }
232
+ const nonce = await client.getCurrentNonce({ address: senderAccount.address });
77
233
  const signedTransaction = await senderAccount.signTransaction({
78
234
  data: encodedData,
79
235
  to: address,
80
236
  value,
81
- type: "legacy"
237
+ type: "legacy",
238
+ nonce
239
+ });
240
+ const result = await client.request({
241
+ method: "eth_sendRawTransaction",
242
+ params: [signedTransaction]
243
+ });
244
+ return result;
245
+ };
246
+ client.deployContract = async (args) => {
247
+ const { account, code, args: constructorArgs } = args;
248
+ const data = [code, encode({ args: constructorArgs })];
249
+ const serializedData = serialize(data);
250
+ const senderAccount = account || client.account;
251
+ if (!senderAccount) {
252
+ throw new Error(
253
+ "No account set. Configure the client with an account or pass an account to this function."
254
+ );
255
+ }
256
+ if (!_optionalChain([senderAccount, 'optionalAccess', _9 => _9.signTransaction])) {
257
+ throw new Error("Account does not support signTransaction");
258
+ }
259
+ const nonce = await client.getCurrentNonce({ address: senderAccount.address });
260
+ const signedTransaction = await senderAccount.signTransaction({
261
+ data: serializedData,
262
+ type: "legacy",
263
+ nonce
82
264
  });
83
265
  const result = await client.request({
84
266
  method: "eth_sendRawTransaction",
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as viem from 'viem';
2
2
  import { Transport, Account } from 'viem';
3
3
  import { S as SimulatorChain } from './chains-CtZJFz4Q.cjs';
4
- import { G as GenLayerClient } from './clients-CL75M8Ma.cjs';
4
+ import { G as GenLayerClient } from './clients-BamlAEcy.cjs';
5
5
  import * as abitype from 'abitype';
6
6
  import * as viem__types_experimental_eip7702_types_authorization from 'viem/_types/experimental/eip7702/types/authorization';
7
7
  import * as viem_accounts from 'viem/accounts';
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as viem from 'viem';
2
2
  import { Transport, Account } from 'viem';
3
3
  import { S as SimulatorChain } from './chains-CtZJFz4Q.js';
4
- import { G as GenLayerClient } from './clients-Bt_8fb_v.js';
4
+ import { G as GenLayerClient } from './clients-CJ820ePR.js';
5
5
  import * as abitype from 'abitype';
6
6
  import * as viem__types_experimental_eip7702_types_authorization from 'viem/_types/experimental/eip7702/types/authorization';
7
7
  import * as viem_accounts from 'viem/accounts';
package/dist/index.js CHANGED
@@ -2,7 +2,9 @@ import {
2
2
  chains_exports,
3
3
  simulator
4
4
  } from "./chunk-D7VZGQ4K.js";
5
- import "./chunk-VQTD5PMI.js";
5
+ import {
6
+ Address
7
+ } from "./chunk-M7SA3INM.js";
6
8
  import "./chunk-MLKGABMK.js";
7
9
 
8
10
  // src/client/client.ts
@@ -19,12 +21,169 @@ function accountActions(client) {
19
21
  method: "sim_fundAccount",
20
22
  params: [address, amount]
21
23
  });
24
+ },
25
+ getCurrentNonce: async ({ address }) => {
26
+ return client.request({
27
+ method: "eth_getTransactionCount",
28
+ params: [address || client.account?.address]
29
+ });
22
30
  }
23
31
  };
24
32
  }
25
33
 
34
+ // src/abi/calldata/encoder.ts
35
+ import { toHex, toRlp } from "viem";
36
+ var BITS_IN_TYPE = 3;
37
+ var TYPE_SPECIAL = 0;
38
+ var TYPE_PINT = 1;
39
+ var TYPE_NINT = 2;
40
+ var TYPE_BYTES = 3;
41
+ var TYPE_STR = 4;
42
+ var TYPE_ARR = 5;
43
+ var TYPE_MAP = 6;
44
+ var SPECIAL_NULL = 0 << BITS_IN_TYPE | TYPE_SPECIAL;
45
+ var SPECIAL_FALSE = 1 << BITS_IN_TYPE | TYPE_SPECIAL;
46
+ var SPECIAL_TRUE = 2 << BITS_IN_TYPE | TYPE_SPECIAL;
47
+ var SPECIAL_ADDR = 3 << BITS_IN_TYPE | TYPE_SPECIAL;
48
+ function reportError(msg, data) {
49
+ throw new Error(`invalid calldata input '${data}'`);
50
+ }
51
+ function writeNum(to, data) {
52
+ if (data === 0n) {
53
+ to.push(0);
54
+ return;
55
+ }
56
+ while (data > 0) {
57
+ let cur = Number(data & 0x7fn);
58
+ data >>= 7n;
59
+ if (data > 0) {
60
+ cur |= 128;
61
+ }
62
+ to.push(cur);
63
+ }
64
+ }
65
+ function encodeNumWithType(to, data, type) {
66
+ const res = data << BigInt(BITS_IN_TYPE) | BigInt(type);
67
+ writeNum(to, res);
68
+ }
69
+ function encodeNum(to, data) {
70
+ if (data >= 0n) {
71
+ encodeNumWithType(to, data, TYPE_PINT);
72
+ } else {
73
+ encodeNumWithType(to, -data - 1n, TYPE_NINT);
74
+ }
75
+ }
76
+ function compareString(l, r) {
77
+ for (let index = 0; index < l.length && index < r.length; index++) {
78
+ const cur = l[index] - r[index];
79
+ if (cur !== 0) {
80
+ return cur;
81
+ }
82
+ }
83
+ return l.length - r.length;
84
+ }
85
+ function encodeMap(to, arr) {
86
+ const newEntries = Array.from(
87
+ arr,
88
+ ([k, v]) => [
89
+ Array.from(k, (x) => x.codePointAt(0)),
90
+ new TextEncoder().encode(k),
91
+ v
92
+ ]
93
+ );
94
+ newEntries.sort((v1, v2) => compareString(v1[0], v2[0]));
95
+ for (let i = 1; i < newEntries.length; i++) {
96
+ if (compareString(newEntries[i - 1][0], newEntries[i][0]) === 0) {
97
+ throw new Error(`duplicate key '${new TextDecoder().decode(newEntries[i][1])}'`);
98
+ }
99
+ }
100
+ encodeNumWithType(to, BigInt(newEntries.length), TYPE_MAP);
101
+ for (const [_k, k, v] of newEntries) {
102
+ writeNum(to, BigInt(k.length));
103
+ for (const c of k) {
104
+ to.push(c);
105
+ }
106
+ encodeImpl(to, v);
107
+ }
108
+ }
109
+ function encodeImpl(to, data) {
110
+ if (data === null || data === void 0) {
111
+ to.push(SPECIAL_NULL);
112
+ return;
113
+ }
114
+ if (data === true) {
115
+ to.push(SPECIAL_TRUE);
116
+ return;
117
+ }
118
+ if (data === false) {
119
+ to.push(SPECIAL_FALSE);
120
+ return;
121
+ }
122
+ switch (typeof data) {
123
+ case "number": {
124
+ if (!Number.isInteger(data)) {
125
+ reportError("floats are not supported", data);
126
+ }
127
+ encodeNum(to, BigInt(data));
128
+ return;
129
+ }
130
+ case "bigint": {
131
+ encodeNum(to, data);
132
+ return;
133
+ }
134
+ case "string": {
135
+ const str = new TextEncoder().encode(data);
136
+ encodeNumWithType(to, BigInt(str.length), TYPE_STR);
137
+ for (const c of str) {
138
+ to.push(c);
139
+ }
140
+ return;
141
+ }
142
+ case "object": {
143
+ if (data instanceof Uint8Array) {
144
+ encodeNumWithType(to, BigInt(data.length), TYPE_BYTES);
145
+ for (const c of data) {
146
+ to.push(c);
147
+ }
148
+ } else if (data instanceof Array) {
149
+ encodeNumWithType(to, BigInt(data.length), TYPE_ARR);
150
+ for (const c of data) {
151
+ encodeImpl(to, c);
152
+ }
153
+ } else if (data instanceof Map) {
154
+ encodeMap(to, data);
155
+ } else if (data instanceof Address) {
156
+ to.push(SPECIAL_ADDR);
157
+ for (const c of data.bytes) {
158
+ to.push(c);
159
+ }
160
+ } else if (Object.getPrototypeOf(data) === Object.prototype) {
161
+ encodeMap(
162
+ to,
163
+ Object.keys(data).map((k) => [k, data[k]])
164
+ );
165
+ } else {
166
+ reportError("unknown object type", data);
167
+ }
168
+ return;
169
+ }
170
+ default:
171
+ reportError("unknown base type", data);
172
+ }
173
+ }
174
+ function encode(data) {
175
+ const arr = [];
176
+ encodeImpl(arr, data);
177
+ return new Uint8Array(arr);
178
+ }
179
+ function serialize(data) {
180
+ return toRlp(data.map((param) => toHex(param)));
181
+ }
182
+ function encodeAndSerialize(data) {
183
+ return serialize([encode(data)]);
184
+ }
185
+
26
186
  // src/contracts/actions.ts
27
- import { toRlp, toHex } from "viem";
28
187
  var contractActions = (client) => {
29
188
  return {
30
189
  getContractSchema: async (address) => {
@@ -46,9 +205,7 @@ var contractActions = (client) => {
46
205
  var overrideContractActions = (client) => {
47
206
  client.readContract = async (args) => {
48
207
  const { account, address, functionName, args: params } = args;
49
- const methodParamsAsString = JSON.stringify(params);
50
- const data = [functionName, methodParamsAsString];
51
- const encodedData = toRlp(data.map((param) => toHex(param)));
208
+ const encodedData = encodeAndSerialize({ method: functionName, args: params });
52
209
  const requestParams = {
53
210
  to: address,
54
211
  from: account?.address || client.account?.address,
@@ -62,9 +219,7 @@ var overrideContractActions = (client) => {
62
219
  };
63
220
  client.writeContract = async (args) => {
64
221
  const { account, address, functionName, args: params, value = 0n } = args;
65
- const methodParamsAsString = JSON.stringify(params);
66
- const data = [functionName, methodParamsAsString];
67
- const encodedData = toRlp(data.map((param) => toHex(param)));
222
+ const encodedData = encodeAndSerialize({ method: functionName, args: params });
68
223
  const senderAccount = account || client.account;
69
224
  if (!senderAccount) {
70
225
  throw new Error(
@@ -74,11 +229,38 @@ var overrideContractActions = (client) => {
74
229
  if (!senderAccount?.signTransaction) {
75
230
  throw new Error("Account does not support signTransaction");
76
231
  }
232
+ const nonce = await client.getCurrentNonce({ address: senderAccount.address });
77
233
  const signedTransaction = await senderAccount.signTransaction({
78
234
  data: encodedData,
79
235
  to: address,
80
236
  value,
81
- type: "legacy"
237
+ type: "legacy",
238
+ nonce
239
+ });
240
+ const result = await client.request({
241
+ method: "eth_sendRawTransaction",
242
+ params: [signedTransaction]
243
+ });
244
+ return result;
245
+ };
246
+ client.deployContract = async (args) => {
247
+ const { account, code, args: constructorArgs } = args;
248
+ const data = [code, encode({ args: constructorArgs })];
249
+ const serializedData = serialize(data);
250
+ const senderAccount = account || client.account;
251
+ if (!senderAccount) {
252
+ throw new Error(
253
+ "No account set. Configure the client with an account or pass an account to this function."
254
+ );
255
+ }
256
+ if (!senderAccount?.signTransaction) {
257
+ throw new Error("Account does not support signTransaction");
258
+ }
259
+ const nonce = await client.getCurrentNonce({ address: senderAccount.address });
260
+ const signedTransaction = await senderAccount.signTransaction({
261
+ data: serializedData,
262
+ type: "legacy",
263
+ nonce
82
264
  });
83
265
  const result = await client.request({
84
266
  method: "eth_sendRawTransaction",
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkAR7OM4HIcjs = require('../chunk-AR7OM4HI.cjs');
3
+ var _chunkYI62SDKVcjs = require('../chunk-YI62SDKV.cjs');
4
4
  require('../chunk-75ZPJI57.cjs');
5
5
 
6
6
  // src/types/accounts.ts
@@ -8,4 +8,4 @@ var _viem = require('viem');
8
8
 
9
9
 
10
10
 
11
- exports.Account = _viem.Account; exports.TransactionStatus = _chunkAR7OM4HIcjs.TransactionStatus;
11
+ exports.Account = _viem.Account; exports.TransactionStatus = _chunkYI62SDKVcjs.TransactionStatus;
@@ -1,4 +1,4 @@
1
- export { A as Address, G as GenLayerClient, a as GenLayerMethod, c as GenLayerTransaction, T as TransactionHash, b as TransactionStatus } from '../clients-CL75M8Ma.cjs';
1
+ export { A as Address, C as CalldataEncodable, G as GenLayerClient, a as GenLayerMethod, d as GenLayerTransaction, M as MethodDescription, T as TransactionData, e as TransactionDataElement, b as TransactionHash, c as TransactionStatus } from '../clients-BamlAEcy.cjs';
2
2
  export { S as SimulatorChain } from '../chains-CtZJFz4Q.cjs';
3
3
  export { Account } from 'viem';
4
4
 
@@ -1,4 +1,4 @@
1
- export { A as Address, G as GenLayerClient, a as GenLayerMethod, c as GenLayerTransaction, T as TransactionHash, b as TransactionStatus } from '../clients-Bt_8fb_v.js';
1
+ export { A as Address, C as CalldataEncodable, G as GenLayerClient, a as GenLayerMethod, d as GenLayerTransaction, M as MethodDescription, T as TransactionData, e as TransactionDataElement, b as TransactionHash, c as TransactionStatus } from '../clients-CJ820ePR.js';
2
2
  export { S as SimulatorChain } from '../chains-CtZJFz4Q.js';
3
3
  export { Account } from 'viem';
4
4
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TransactionStatus
3
- } from "../chunk-VQTD5PMI.js";
3
+ } from "../chunk-M7SA3INM.js";
4
4
  import "../chunk-MLKGABMK.js";
5
5
 
6
6
  // src/types/accounts.ts
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "genlayer-js",
3
3
  "type": "module",
4
- "version": "0.1.2",
4
+ "version": "0.3.0",
5
5
  "description": "GenLayer JavaScript SDK",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -49,6 +49,7 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "eslint-plugin-import": "^2.30.0",
52
+ "typescript-parsec": "^0.3.4",
52
53
  "viem": "^2.21.7"
53
54
  }
54
55
  }
@@ -0,0 +1,168 @@
1
+ import {toHex, toRlp} from "viem";
2
+ import type {CalldataEncodable, TransactionDataElement} from "../../types/calldata";
3
+ 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;
19
+
20
+ function reportError(msg: string, data: CalldataEncodable): never {
21
+ throw new Error(`invalid calldata input '${data}'`);
22
+ }
23
+
24
+ function writeNum(to: number[], data: bigint) {
25
+ if (data === 0n) {
26
+ to.push(0);
27
+ return;
28
+ }
29
+ while (data > 0) {
30
+ let cur = Number(data & 0x7fn);
31
+ data >>= 7n;
32
+ if (data > 0) {
33
+ cur |= 0x80;
34
+ }
35
+ to.push(cur);
36
+ }
37
+ }
38
+
39
+ function encodeNumWithType(to: number[], data: bigint, type: number) {
40
+ const res = (data << BigInt(BITS_IN_TYPE)) | BigInt(type);
41
+ writeNum(to, res);
42
+ }
43
+
44
+ function encodeNum(to: number[], data: bigint) {
45
+ if (data >= 0n) {
46
+ encodeNumWithType(to, data, TYPE_PINT);
47
+ } else {
48
+ encodeNumWithType(to, -data - 1n, TYPE_NINT);
49
+ }
50
+ }
51
+
52
+ function compareString(l: number[], r: number[]): number {
53
+ for (let index = 0; index < l.length && index < r.length; index++) {
54
+ const cur = l[index] - r[index];
55
+ if (cur !== 0) {
56
+ return cur;
57
+ }
58
+ }
59
+ return l.length - r.length;
60
+ }
61
+
62
+ function encodeMap(to: number[], arr: Iterable<[string, CalldataEncodable]>) {
63
+ // unicode code points array, utf8 encoded array, item
64
+ const newEntries: [number[], Uint8Array, CalldataEncodable][] = Array.from(
65
+ arr,
66
+ ([k, v]): [number[], Uint8Array, CalldataEncodable] => [
67
+ Array.from(k, x => x.codePointAt(0)!),
68
+ new TextEncoder().encode(k),
69
+ v,
70
+ ],
71
+ );
72
+ newEntries.sort((v1, v2) => compareString(v1[0], v2[0]));
73
+ for (let i = 1; i < newEntries.length; i++) {
74
+ if (compareString(newEntries[i - 1][0], newEntries[i][0]) === 0) {
75
+ throw new Error(`duplicate key '${new TextDecoder().decode(newEntries[i][1])}'`);
76
+ }
77
+ }
78
+
79
+ encodeNumWithType(to, BigInt(newEntries.length), TYPE_MAP);
80
+ for (const [_k, k, v] of newEntries) {
81
+ writeNum(to, BigInt(k.length));
82
+ for (const c of k) {
83
+ to.push(c);
84
+ }
85
+ encodeImpl(to, v);
86
+ }
87
+ }
88
+
89
+ function encodeImpl(to: number[], data: CalldataEncodable) {
90
+ if (data === null || data === undefined) {
91
+ to.push(SPECIAL_NULL);
92
+ return;
93
+ }
94
+ if (data === true) {
95
+ to.push(SPECIAL_TRUE);
96
+ return;
97
+ }
98
+ if (data === false) {
99
+ to.push(SPECIAL_FALSE);
100
+ return;
101
+ }
102
+ switch (typeof data) {
103
+ case "number": {
104
+ if (!Number.isInteger(data)) {
105
+ reportError("floats are not supported", data);
106
+ }
107
+ encodeNum(to, BigInt(data));
108
+ return;
109
+ }
110
+ case "bigint": {
111
+ encodeNum(to, data);
112
+ return;
113
+ }
114
+ case "string": {
115
+ const str = new TextEncoder().encode(data);
116
+ encodeNumWithType(to, BigInt(str.length), TYPE_STR);
117
+ for (const c of str) {
118
+ to.push(c);
119
+ }
120
+ return;
121
+ }
122
+ case "object": {
123
+ if (data instanceof Uint8Array) {
124
+ encodeNumWithType(to, BigInt(data.length), TYPE_BYTES);
125
+ for (const c of data) {
126
+ to.push(c);
127
+ }
128
+ } else if (data instanceof Array) {
129
+ encodeNumWithType(to, BigInt(data.length), TYPE_ARR);
130
+ for (const c of data) {
131
+ encodeImpl(to, c);
132
+ }
133
+ } else if (data instanceof Map) {
134
+ encodeMap(to, data);
135
+ } else if (data instanceof Address) {
136
+ to.push(SPECIAL_ADDR);
137
+ for (const c of data.bytes) {
138
+ to.push(c);
139
+ }
140
+ } else if (Object.getPrototypeOf(data) === Object.prototype) {
141
+ encodeMap(
142
+ to,
143
+ Object.keys(data).map((k): [string, CalldataEncodable] => [k, data[k]]),
144
+ );
145
+ } else {
146
+ reportError("unknown object type", data);
147
+ }
148
+ return;
149
+ }
150
+ default:
151
+ reportError("unknown base type", data);
152
+ }
153
+ }
154
+
155
+ export function encode(data: CalldataEncodable): Uint8Array {
156
+ // FIXME: find a better growable type
157
+ const arr: number[] = [];
158
+ encodeImpl(arr, data);
159
+ return new Uint8Array(arr);
160
+ }
161
+
162
+ export function serialize(data: TransactionDataElement[]): `0x${string}` {
163
+ return toRlp(data.map(param => toHex(param)));
164
+ }
165
+
166
+ export function encodeAndSerialize(data: CalldataEncodable): `0x${string}` {
167
+ return serialize([encode(data)]);
168
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./calldata/encoder";
2
+ export * from "./calldata/parser";
@@ -18,5 +18,11 @@ export function accountActions<
18
18
  params: [address, amount],
19
19
  }) as Promise<TransactionHash>;
20
20
  },
21
+ getCurrentNonce: async ({address}: {address: string}): Promise<number> => {
22
+ return client.request({
23
+ method: "eth_getTransactionCount",
24
+ params: [address || client.account?.address],
25
+ }) as Promise<number>;
26
+ },
21
27
  };
22
28
  }
@@ -1,7 +1,7 @@
1
- import {toRlp, toHex, Transport, Account, Address} from "viem";
1
+ import {Transport, Account, Address} from "viem";
2
2
 
3
- import {ContractSchema, SimulatorChain, GenLayerClient} from "@/types";
4
- import {createAccount} from "@/accounts/account";
3
+ import {encode, serialize, encodeAndSerialize} from "@/abi/calldata/encoder";
4
+ import {ContractSchema, SimulatorChain, GenLayerClient, CalldataEncodable} from "@/types";
5
5
 
6
6
  export const contractActions = (client: GenLayerClient<Transport, SimulatorChain, Account>) => {
7
7
  return {
@@ -27,12 +27,10 @@ export const overrideContractActions = (client: GenLayerClient<Transport, Simula
27
27
  account: Account;
28
28
  address: Address;
29
29
  functionName: string;
30
- args: any[];
30
+ args: CalldataEncodable[];
31
31
  }): Promise<any> => {
32
32
  const {account, address, functionName, args: params} = args;
33
- const methodParamsAsString = JSON.stringify(params);
34
- const data = [functionName, methodParamsAsString];
35
- const encodedData = toRlp(data.map(param => toHex(param)));
33
+ const encodedData = encodeAndSerialize({method: functionName, args: params});
36
34
 
37
35
  const requestParams = {
38
36
  to: address,
@@ -50,13 +48,11 @@ export const overrideContractActions = (client: GenLayerClient<Transport, Simula
50
48
  account: Account;
51
49
  address: Address;
52
50
  functionName: string;
53
- args: any[];
51
+ args: CalldataEncodable[];
54
52
  value: bigint;
55
53
  }): Promise<any> => {
56
54
  const {account, address, functionName, args: params, value = 0n} = args;
57
- const methodParamsAsString = JSON.stringify(params);
58
- const data = [functionName, methodParamsAsString];
59
- const encodedData = toRlp(data.map(param => toHex(param)));
55
+ const encodedData = encodeAndSerialize({method: functionName, args: params});
60
56
 
61
57
  const senderAccount = account || client.account;
62
58
  if (!senderAccount) {
@@ -69,11 +65,14 @@ export const overrideContractActions = (client: GenLayerClient<Transport, Simula
69
65
  throw new Error("Account does not support signTransaction");
70
66
  }
71
67
 
68
+ const nonce = await client.getCurrentNonce({address: senderAccount.address});
69
+
72
70
  const signedTransaction = await senderAccount.signTransaction({
73
71
  data: encodedData,
74
72
  to: address,
75
73
  value,
76
74
  type: "legacy",
75
+ nonce,
77
76
  });
78
77
  const result = await client.request({
79
78
  method: "eth_sendRawTransaction",
@@ -82,5 +81,36 @@ export const overrideContractActions = (client: GenLayerClient<Transport, Simula
82
81
  return result;
83
82
  };
84
83
 
84
+ client.deployContract = async (args: {account: Account; code: string; args: CalldataEncodable[]}) => {
85
+ const {account, code, args: constructorArgs} = args;
86
+ const data = [code, encode({args: constructorArgs})];
87
+ const serializedData = serialize(data);
88
+
89
+ const senderAccount = account || client.account;
90
+ if (!senderAccount) {
91
+ throw new Error(
92
+ "No account set. Configure the client with an account or pass an account to this function.",
93
+ );
94
+ }
95
+
96
+ if (!senderAccount?.signTransaction) {
97
+ throw new Error("Account does not support signTransaction");
98
+ }
99
+
100
+ const nonce = await client.getCurrentNonce({address: senderAccount.address});
101
+
102
+ const signedTransaction = await senderAccount.signTransaction({
103
+ data: serializedData,
104
+ type: "legacy",
105
+ nonce,
106
+ });
107
+
108
+ const result = await client.request({
109
+ method: "eth_sendRawTransaction",
110
+ params: [signedTransaction],
111
+ });
112
+ return result;
113
+ };
114
+
85
115
  return client;
86
116
  };
@@ -0,0 +1,38 @@
1
+ export class Address {
2
+ bytes: Uint8Array;
3
+
4
+ constructor(addr: Uint8Array) {
5
+ if (addr.length != 32) {
6
+ throw new Error(`invalid address length ${addr}`);
7
+ }
8
+
9
+ this.bytes = addr;
10
+ }
11
+ }
12
+
13
+ export type CalldataEncodable =
14
+ | null
15
+ | boolean
16
+ | Address
17
+ | number
18
+ | bigint
19
+ | string
20
+ | Uint8Array /// bytes
21
+ | Address
22
+ | Array<CalldataEncodable>
23
+ | Map<string, CalldataEncodable>
24
+ | {[key: string]: CalldataEncodable}; /// also a "map"
25
+
26
+ export type MethodDescription = {
27
+ method: string;
28
+
29
+ args: Array<CalldataEncodable>;
30
+ };
31
+
32
+ export type TransactionData = {
33
+ method: string;
34
+
35
+ args: CalldataEncodable[];
36
+ };
37
+
38
+ export type TransactionDataElement = string | number | bigint | boolean | Uint8Array;
@@ -2,6 +2,7 @@ import {Account, Transport, Client} from "viem";
2
2
  import {GenLayerTransaction, TransactionHash} from "./transactions";
3
3
  import {SimulatorChain} from "./chains";
4
4
  import {Address} from "./accounts";
5
+ import {CalldataEncodable} from "./calldata";
5
6
 
6
7
  export type GenLayerMethod =
7
8
  | {method: "sim_fundAccount"; params: [address: string, amount: number]}
@@ -9,7 +10,8 @@ export type GenLayerMethod =
9
10
  | {method: "eth_call"; params: [requestParams: any, blockNumberOrHash: string]}
10
11
  | {method: "eth_sedRawTransaction"; params: [signedTransaction: string]}
11
12
  | {method: "gen_getContractSchema"; params: [address: string]}
12
- | {method: "gen_getContractSchemaForCode"; params: [contractCode: string]};
13
+ | {method: "gen_getContractSchemaForCode"; params: [contractCode: string]}
14
+ | {method: "eth_getTransactionCount"; params: [address: string]};
13
15
 
14
16
  export type GenLayerClient<
15
17
  TTransport extends Transport,
@@ -34,5 +36,7 @@ export type GenLayerClient<
34
36
  args: any[];
35
37
  value: bigint;
36
38
  }) => Promise<any>;
39
+ deployContract: (args: {account: Account; code: string; args: CalldataEncodable[]}) => Promise<any>;
37
40
  getTransaction: (args: {hash: TransactionHash}) => Promise<GenLayerTransaction>;
41
+ getCurrentNonce: (args: {address: string}) => Promise<number>;
38
42
  };
@@ -1,4 +1,5 @@
1
1
  export * from "./accounts";
2
+ export {CalldataEncodable, MethodDescription, TransactionData} from "./calldata";
2
3
  export * from "./chains";
3
4
  export * from "./clients";
4
5
  export * from "./contracts";
@@ -27,3 +27,5 @@ export type GenLayerTransaction = {
27
27
  s?: number;
28
28
  v?: number;
29
29
  };
30
+
31
+ export type TransactionDataElement = string | number | bigint | boolean | Uint8Array;