genlayer-js 0.4.7 → 0.4.8

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,12 @@
1
1
 
2
2
 
3
+ ## 0.4.8 (2024-12-18)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * added GenVM decoder to readContract method ([#42](https://github.com/yeagerai/genlayer-js/issues/42)) ([096d36d](https://github.com/yeagerai/genlayer-js/commit/096d36de06d3f4d341f6532ddead694c1882651d))
9
+
3
10
  ## 0.4.7 (2024-12-03)
4
11
 
5
12
  ## 0.4.6 (2024-12-02)
package/dist/index.cjs CHANGED
@@ -35,8 +35,7 @@ function accountActions(client) {
35
35
  };
36
36
  }
37
37
 
38
- // src/abi/calldata/encoder.ts
39
-
38
+ // src/abi/calldata/consts.ts
40
39
  var BITS_IN_TYPE = 3;
41
40
  var TYPE_SPECIAL = 0;
42
41
  var TYPE_PINT = 1;
@@ -49,6 +48,92 @@ var SPECIAL_NULL = 0 << BITS_IN_TYPE | TYPE_SPECIAL;
49
48
  var SPECIAL_FALSE = 1 << BITS_IN_TYPE | TYPE_SPECIAL;
50
49
  var SPECIAL_TRUE = 2 << BITS_IN_TYPE | TYPE_SPECIAL;
51
50
  var SPECIAL_ADDR = 3 << BITS_IN_TYPE | TYPE_SPECIAL;
51
+
52
+ // src/abi/calldata/decoder.ts
53
+ function readULeb128(data, index) {
54
+ let res = 0n;
55
+ let accum = 0n;
56
+ let shouldContinue = true;
57
+ while (shouldContinue) {
58
+ const byte = data[index.i];
59
+ index.i++;
60
+ const rest = byte & 127;
61
+ res += BigInt(rest) * (1n << accum);
62
+ accum += 7n;
63
+ shouldContinue = byte >= 128;
64
+ }
65
+ return res;
66
+ }
67
+ function decodeImpl(data, index) {
68
+ const cur = readULeb128(data, index);
69
+ switch (cur) {
70
+ case BigInt(SPECIAL_NULL):
71
+ return null;
72
+ case BigInt(SPECIAL_TRUE):
73
+ return true;
74
+ case BigInt(SPECIAL_FALSE):
75
+ return false;
76
+ case BigInt(SPECIAL_ADDR): {
77
+ const res = data.slice(index.i, index.i + 20);
78
+ index.i += 20;
79
+ return new (0, _chunkYI62SDKVcjs.Address)(res);
80
+ }
81
+ }
82
+ const type = Number(cur & 0xffn) & (1 << BITS_IN_TYPE) - 1;
83
+ const rest = cur >> BigInt(BITS_IN_TYPE);
84
+ switch (type) {
85
+ case TYPE_BYTES: {
86
+ const ret = data.slice(index.i, index.i + Number(rest));
87
+ index.i += Number(rest);
88
+ return ret;
89
+ }
90
+ case TYPE_PINT:
91
+ return rest;
92
+ case TYPE_NINT:
93
+ return -1n - rest;
94
+ case TYPE_STR: {
95
+ const ret = data.slice(index.i, index.i + Number(rest));
96
+ index.i += Number(rest);
97
+ return new TextDecoder("utf-8").decode(ret);
98
+ }
99
+ case TYPE_ARR: {
100
+ const ret = [];
101
+ let elems = rest;
102
+ while (elems > 0) {
103
+ elems--;
104
+ ret.push(decodeImpl(data, index));
105
+ }
106
+ return ret;
107
+ }
108
+ case TYPE_MAP: {
109
+ const ret = /* @__PURE__ */ new Map();
110
+ let elems = rest;
111
+ while (elems > 0) {
112
+ elems--;
113
+ const strLen = Number(readULeb128(data, index));
114
+ const key = data.slice(index.i, index.i + strLen);
115
+ index.i += strLen;
116
+ const keyStr = new TextDecoder("utf-8").decode(key);
117
+ ret.set(keyStr, decodeImpl(data, index));
118
+ }
119
+ return ret;
120
+ }
121
+ default:
122
+ throw new Error(`can't decode type from ${type} rest is ${rest} at pos ${index.i}`);
123
+ }
124
+ }
125
+ function decode(data) {
126
+ const index = { i: 0 };
127
+ const res = decodeImpl(data, index);
128
+ if (index.i !== data.length) {
129
+ throw new Error("some data left");
130
+ }
131
+ return res;
132
+ }
133
+
134
+ // src/abi/calldata/encoder.ts
135
+
136
+
52
137
  function reportError(msg, data) {
53
138
  throw new Error(`invalid calldata input '${data}'`);
54
139
  }
