antelopeql 2.0.0-rc.0 → 2.0.0-rc.2

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.
@@ -0,0 +1,244 @@
1
+ import { GraphQLObjectType, GraphQLScalarType, GraphQLString } from "graphql";
2
+
3
+ const string_or_int = new GraphQLScalarType({
4
+ name: "string_or_int",
5
+ description: "`String` or `Integer` type."
6
+ });
7
+
8
+ /**
9
+ * Calculates the fraction of bw needed for power up action for the EOSIO blockchain.
10
+ * @param {number | string} us Microseconds needed to supply to account.
11
+ * @param {number | string} us Kibibytes needed to supply to account.
12
+ * @param {Object} power_up_state Power up state.
13
+ * @param {Object} account_info Account to get an approximate cost of BW.
14
+ * @returns {number} Fraction of CPU and Netwotk bandwidth to supply to powerup action.
15
+ */
16
+ function calculate_fraction(us, bytes, power_up_state, account_info) {
17
+ function get_sample_usage({ cpu_limit, cpu_weight, net_limit, net_weight }) {
18
+ const c = BigInt(1000000);
19
+
20
+ const cpu = parseInt(
21
+ (BigInt(cpu_limit.max) * c) / BigInt(cpu_weight) + BigInt(1)
22
+ );
23
+
24
+ const net = parseInt(
25
+ (BigInt(net_limit.max) * c) / BigInt(net_weight) + BigInt(1)
26
+ );
27
+
28
+ return { cpu, net };
29
+ }
30
+
31
+ function frac_by_us(cpu) {
32
+ const { weight } = power_up_state.cpu;
33
+ const n = Math.floor((us / cpu) * 1e6) / parseInt(weight);
34
+ return Math.floor(n * 1e15);
35
+ }
36
+
37
+ function frac_by_bytes(net) {
38
+ const { weight } = power_up_state.net;
39
+ return Math.floor((Math.floor((bytes / net) * 1e6) / weight) * 1e15);
40
+ }
41
+
42
+ const { cpu, net } = get_sample_usage(account_info);
43
+
44
+ return {
45
+ net_frac: frac_by_bytes(net),
46
+ cpu_frac: frac_by_us(cpu)
47
+ };
48
+ }
49
+
50
+ /**
51
+ * Return an approximate EOS amount for the fraction of bandwidth.
52
+ * @param {number} frac The bandwidth fraction required.
53
+ * @param {Object} bw Powerup state bandwidth.
54
+ * @returns {{Asset}} The EOS value for CPU and Network bandwidth fraction
55
+ */
56
+ function calculate_price(frac, bw) {
57
+ let { utilization, weight, exponent, max_price, min_price } = bw;
58
+ min_price = parseFloat(min_price.replace(" EOS").split(".")[0]);
59
+ max_price = parseFloat(max_price.replace(" EOS").split(".")[0]);
60
+ exponent = parseFloat(exponent);
61
+ utilization = parseInt(utilization);
62
+ weight = parseInt(weight);
63
+
64
+ const determine_adjusted_utilization = () => {
65
+ const { decay_secs, utilization, utilization_timestamp } = bw;
66
+ let { adjusted_utilization } = bw;
67
+
68
+ if (parseInt(utilization) < parseInt(adjusted_utilization)) {
69
+ const now = Math.floor(new Date().getTime() / 1e3);
70
+ const diff = parseInt(adjusted_utilization) - parseInt(utilization);
71
+ let delta =
72
+ diff *
73
+ Math.exp(
74
+ -(now - parseInt(utilization_timestamp)) / parseInt(decay_secs)
75
+ );
76
+
77
+ delta = Math.min(Math.max(delta, 0), diff);
78
+ adjusted_utilization = parseInt(utilization) + delta;
79
+ }
80
+ return adjusted_utilization;
81
+ };
82
+
83
+ const utilization_increase = Math.ceil((frac * weight) / 1e15);
84
+ const adjusted_utilization = determine_adjusted_utilization(bw);
85
+
86
+ const price_function = (utilization) => {
87
+ let price = min_price;
88
+ const new_exponent = exponent - 1.0;
89
+ if (new_exponent <= 0.0) return max_price;
90
+ else
91
+ price +=
92
+ (max_price - min_price) * Math.pow(utilization / weight, new_exponent);
93
+
94
+ return price;
95
+ };
96
+
97
+ const price_integral_delta = (start_utilization, end_utilization) => {
98
+ const coefficient = (max_price - min_price) / exponent;
99
+ const start_u = start_utilization / weight;
100
+ const end_u = end_utilization / weight;
101
+ const delta =
102
+ min_price * end_u -
103
+ min_price * start_u +
104
+ coefficient * Math.pow(end_u, exponent) -
105
+ coefficient * Math.pow(start_u, exponent);
106
+ return delta;
107
+ };
108
+
109
+ let start_utilization = utilization;
110
+ const end_utilization = start_utilization + utilization_increase;
111
+ let fee = 0;
112
+
113
+ if (start_utilization < adjusted_utilization) {
114
+ fee +=
115
+ (price_function(adjusted_utilization) *
116
+ Math.min(
117
+ utilization_increase,
118
+ adjusted_utilization - start_utilization
119
+ )) /
120
+ weight;
121
+ start_utilization = adjusted_utilization;
122
+ }
123
+ if (start_utilization < end_utilization)
124
+ fee += price_integral_delta(start_utilization, end_utilization);
125
+
126
+ return fee;
127
+ // return Math.ceil(fee * 1e4) / 1e4
128
+ }
129
+
130
+ const eos_bandwidth_price = {
131
+ description: "`EOS` bandwidth powerup quote.",
132
+ type: new GraphQLObjectType({
133
+ name: "eos_bandwidth_price",
134
+ fields: {
135
+ cpu_frac: {
136
+ type: GraphQLString
137
+ },
138
+ net_frac: {
139
+ type: GraphQLString
140
+ },
141
+ cpu_estimate: {
142
+ type: GraphQLString
143
+ },
144
+ net_estimate: {
145
+ type: GraphQLString
146
+ }
147
+ }
148
+ }),
149
+ args: {
150
+ us: {
151
+ type: string_or_int,
152
+ description:
153
+ "Number of micro seconds of CPU bandwidth you want a quote for.",
154
+ defaultValue: 0
155
+ },
156
+ bytes: {
157
+ type: string_or_int,
158
+ description: "Number of bytes of network bandwidth you want a quote for.",
159
+ defaultValue: 0
160
+ }
161
+ },
162
+ async resolve(_, { us, bytes }, { network: { fetch, rpc_url } }) {
163
+ rpc_url = "https://jungle.relocke.io";
164
+
165
+ const get_sample_account = async () => {
166
+ const account_names = await fetch(rpc_url + "/v1/chain/get_table_rows", {
167
+ method: "post",
168
+ body: JSON.stringify({
169
+ code: "eosio",
170
+ table: "powup.order",
171
+ scope: "",
172
+ json: true
173
+ })
174
+ });
175
+
176
+ const { rows } = await account_names.json();
177
+
178
+ const request = await fetch(rpc_url + "/v1/chain/get_account", {
179
+ method: "post",
180
+ body: JSON.stringify({ account_name: rows[2].owner })
181
+ });
182
+
183
+ return request.json();
184
+ };
185
+
186
+ const get_powerup_state = fetch(rpc_url + "/v1/chain/get_table_rows", {
187
+ method: "post",
188
+ headers: {
189
+ "Content-Type": "application/json"
190
+ },
191
+ body: JSON.stringify({
192
+ code: "eosio",
193
+ table: "powup.state",
194
+ scope: "",
195
+ json: true
196
+ })
197
+ });
198
+
199
+ const [sample_account, get_powerup_state_req] = await Promise.all([
200
+ await get_sample_account(),
201
+ get_powerup_state
202
+ ]);
203
+
204
+ const power_up_state = await get_powerup_state_req.json();
205
+
206
+ let { cpu_frac, net_frac } = calculate_fraction(
207
+ us,
208
+ bytes,
209
+ power_up_state.rows[0],
210
+ sample_account
211
+ );
212
+
213
+ let cpu_estimate = Number(
214
+ calculate_price(cpu_frac, power_up_state.rows[0].cpu)
215
+ );
216
+ let net_estimate = Number(
217
+ calculate_price(net_frac, power_up_state.rows[0].net)
218
+ );
219
+
220
+ // handle the net and cpu estimates so that they are > minimum system token.
221
+ const MIN_TOKEN = Number(
222
+ power_up_state.rows[0].min_powerup_fee.replace(/[A-Z\s]+/gmu, "")
223
+ );
224
+ console.log(MIN_TOKEN);
225
+ // if (cpu_estimate < MIN_TOKEN) {
226
+ // cpu_frac *= Math.floor(MIN_TOKEN / cpu_estimate);
227
+ // cpu_estimate = Number(MIN_TOKEN) + cpu_estimate;
228
+ // }
229
+
230
+ // if (net_estimate < MIN_TOKEN) {
231
+ // net_frac *= Math.floor(MIN_TOKEN / net_estimate);
232
+ // net_estimate = MIN_TOKEN + net_estimate;
233
+ // }
234
+
235
+ return {
236
+ cpu_frac,
237
+ net_frac,
238
+ cpu_estimate,
239
+ net_estimate
240
+ };
241
+ }
242
+ };
243
+
244
+ export default eos_bandwidth_price;
@@ -0,0 +1,53 @@
1
+ import {
2
+ GraphQLError,
3
+ GraphQLNonNull,
4
+ GraphQLObjectType,
5
+ GraphQLString
6
+ } from "graphql";
7
+
8
+ import name_type from "../eosio_types/name_type.mjs";
9
+
10
+ const smart_contract_type = new GraphQLObjectType({
11
+ name: "smart_contract_type",
12
+ fields: () => ({
13
+ wasm: {
14
+ type: GraphQLString,
15
+ description: "base64 encoded contract WASM"
16
+ },
17
+ abi: {
18
+ description: "base64 encoded contract ABI",
19
+ type: GraphQLString
20
+ }
21
+ })
22
+ });
23
+
24
+ const get_smart_contract = {
25
+ description: "Retrieve a smart contract from the blockchain.",
26
+ type: smart_contract_type,
27
+ args: {
28
+ account_name: {
29
+ description: "The account holding the `smart contract`.",
30
+ type: new GraphQLNonNull(name_type)
31
+ }
32
+ },
33
+ async resolve(
34
+ _,
35
+ { account_name },
36
+ { network: { fetch, rpc_url, ...fetchOptions } }
37
+ ) {
38
+ const uri = `${rpc_url}/v1/chain/get_raw_code_and_abi`;
39
+ const data = await fetch(uri, {
40
+ method: "POST",
41
+ ...fetchOptions,
42
+ body: JSON.stringify({
43
+ account_name,
44
+ code_as_wasm: 1
45
+ })
46
+ }).then((req) => req.json());
47
+
48
+ if (data.error) throw new GraphQLError(data.message, { extensions: data });
49
+ return data;
50
+ }
51
+ };
52
+
53
+ export default get_smart_contract;
@@ -0,0 +1,284 @@
1
+ import serialize from "eosio-wasm-js/serialize.mjs";
2
+
3
+ import { eosio_abi_to_graphql_ast } from "../eosio_abi_to_graphql_ast.mjs";
4
+ import Bytes from "../eosio_types/bytes_type.mjs";
5
+
6
+ const ABI = {
7
+ version: "eosio::abi/1.1",
8
+ structs: [
9
+ {
10
+ name: "extensions_entry",
11
+ base: "",
12
+ fields: [
13
+ {
14
+ name: "tag",
15
+ type: "uint16"
16
+ },
17
+ {
18
+ name: "value",
19
+ type: "bytes"
20
+ }
21
+ ]
22
+ },
23
+ {
24
+ name: "type_def",
25
+ base: "",
26
+ fields: [
27
+ {
28
+ name: "new_type_name",
29
+ type: "string"
30
+ },
31
+ {
32
+ name: "type",
33
+ type: "string"
34
+ }
35
+ ]
36
+ },
37
+ {
38
+ name: "field_def",
39
+ base: "",
40
+ fields: [
41
+ {
42
+ name: "name",
43
+ type: "string"
44
+ },
45
+ {
46
+ name: "type",
47
+ type: "string"
48
+ }
49
+ ]
50
+ },
51
+ {
52
+ name: "struct_def",
53
+ base: "",
54
+ fields: [
55
+ {
56
+ name: "name",
57
+ type: "string"
58
+ },
59
+ {
60
+ name: "base",
61
+ type: "string"
62
+ },
63
+ {
64
+ name: "fields",
65
+ type: "field_def[]"
66
+ }
67
+ ]
68
+ },
69
+ {
70
+ name: "action_def",
71
+ base: "",
72
+ fields: [
73
+ {
74
+ name: "name",
75
+ type: "name"
76
+ },
77
+ {
78
+ name: "type",
79
+ type: "string"
80
+ },
81
+ {
82
+ name: "ricardian_contract",
83
+ type: "string"
84
+ }
85
+ ]
86
+ },
87
+ {
88
+ name: "table_def",
89
+ base: "",
90
+ fields: [
91
+ {
92
+ name: "name",
93
+ type: "name"
94
+ },
95
+ {
96
+ name: "index_type",
97
+ type: "string"
98
+ },
99
+ {
100
+ name: "key_names",
101
+ type: "string[]"
102
+ },
103
+ {
104
+ name: "key_types",
105
+ type: "string[]"
106
+ },
107
+ {
108
+ name: "type",
109
+ type: "string"
110
+ }
111
+ ]
112
+ },
113
+ {
114
+ name: "clause_pair",
115
+ base: "",
116
+ fields: [
117
+ {
118
+ name: "id",
119
+ type: "string"
120
+ },
121
+ {
122
+ name: "body",
123
+ type: "string"
124
+ }
125
+ ]
126
+ },
127
+ {
128
+ name: "error_message",
129
+ base: "",
130
+ fields: [
131
+ {
132
+ name: "error_code",
133
+ type: "uint64"
134
+ },
135
+ {
136
+ name: "error_msg",
137
+ type: "string"
138
+ }
139
+ ]
140
+ },
141
+ {
142
+ name: "variant_def",
143
+ base: "",
144
+ fields: [
145
+ {
146
+ name: "name",
147
+ type: "string"
148
+ },
149
+ {
150
+ name: "types",
151
+ type: "string[]"
152
+ }
153
+ ]
154
+ },
155
+ {
156
+ name: "abi_def",
157
+ base: "",
158
+ fields: [
159
+ {
160
+ name: "version",
161
+ type: "string"
162
+ },
163
+ {
164
+ name: "types",
165
+ type: "type_def[]"
166
+ },
167
+ {
168
+ name: "structs",
169
+ type: "struct_def[]"
170
+ },
171
+ {
172
+ name: "actions",
173
+ type: "action_def[]"
174
+ },
175
+ {
176
+ name: "tables",
177
+ type: "table_def[]"
178
+ },
179
+ {
180
+ name: "ricardian_clauses",
181
+ type: "clause_pair[]"
182
+ },
183
+ {
184
+ name: "error_messages",
185
+ type: "error_message[]"
186
+ },
187
+ {
188
+ name: "abi_extensions",
189
+ type: "extensions_entry[]"
190
+ },
191
+ {
192
+ name: "variants",
193
+ type: "variant_def[]$"
194
+ }
195
+ ]
196
+ }
197
+ ]
198
+ };
199
+ const AST = eosio_abi_to_graphql_ast(ABI);
200
+
201
+ const serialize_abi = {
202
+ description:
203
+ "Serializes ABI to WASM hex code, this function is useful when you are using set ABI",
204
+ type: Bytes,
205
+ args: {
206
+ abi: {
207
+ type: Bytes,
208
+ description: "ABI to serialize as buffer",
209
+ defaultValue: 0
210
+ }
211
+ },
212
+ async resolve(_, { abi }) {
213
+ const JSON_ABI = JSON.parse(
214
+ abi
215
+ .match(/[a-z0-9]{2}/gmu)
216
+ .map((i) => String.fromCharCode(`0x${i}`))
217
+ .join("")
218
+ );
219
+
220
+ const build_serialize_list = async (data, instructions) => {
221
+ const serialize_list = [];
222
+
223
+ for (const instruction of instructions) {
224
+ const { $info, name, type } = instruction;
225
+ const datum = data[name];
226
+
227
+ const next_instruction = AST[type];
228
+
229
+ if ($info.variant) {
230
+ if (Object.keys(data).length > 1)
231
+ throw new Error(`Must only include one type for variant.`);
232
+ if (!datum) continue;
233
+ else
234
+ serialize_list.push({
235
+ type: "varuint32",
236
+ value: instructions.findIndex((i) => i.type == type)
237
+ });
238
+ }
239
+
240
+ if ($info.binary_ex) $info.optional = false; // Binary extentions are optional (GraphQL types) but should not serialize an optional type.
241
+
242
+ if ($info.optional)
243
+ serialize_list.push({ type: "bool", value: datum != undefined }); // Add an optional item to serialize list.
244
+
245
+ if ($info.list)
246
+ if (datum !== undefined)
247
+ serialize_list.push({ type: "varuint32", value: datum.length }); // Add an length of list to serialize list.
248
+
249
+ // Indicates that we need to recursion loop through each data item.
250
+ if (next_instruction)
251
+ if ($info.list) {
252
+ if (datum != undefined && !$info.binary_ex)
253
+ for await (const d of datum)
254
+ serialize_list.push(
255
+ ...(await build_serialize_list(await d, next_instruction))
256
+ );
257
+ }
258
+ // None list recursion
259
+ else
260
+ serialize_list.push(
261
+ ...(await build_serialize_list(datum, next_instruction))
262
+ );
263
+ // Indicates that the list of data can be serilaized and so is pushed into serialize_list.
264
+ else if ($info.list && datum !== undefined)
265
+ for await (const d of datum) serialize_list.push({ type, value: d });
266
+ else if (datum !== undefined)
267
+ serialize_list.push({ type, value: datum }); // Native eoio types than can be serialized.
268
+ }
269
+
270
+ return serialize_list;
271
+ };
272
+
273
+ const ser_list = await build_serialize_list(JSON_ABI, AST.abi_def);
274
+
275
+ let hex_string = "";
276
+ ser_list.forEach(
277
+ ({ type, value }) => (hex_string += serialize[type](value))
278
+ );
279
+
280
+ return hex_string;
281
+ }
282
+ };
283
+
284
+ export default serialize_abi;
@@ -1,5 +1,6 @@
1
1
  import { GraphQLError, GraphQLObjectType } from "graphql";
