genlayer-js 0.1.1 → 0.2.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,14 @@
1
1
 
2
2
 
3
+ ## 0.2.0 (2024-10-17)
4
+
5
+
6
+ ### Features
7
+
8
+ * implement genvm calldata ([#14](https://github.com/yeagerai/genlayer-js/issues/14)) ([d9a1abd](https://github.com/yeagerai/genlayer-js/commit/d9a1abdfb5eef13e5c77433db546953369087e04))
9
+
10
+ ## 0.1.2 (2024-10-03)
11
+
3
12
  ## 0.1.1 (2024-10-03)
4
13
 
5
14
  ## 0.1.0 (2024-10-01)
package/README.md CHANGED
@@ -85,7 +85,7 @@ _* under development_
85
85
 
86
86
  ## 📖 Documentation
87
87
 
88
- For detailed information on how to use GenLayerJS SDK, please refer to our [documentation](https://docs.genlayer.io/).
88
+ For detailed information on how to use GenLayerJS SDK, please refer to our [documentation](https://docs.genlayer.com/).
89
89
 
90
90
 
91
91
 
@@ -95,4 +95,4 @@ We welcome contributions to GenLayerJS SDK! Whether it's new features, improved
95
95
 
96
96
  ## License
97
97
 
98
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
98
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -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;
@@ -34,6 +34,7 @@ type GenLayerTransaction = {
34
34
  s?: number;
35
35
  v?: number;
36
36
  };
37
+ type TransactionDataElement = string | number | bigint | boolean | Uint8Array;
37
38
 
38
39
  type GenLayerMethod = {
39
40
  method: "sim_fundAccount";
@@ -53,6 +54,9 @@ type GenLayerMethod = {
53
54
  } | {
54
55
  method: "gen_getContractSchemaForCode";
55
56
  params: [contractCode: string];
57
+ } | {
58
+ method: "eth_getTransactionCount";
59
+ params: [address: string];
56
60
  };
57
61
  type GenLayerClient<TTransport extends Transport, TSimulatorChain extends SimulatorChain, TAccount extends Account> = Client<TTransport, TSimulatorChain, TAccount> & {
58
62
  request: Client<TTransport, TSimulatorChain, TAccount>["request"] & {
@@ -76,6 +80,9 @@ type GenLayerClient<TTransport extends Transport, TSimulatorChain extends Simula
76
80
  getTransaction: (args: {
77
81
  hash: TransactionHash;
78
82
  }) => Promise<GenLayerTransaction>;
83
+ getCurrentNonce: (args: {
84
+ address: string;
85
+ }) => Promise<number>;
79
86
  };
80
87
 
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 };
88
+ export { type Address as A, type GenLayerClient as G, type TransactionHash as T, type GenLayerMethod as a, TransactionStatus as b, type GenLayerTransaction as c, type TransactionDataElement as d };
@@ -34,6 +34,7 @@ type GenLayerTransaction = {
34
34
  s?: number;
35
35
  v?: number;
36
36
  };
37
+ type TransactionDataElement = string | number | bigint | boolean | Uint8Array;
37
38
 
38
39
  type GenLayerMethod = {
39
40
  method: "sim_fundAccount";
@@ -53,6 +54,9 @@ type GenLayerMethod = {
53
54
  } | {
54
55
  method: "gen_getContractSchemaForCode";
55
56
  params: [contractCode: string];
57
+ } | {
58
+ method: "eth_getTransactionCount";
59
+ params: [address: string];
56
60
  };
57
61
  type GenLayerClient<TTransport extends Transport, TSimulatorChain extends SimulatorChain, TAccount extends Account> = Client<TTransport, TSimulatorChain, TAccount> & {
58
62
  request: Client<TTransport, TSimulatorChain, TAccount>["request"] & {
@@ -76,6 +80,9 @@ type GenLayerClient<TTransport extends Transport, TSimulatorChain extends Simula
76
80
  getTransaction: (args: {
77
81
  hash: TransactionHash;
78
82
  }) => Promise<GenLayerTransaction>;
83
+ getCurrentNonce: (args: {
84
+ address: string;
85
+ }) => Promise<number>;
79
86
  };
80
87
 
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 };
88
+ export { type Address as A, type GenLayerClient as G, type TransactionHash as T, type GenLayerMethod as a, TransactionStatus as b, type GenLayerTransaction as c, type TransactionDataElement as d };
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,164 @@ 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
+ const encodedData = new Uint8Array(arr);
178
+ return _viem.toRlp.call(void 0, [encodedData].map((param) => _viem.toHex.call(void 0, param)));
179
+ }
27
180
 
181
+ // src/contracts/actions.ts
28
182
  var contractActions = (client) => {
29
183
  return {
30
184
  getContractSchema: async (address) => {
@@ -46,12 +200,10 @@ var contractActions = (client) => {
46
200
  var overrideContractActions = (client) => {
47
201
  client.readContract = async (args) => {
48
202
  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)));
203
+ const encodedData = encode({ method: functionName, args: params });
52
204
  const requestParams = {
53
205
  to: address,
54
- from: _optionalChain([account, 'optionalAccess', _3 => _3.address]) || _optionalChain([client, 'access', _4 => _4.account, 'optionalAccess', _5 => _5.address]),
206
+ from: _optionalChain([account, 'optionalAccess', _5 => _5.address]) || _optionalChain([client, 'access', _6 => _6.account, 'optionalAccess', _7 => _7.address]),
55
207
  data: encodedData
56
208
  };
57
209
  const result = await client.request({
@@ -62,23 +214,23 @@ var overrideContractActions = (client) => {
62
214
  };
63
215
  client.writeContract = async (args) => {
64
216
  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)));
217
+ const encodedData = encode({ method: functionName, args: params });
68
218
  const senderAccount = account || client.account;
69
219
  if (!senderAccount) {
70
220
  throw new Error(
71
221
  "No account set. Configure the client with an account or pass an account to this function."
72
222
  );
73
223
  }
74
- if (!_optionalChain([senderAccount, 'optionalAccess', _6 => _6.signTransaction])) {
224
+ if (!_optionalChain([senderAccount, 'optionalAccess', _8 => _8.signTransaction])) {
75
225
  throw new Error("Account does not support signTransaction");
76
226
  }
227
+ const nonce = await client.getCurrentNonce({ address: senderAccount.address });
77
228
  const signedTransaction = await senderAccount.signTransaction({
78
229
  data: encodedData,
79
230
  to: address,
80
231
  value,
81
- type: "legacy"
232
+ type: "legacy",
233
+ nonce
82
234
  });
83
235
  const result = await client.request({
84
236
  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-B1y56AIF.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-C-WgCMQF.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,164 @@ 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
+ const encodedData = new Uint8Array(arr);
178
+ return toRlp([encodedData].map((param) => toHex(param)));
179
+ }
180
+
26
181
  // src/contracts/actions.ts
27
- import { toRlp, toHex } from "viem";
28
182
  var contractActions = (client) => {
29
183
  return {
30
184
  getContractSchema: async (address) => {
@@ -46,9 +200,7 @@ var contractActions = (client) => {
46
200
  var overrideContractActions = (client) => {
47
201
  client.readContract = async (args) => {
48
202
  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)));
203
+ const encodedData = encode({ method: functionName, args: params });
52
204
  const requestParams = {
53
205
  to: address,
54
206
  from: account?.address || client.account?.address,
@@ -62,9 +214,7 @@ var overrideContractActions = (client) => {
62
214
  };
63
215
  client.writeContract = async (args) => {
64
216
  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)));
217
+ const encodedData = encode({ method: functionName, args: params });
68
218
  const senderAccount = account || client.account;
69
219
  if (!senderAccount) {
70
220
  throw new Error(
@@ -74,11 +224,13 @@ var overrideContractActions = (client) => {
74
224
  if (!senderAccount?.signTransaction) {
75
225
  throw new Error("Account does not support signTransaction");
76
226
  }
227
+ const nonce = await client.getCurrentNonce({ address: senderAccount.address });
77
228
  const signedTransaction = await senderAccount.signTransaction({
78
229
  data: encodedData,
79
230
  to: address,
80
231
  value,
81
- type: "legacy"
232
+ type: "legacy",
233
+ nonce
82
234
  });
83
235
  const result = await client.request({
84
236
  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,7 +1,23 @@
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, G as GenLayerClient, a as GenLayerMethod, c as GenLayerTransaction, d as TransactionDataElement, T as TransactionHash, b as TransactionStatus } from '../clients-B1y56AIF.cjs';
2
2
  export { S as SimulatorChain } from '../chains-CtZJFz4Q.cjs';
3
3
  export { Account } from 'viem';
4
4
 
5
+ declare class Address {
6
+ bytes: Uint8Array;
7
+ constructor(addr: Uint8Array);
8
+ }
9
+ type CalldataEncodable = null | boolean | Address | number | bigint | string | Uint8Array | Address | Array<CalldataEncodable> | Map<string, CalldataEncodable> | {
10
+ [key: string]: CalldataEncodable;
11
+ };
12
+ type MethodDescription = {
13
+ method: string;
14
+ args: Array<CalldataEncodable>;
15
+ };
16
+ type TransactionData = {
17
+ method: string;
18
+ args: CalldataEncodable[];
19
+ };
20
+
5
21
  type ContractSchema = {
6
22
  abi: Array<{
7
23
  inputs?: Array<{
@@ -18,4 +34,4 @@ type ContractSchema = {
18
34
  class: string;
19
35
  };
20
36
 
21
- export type { ContractSchema };
37
+ export type { CalldataEncodable, ContractSchema, MethodDescription, TransactionData };
@@ -1,7 +1,23 @@
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, G as GenLayerClient, a as GenLayerMethod, c as GenLayerTransaction, d as TransactionDataElement, T as TransactionHash, b as TransactionStatus } from '../clients-C-WgCMQF.js';
2
2
  export { S as SimulatorChain } from '../chains-CtZJFz4Q.js';
3
3
  export { Account } from 'viem';
4
4
 
5
+ declare class Address {
6
+ bytes: Uint8Array;
7
+ constructor(addr: Uint8Array);
8
+ }
9
+ type CalldataEncodable = null | boolean | Address | number | bigint | string | Uint8Array | Address | Array<CalldataEncodable> | Map<string, CalldataEncodable> | {
10
+ [key: string]: CalldataEncodable;
11
+ };
12
+ type MethodDescription = {
13
+ method: string;
14
+ args: Array<CalldataEncodable>;
15
+ };
16
+ type TransactionData = {
17
+ method: string;
18
+ args: CalldataEncodable[];
19
+ };
20
+
5
21
  type ContractSchema = {
6
22
  abi: Array<{
7
23
  inputs?: Array<{
@@ -18,4 +34,4 @@ type ContractSchema = {
18
34
  class: string;
19
35
  };
20
36
 
21
- export type { ContractSchema };
37
+ export type { CalldataEncodable, ContractSchema, MethodDescription, TransactionData };
@@ -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.1",
4
+ "version": "0.2.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,161 @@
1
+ import {toHex, toRlp} from "viem";
2
+ import type {CalldataEncodable} 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): `0x${string}` {
156
+ // FIXME: find a better growable type
157
+ const arr: number[] = [];
158
+ encodeImpl(arr, data);
159
+ const encodedData = new Uint8Array(arr);
160
+ return toRlp([encodedData].map(param => toHex(param)));
161
+ }
@@ -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} 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 = encode({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 = encode({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",
@@ -0,0 +1,36 @@
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
+ };
@@ -9,7 +9,8 @@ export type GenLayerMethod =
9
9
  | {method: "eth_call"; params: [requestParams: any, blockNumberOrHash: string]}
10
10
  | {method: "eth_sedRawTransaction"; params: [signedTransaction: string]}
11
11
  | {method: "gen_getContractSchema"; params: [address: string]}
12
- | {method: "gen_getContractSchemaForCode"; params: [contractCode: string]};
12
+ | {method: "gen_getContractSchemaForCode"; params: [contractCode: string]}
13
+ | {method: "eth_getTransactionCount"; params: [address: string]};
13
14
 
14
15
  export type GenLayerClient<
15
16
  TTransport extends Transport,
@@ -35,4 +36,5 @@ export type GenLayerClient<
35
36
  value: bigint;
36
37
  }) => Promise<any>;
37
38
  getTransaction: (args: {hash: TransactionHash}) => Promise<GenLayerTransaction>;
39
+ getCurrentNonce: (args: {address: string}) => Promise<number>;
38
40
  };
@@ -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;