@@ -162,10 +247,7 @@ function encodeImpl(to, data) {
162
247
  to.push(c);
163
248
  }
164
249
  } else if (Object.getPrototypeOf(data) === Object.prototype) {
165
- encodeMap(
166
- to,
167
- Object.keys(data).map((k) => [k, data[k]])
168
- );
250
+ encodeMap(to, Object.entries(data));
169
251
  } else {
170
252
  reportError("unknown object type", data);
171
253
  }
@@ -219,7 +301,12 @@ var overrideContractActions = (client) => {
219
301
  method: "eth_call",
220
302
  params: [requestParams, "latest"]
221
303
  });
222
- return result;
304
+ if (typeof result === "string") {
305
+ const val = Uint8Array.from(atob(result), (c) => c.charCodeAt(0));
306
+ return decode(val);
307
+ } else {
308
+ return "<unknown>";
309
+ }
223
310
  };
224
311
  client.writeContract = async (args) => {
225
312
  const { account, address, functionName, args: params, value = 0n, leaderOnly = false } = args;
package/dist/index.js CHANGED
@@ -35,8 +35,7 @@ function accountActions(client) {
35
35
  };
36
36
  }
37
37
 
38
- // src/abi/calldata/encoder.ts
39
- import { toHex, toRlp } from "viem";
38
+ // src/abi/calldata/consts.ts
40
39
  var BITS_IN_TYPE = 3;
41
40
  var TYPE_SPECIAL = 0;
42
41
  var TYPE_PINT = 1;
@@ -49,6 +48,92 @@ var SPECIAL_NULL = 0 << BITS_IN_TYPE | TYPE_SPECIAL;
49
48
  var SPECIAL_FALSE = 1 << BITS_IN_TYPE | TYPE_SPECIAL;
50
49
  var SPECIAL_TRUE = 2 << BITS_IN_TYPE | TYPE_SPECIAL;
51
50
  var SPECIAL_ADDR = 3 << BITS_IN_TYPE | TYPE_SPECIAL;