2
2
 
3
+ import eos_bandwidth_price from "./blockchain/bandwidth_quote.mjs";
3
4
  import deserialize_action_data from "./blockchain/deserialize_action_data.mjs";
4
5
  import get_abi from "./blockchain/get_abi.mjs";
5
6
  import get_account from "./blockchain/get_account.mjs";
@@ -10,7 +11,9 @@ import get_currency_stats from "./blockchain/get_currency_stats.mjs";
10
11
  import get_info from "./blockchain/get_info.mjs";
11
12
  import get_producers from "./blockchain/get_producers.mjs";
12
13
  import get_ram_price from "./blockchain/get_ram_price.mjs";
14
+ import get_smart_contract from "./blockchain/get_smart_contract.mjs";
13
15
  import get_table from "./blockchain/get_table_by_scope.mjs";
16
+ import serialize_abi from "./blockchain/serialize_abi.mjs";
14
17
 
15
18
  const blockchain_query_field = {
16
19
  type: new GraphQLObjectType({
@@ -21,13 +24,16 @@ const blockchain_query_field = {
21
24
  get_abi,
22
25
  get_accounts_by_authorizers,
23
26
  get_block,
27
+ get_smart_contract,
24
28
  get_currency_balance,
25
29
  get_currency_stats,
26
30
  get_info,
27
31
  get_producers,
28
32
  deserialize_action_data,
29
33
  get_table,
30
- get_ram_price
34
+ get_ram_price,
35
+ eos_bandwidth_price,
36
+ serialize_abi
31
37
  }
32
38
  }),
33
39
  resolve(_, __, { network: { fetch, rpc_url } }) {
@@ -69,15 +69,17 @@ export function eosio_abi_to_graphql_ast(abi) {
69
69
  const { types, variants } = abi;
70
70
 
71
71
  let structs = [
72
- ...variants.map(({ name, types }) => ({
73
- name,
74
- base: "",
75
- fields: types.map((item) => ({ name: item, type: item + "$@" })) // @ indiacted a variant type and binary extention.
76
- })),
72
+ ...(variants?.length
73
+ ? variants.map(({ name, types }) => ({
74
+ name,
75
+ base: "",
76
+ fields: types.map((item) => ({ name: item, type: item + "$@" })) // @ indiacted a variant type and binary extention.
77
+ }))
78
+ : []),
77
79
  ...abi.structs
78
80
  ];
79
81
 
80
- if (types.length)
82
+ if (types?.length)
81
83
  for (const { type: real_type, new_type_name } of types)
82
84
  structs = structs.map(({ fields, ...struct }) => ({
83
85
  ...struct,
@@ -16,11 +16,11 @@ const packed_transaction_type = new GraphQLObjectType({
16
16
  fields: {
17
17
  chain_id: {
18
18
  type: GraphQLString,
19
- description: "A unique ID that Specifies which chain we are operating on."
19
+ description: "A unique ID that specifies which chain we are operating on."
20
20
  },
21
21
  transaction_header: {
22
22
  type: GraphQLString,
23
- description: "Serialized transaction header _(TaPoS protection)_."
23
+ description: "Serialized transaction header."
24
24
  },
25
25
  transaction_body: {
26
26
  type: GraphQLString,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "antelopeql",
3
- "version": "2.0.0-rc.0",
3
+ "version": "2.0.0-rc.2",
4
4
  "description": "A GraphQL implementation for interacting with Antelope based blockchains.",
5
5
  "repository": "github:pur3miish/antelopeql",
6
6
  "bugs": "https://github.com/pur3miish/antelopeql/issues",
@@ -92,7 +92,7 @@
92
92
  },
93
93
  "dependencies": {
94
94
  "base58-js": "^2.0.0",
95
- "eosio-wasm-js": "^4.1.0",
95
+ "eosio-wasm-js": "^4.1.1",
96
96
  "ripemd160-js": "*",
97
97
  "universal-sha256-js": "^2.0.0"
98
98
  }
@@ -18,9 +18,7 @@ export default async function push_transaction_rpc(
18
18
  ) {
19
19
  const { fetch, rpc_url, ...fetchOptions } = network;
20
20
 
21
- console.log(transaction_body);
22
-
23
- const pushed_txn_req = await fetch(`${rpc_url}/v1/chain/push_transaction`, {
21
+ const pushed_txn_req = await fetch(`${rpc_url}/v1/chain/send_transaction`, {
24
22
  method: "POST",
25
23
  ...fetchOptions,
26
24
  body: JSON.stringify({