51
+
52
+ // src/abi/calldata/decoder.ts
53
+ function readULeb128(data, index) {
54
+ let res = 0n;
55
+ let accum = 0n;
56
+ let shouldContinue = true;
57
+ while (shouldContinue) {
58
+ const byte = data[index.i];
59
+ index.i++;
60
+ const rest = byte & 127;
61
+ res += BigInt(rest) * (1n << accum);
62
+ accum += 7n;
63
+ shouldContinue = byte >= 128;
64
+ }
65
+ return res;
66
+ }
67
+ function decodeImpl(data, index) {
68
+ const cur = readULeb128(data, index);
69
+ switch (cur) {
70
+ case BigInt(SPECIAL_NULL):
71
+ return null;
72
+ case BigInt(SPECIAL_TRUE):
73
+ return true;
74
+ case BigInt(SPECIAL_FALSE):
75
+ return false;
76
+ case BigInt(SPECIAL_ADDR): {
77
+ const res = data.slice(index.i, index.i + 20);
78
+ index.i += 20;
79
+ return new Address(res);
80
+ }
81
+ }
82
+ const type = Number(cur & 0xffn) & (1 << BITS_IN_TYPE) - 1;
83
+ const rest = cur >> BigInt(BITS_IN_TYPE);
84
+ switch (type) {
85
+ case TYPE_BYTES: {
86
+ const ret = data.slice(index.i, index.i + Number(rest));
87
+ index.i += Number(rest);
88
+ return ret;
89
+ }
90
+ case TYPE_PINT:
91
+ return rest;
92
+ case TYPE_NINT:
93
+ return -1n - rest;
94
+ case TYPE_STR: {
95
+ const ret = data.slice(index.i, index.i + Number(rest));
96
+ index.i += Number(rest);
97
+ return new TextDecoder("utf-8").decode(ret);
98
+ }
99
+ case TYPE_ARR: {
100
+ const ret = [];
101
+ let elems = rest;
102
+ while (elems > 0) {
103
+ elems--;
104
+ ret.push(decodeImpl(data, index));
105
+ }
106
+ return ret;
107
+ }
108
+ case TYPE_MAP: {
109
+ const ret = /* @__PURE__ */ new Map();
110
+ let elems = rest;
111
+ while (elems > 0) {
112
+ elems--;
113
+ const strLen = Number(readULeb128(data, index));
114
+ const key = data.slice(index.i, index.i + strLen);
115
+ index.i += strLen;
116
+ const keyStr = new TextDecoder("utf-8").decode(key);
117
+ ret.set(keyStr, decodeImpl(data, index));
118
+ }
119
+ return ret;
120
+ }
121
+ default:
122
+ throw new Error(`can't decode type from ${type} rest is ${rest} at pos ${index.i}`);
123
+ }
124
+ }
125
+ function decode(data) {
126
+ const index = { i: 0 };
127
+ const res = decodeImpl(data, index);
128
+ if (index.i !== data.length) {
129
+ throw new Error("some data left");
130
+ }
131
+ return res;
132
+ }
133
+
134
+ // src/abi/calldata/encoder.ts
135
+ import { toHex } from "viem";
136
+ import { toRlp } from "viem";
52
137
  function reportError(msg, data) {
53
138
  throw new Error(`invalid calldata input '${data}'`);
54
139
  }
@@ -162,10 +247,7 @@ function encodeImpl(to, data) {
162
247
  to.push(c);
163
248
  }
164
249
  } else if (Object.getPrototypeOf(data) === Object.prototype) {
165
- encodeMap(
166
- to,
167
- Object.keys(data).map((k) => [k, data[k]])
168
- );
250
+ encodeMap(to, Object.entries(data));
169
251
  } else {
170
252
  reportError("unknown object type", data);
171
253
  }
@@ -219,7 +301,12 @@ var overrideContractActions = (client) => {
219
301
  method: "eth_call",
220
302
  params: [requestParams, "latest"]
221
303
  });
222
- return result;
304
+ if (typeof result === "string") {
305
+ const val = Uint8Array.from(atob(result), (c) => c.charCodeAt(0));
306
+ return decode(val);
307
+ } else {
308
+ return "<unknown>";
309
+ }
223
310
  };
224
311
  client.writeContract = async (args) => {
225
312
  const { account, address, functionName, args: params, value = 0n, leaderOnly = false } = args;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "genlayer-js",
3
3
  "type": "module",
4
- "version": "0.4.7",
4
+ "version": "0.4.8",
5
5
  "description": "GenLayer JavaScript SDK",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -0,0 +1,14 @@
1
+ export const BITS_IN_TYPE = 3;
2
+
3
+ export const TYPE_SPECIAL = 0;
4
+ export const TYPE_PINT = 1;
5
+ export const TYPE_NINT = 2;
6
+ export const TYPE_BYTES = 3;
7
+ export const TYPE_STR = 4;
8
+ export const TYPE_ARR = 5;
9
+ export const TYPE_MAP = 6;
10
+
11
+ export const SPECIAL_NULL = (0 << BITS_IN_TYPE) | TYPE_SPECIAL;
12
+ export const SPECIAL_FALSE = (1 << BITS_IN_TYPE) | TYPE_SPECIAL;
13
+ export const SPECIAL_TRUE = (2 << BITS_IN_TYPE) | TYPE_SPECIAL;
14
+ export const SPECIAL_ADDR = (3 << BITS_IN_TYPE) | TYPE_SPECIAL;
@@ -0,0 +1,86 @@
1
+ import type {CalldataEncodable} from "../../types/calldata";
2
+ import {Address} from "../../types/calldata";
3
+ import * as consts from "./consts";
4
+
5
+ function readULeb128(data: Uint8Array, index: {i: number}): bigint {
6
+ let res: bigint = 0n;
7
+ let accum = 0n;
8
+ let shouldContinue = true;
9
+ while (shouldContinue) {
10
+ const byte = data[index.i];
11
+ index.i++;
12
+ const rest = byte & 0x7f;
13
+ res += BigInt(rest) * (1n << accum);
14
+ accum += 7n;
15
+ shouldContinue = byte >= 128;
16
+ }
17
+ return res;
18
+ }
19
+
20
+ function decodeImpl(data: Uint8Array, index: {i: number}): CalldataEncodable {
21
+ const cur = readULeb128(data, index);
22
+ switch (cur) {
23
+ case BigInt(consts.SPECIAL_NULL):
24
+ return null;
25
+ case BigInt(consts.SPECIAL_TRUE):
26
+ return true;
27
+ case BigInt(consts.SPECIAL_FALSE):
28
+ return false;
29
+ case BigInt(consts.SPECIAL_ADDR): {
30
+ const res = data.slice(index.i, index.i + 20);
31
+ index.i += 20;
32
+ return new Address(res);
33
+ }
34
+ }
35
+ const type = Number(cur & 0xffn) & ((1 << consts.BITS_IN_TYPE) - 1);
36
+ const rest = cur >> BigInt(consts.BITS_IN_TYPE);
37
+ switch (type) {
38
+ case consts.TYPE_BYTES: {
39
+ const ret = data.slice(index.i, index.i + Number(rest));
40
+ index.i += Number(rest);
41
+ return ret;
42
+ }
43
+ case consts.TYPE_PINT:
44
+ return rest;
45
+ case consts.TYPE_NINT:
46
+ return -1n - rest;
47
+ case consts.TYPE_STR: {
48
+ const ret = data.slice(index.i, index.i + Number(rest));
49
+ index.i += Number(rest);
50
+ return new TextDecoder("utf-8").decode(ret);
51
+ }
52
+ case consts.TYPE_ARR: {
53
+ const ret = [] as CalldataEncodable[];
54
+ let elems = rest;
55
+ while (elems > 0) {
56
+ elems--;
57
+ ret.push(decodeImpl(data, index));
58
+ }
59
+ return ret;
60
+ }
61
+ case consts.TYPE_MAP: {
62
+ const ret = new Map<string, CalldataEncodable>();
63
+ let elems = rest;
64
+ while (elems > 0) {
65
+ elems--;
66
+ const strLen = Number(readULeb128(data, index));
67
+ const key = data.slice(index.i, index.i + strLen);
68
+ index.i += strLen;
69
+ const keyStr = new TextDecoder("utf-8").decode(key);
70
+ ret.set(keyStr, decodeImpl(data, index));
71
+ }
72
+ return ret;
73
+ }
74
+ default:
75
+ throw new Error(`can't decode type from ${type} rest is ${rest} at pos ${index.i}`);
76
+ }
77
+ }
78
+
79
+ export function decode(data: Uint8Array): CalldataEncodable {
80
+ const index = {i: 0};
81
+ const res = decodeImpl(data, index);
82
+ if (index.i !== data.length) {
83
+ throw new Error("some data left");
84
+ }
85
+ return res;
86
+ }
@@ -1,21 +1,8 @@
1
- import {toHex, toRlp} from "viem";
1
+ import {toHex} from "viem";
2
+ import {toRlp} from "viem";
2
3
  import type {CalldataEncodable, TransactionDataElement} from "../../types/calldata";
3
4
  import {Address} from "../../types/calldata";
4
-
5
- const BITS_IN_TYPE = 3;
6
-
7
- const TYPE_SPECIAL = 0;
8
- const TYPE_PINT = 1;
9
- const TYPE_NINT = 2;
10
- const TYPE_BYTES = 3;
11
- const TYPE_STR = 4;
12
- const TYPE_ARR = 5;
13
- const TYPE_MAP = 6;
14
-
15
- const SPECIAL_NULL = (0 << BITS_IN_TYPE) | TYPE_SPECIAL;
16
- const SPECIAL_FALSE = (1 << BITS_IN_TYPE) | TYPE_SPECIAL;
17
- const SPECIAL_TRUE = (2 << BITS_IN_TYPE) | TYPE_SPECIAL;
18
- const SPECIAL_ADDR = (3 << BITS_IN_TYPE) | TYPE_SPECIAL;
5
+ import * as consts from "./consts";
19
6
 
20
7
  function reportError(msg: string, data: CalldataEncodable): never {
21
8
  throw new Error(`invalid calldata input '${data}'`);
@@ -37,15 +24,15 @@ function writeNum(to: number[], data: bigint) {
37
24
  }
38
25
 
39
26
  function encodeNumWithType(to: number[], data: bigint, type: number) {
40
- const res = (data << BigInt(BITS_IN_TYPE)) | BigInt(type);
27
+ const res = (data << BigInt(consts.BITS_IN_TYPE)) | BigInt(type);
41
28
  writeNum(to, res);
42
29
  }
43
30
 
44
31
  function encodeNum(to: number[], data: bigint) {
45
32
  if (data >= 0n) {
46
- encodeNumWithType(to, data, TYPE_PINT);
33
+ encodeNumWithType(to, data, consts.TYPE_PINT);
47
34
  } else {
48
- encodeNumWithType(to, -data - 1n, TYPE_NINT);
35
+ encodeNumWithType(to, -data - 1n, consts.TYPE_NINT);
49
36
  }
50
37
  }
51
38
 
@@ -76,7 +63,7 @@ function encodeMap(to: number[], arr: Iterable<[string, CalldataEncodable]>) {
76
63
  }
77
64
  }
78
65
 
79
- encodeNumWithType(to, BigInt(newEntries.length), TYPE_MAP);
66
+ encodeNumWithType(to, BigInt(newEntries.length), consts.TYPE_MAP);
80
67
  for (const [, k, v] of newEntries) {
81
68
  writeNum(to, BigInt(k.length));
82
69
  for (const c of k) {
@@ -88,15 +75,15 @@ function encodeMap(to: number[], arr: Iterable<[string, CalldataEncodable]>) {
88
75
 
89
76
  function encodeImpl(to: number[], data: CalldataEncodable) {
90
77
  if (data === null || data === undefined) {
91
- to.push(SPECIAL_NULL);
78
+ to.push(consts.SPECIAL_NULL);
92
79
  return;
93
80
  }
94
81
  if (data === true) {
95
- to.push(SPECIAL_TRUE);
82
+ to.push(consts.SPECIAL_TRUE);
96
83
  return;
97
84
  }
98
85
  if (data === false) {
99
- to.push(SPECIAL_FALSE);
86
+ to.push(consts.SPECIAL_FALSE);
100
87
  return;
101
88
  }
102
89
  switch (typeof data) {
@@ -113,7 +100,7 @@ function encodeImpl(to: number[], data: CalldataEncodable) {
113
100
  }
114
101
  case "string": {
115
102
  const str = new TextEncoder().encode(data);
116
- encodeNumWithType(to, BigInt(str.length), TYPE_STR);
103
+ encodeNumWithType(to, BigInt(str.length), consts.TYPE_STR);
117
104
  for (const c of str) {
118
105
  to.push(c);
119
106
  }
@@ -121,27 +108,24 @@ function encodeImpl(to: number[], data: CalldataEncodable) {
121
108
  }
122
109
  case "object": {
123
110
  if (data instanceof Uint8Array) {
124
- encodeNumWithType(to, BigInt(data.length), TYPE_BYTES);
111
+ encodeNumWithType(to, BigInt(data.length), consts.TYPE_BYTES);
125
112
  for (const c of data) {
126
113
  to.push(c);
127
114
  }
128
115
  } else if (data instanceof Array) {
129
- encodeNumWithType(to, BigInt(data.length), TYPE_ARR);
116
+ encodeNumWithType(to, BigInt(data.length), consts.TYPE_ARR);
130
117
  for (const c of data) {
131
118
  encodeImpl(to, c);
132
119
  }
133
120
  } else if (data instanceof Map) {
134
121
  encodeMap(to, data);
135
122
  } else if (data instanceof Address) {
136
- to.push(SPECIAL_ADDR);
123
+ to.push(consts.SPECIAL_ADDR);
137
124
  for (const c of data.bytes) {
138
125
  to.push(c);
139
126
  }
140
127
  } else if (Object.getPrototypeOf(data) === Object.prototype) {
141
- encodeMap(
142
- to,
143
- Object.keys(data).map((k): [string, CalldataEncodable] => [k, data[k]]),
144
- );
128
+ encodeMap(to, Object.entries(data));
145
129
  } else {
146
130
  reportError("unknown object type", data);
147
131
  }
@@ -159,6 +143,83 @@ export function encode(data: CalldataEncodable): Uint8Array {
159
143
  return new Uint8Array(arr);
160
144
  }
161
145
 
146
+ function toStringImplMap(data: Iterable<[string, CalldataEncodable]>, to: string[]) {
147
+ to.push("{");
148
+ for (const [k, v] of data) {
149
+ to.push(JSON.stringify(k));
150
+ to.push(":");
151
+ toStringImpl(v, to);
152
+ }
153
+ to.push("}");
154
+ }
155
+
156
+ function toStringImpl(data: CalldataEncodable, to: string[]) {
157
+ if (data === null || data === undefined) {
158
+ to.push("null");
159
+ return;
160
+ }
161
+ if (data === true) {
162
+ to.push("true");
163
+ return;
164
+ }
165
+ if (data === false) {
166
+ to.push("false");
167
+ return;
168
+ }
169
+ switch (typeof data) {
170
+ case "number": {
171
+ if (!Number.isInteger(data)) {
172
+ reportError("floats are not supported", data);
173
+ }
174
+ to.push(data.toString());
175
+ return;
176
+ }
177
+ case "bigint": {
178
+ to.push(data.toString());
179
+ return;
180
+ }
181
+ case "string": {
182
+ to.push(JSON.stringify(data));
183
+ return;
184
+ }
185
+ case "object": {
186
+ if (data instanceof Uint8Array) {
187
+ to.push("b#");
188
+ for (const b of data) {
189
+ to.push(b.toString(16));
190
+ }
191
+ } else if (data instanceof Array) {
192
+ to.push("[");
193
+ for (const c of data) {
194
+ toStringImpl(c, to);
195
+ to.push(",");
196
+ }
197
+ to.push("]");
198
+ } else if (data instanceof Map) {
199
+ toStringImplMap(data.entries(), to);
200
+ } else if (data instanceof Address) {
201
+ to.push("addr#");
202
+ for (const c of data.bytes) {
203
+ to.push(c.toString(16));
204
+ }
205
+ } else if (Object.getPrototypeOf(data) === Object.prototype) {
206
+ toStringImplMap(Object.entries(data), to);
207
+ } else {
208
+ reportError("unknown object type", data);
209
+ }
210
+ return;
211
+ }
212
+ default:
213
+ reportError("unknown base type", data);
214
+ }
215
+ }
216
+
217
+ export function toString(data: CalldataEncodable): string {
218
+ const to: string[] = [];
219
+ toStringImpl(data, to);
220
+ return to.join("");
221
+ }
222
+
162
223
  export function serialize(data: TransactionDataElement[]): `0x${string}` {
163
224
  return toRlp(data.map(param => toHex(param)));
164
225
  }
@@ -1,3 +1,4 @@
1
+ import {decode} from "@/abi/calldata/decoder";
1
2
  import {encode, serialize, encodeAndSerialize} from "@/abi/calldata/encoder";
2
3
  import {Account, ContractSchema, SimulatorChain, GenLayerClient, CalldataEncodable, Address} from "@/types";
3
4
 
@@ -39,7 +40,13 @@ export const overrideContractActions = (client: GenLayerClient<SimulatorChain>)
39
40
  method: "eth_call",
40
41
  params: [requestParams, "latest"],
41
42
  });
42
- return result;
43
+
44
+ if (typeof result === "string") {
45
+ const val = Uint8Array.from(atob(result), c => c.charCodeAt(0));
46
+ return decode(val);
47
+ } else {
48
+ return "<unknown>";
49
+ }
43
50
  };
44
51
 
45
52
  client.writeContract = async (args: {