antelopeql 1.0.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/LICENSE +21 -0
- package/antelopeql.mjs +159 -0
- package/blockchain/deserialize_action_data.mjs +41 -0
- package/blockchain/get_abi.mjs +172 -0
- package/blockchain/get_account.mjs +233 -0
- package/blockchain/get_accounts_by_authorizers.mjs +79 -0
- package/blockchain/get_block.mjs +238 -0
- package/blockchain/get_currency_balance.mjs +48 -0
- package/blockchain/get_currency_stats.mjs +60 -0
- package/blockchain/get_info.mjs +96 -0
- package/blockchain/get_producers.mjs +104 -0
- package/blockchain/get_ram_price.mjs +57 -0
- package/blockchain/get_table_by_scope.mjs +96 -0
- package/blockchain_query_field.mjs +44 -0
- package/build_graphql_fields_from_abis.mjs +122 -0
- package/eosio_abi_to_graphql_ast.mjs +222 -0
- package/eosio_types/asset_type.mjs +35 -0
- package/eosio_types/block_timestamp_type.mjs +14 -0
- package/eosio_types/boolean_type.mjs +10 -0
- package/eosio_types/bytes_type.mjs +17 -0
- package/eosio_types/eosio_key_type.mjs +13 -0
- package/eosio_types/extended_asset_type.mjs +19 -0
- package/eosio_types/generate_checksum_type.mjs +20 -0
- package/eosio_types/generate_float_type.mjs +16 -0
- package/eosio_types/generate_int_type.mjs +28 -0
- package/eosio_types/generate_uint_type.mjs +27 -0
- package/eosio_types/name_type.mjs +29 -0
- package/eosio_types/public_key_type.mjs +26 -0
- package/eosio_types/signature_type.mjs +19 -0
- package/eosio_types/symbol_code_type.mjs +13 -0
- package/eosio_types/symbol_type.mjs +33 -0
- package/eosio_types/time_point_sec_type.mjs +12 -0
- package/eosio_types/time_point_type.mjs +12 -0
- package/eosio_types/varint32_type.mjs +13 -0
- package/eosio_types/varuint32_type.mjs +12 -0
- package/eosio_types.mjs +59 -0
- package/graphql_input_types/actions.mjs +15 -0
- package/graphql_input_types/authorization.mjs +30 -0
- package/graphql_input_types/configuration.mjs +55 -0
- package/graphql_input_types/query_argument_fields.mjs +82 -0
- package/graphql_object_types/authorization.mjs +15 -0
- package/graphql_object_types/authorizing_account_type.mjs +15 -0
- package/graphql_object_types/packed_transaction.mjs +32 -0
- package/graphql_object_types/transaction_receipt.mjs +159 -0
- package/mutation_resolver.mjs +234 -0
- package/package.json +97 -0
- package/push_serialized_transaction.mjs +24 -0
- package/push_transaction.mjs +75 -0
- package/push_transaction_rpc.mjs +37 -0
- package/query_resolver.mjs +43 -0
- package/readme.md +164 -0
- package/serialize_transaction.mjs +23 -0
- package/types.mjs +64 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import serialize from "eosio-wasm-js/serialize.mjs";
|
|
2
|
+
import serialize_transaction_header from "eosio-wasm-js/transaction_header.mjs";
|
|
3
|
+
import { GraphQLError } from "graphql";
|
|
4
|
+
|
|
5
|
+
const defeaul_config = {
|
|
6
|
+
blocksBehind: 3,
|
|
7
|
+
expireSeconds: 30,
|
|
8
|
+
max_net_usage_words: 0,
|
|
9
|
+
max_cpu_usage_ms: 0,
|
|
10
|
+
delay_sec: 0
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const validate_actions = () => {
|
|
14
|
+
throw new GraphQLError(`Invalid AntelopeQL query.`, {
|
|
15
|
+
extensions: {
|
|
16
|
+
why: "AntelopeQL enforces one action per object in the list to preserve the top to bottom execution order.",
|
|
17
|
+
example: "actions: [{ action1: … }, { action2: … }]"
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Serializes GraphQL mutation actions into binary instructions.
|
|
24
|
+
* @param {Array<Object>} actions List of actions to serialize.
|
|
25
|
+
* @param {Array<Object>} ast_list Abstract syntax tree list of data to serialize.
|
|
26
|
+
* @returns {String} Serialized transaction body as hexadecimal string.
|
|
27
|
+
*/
|
|
28
|
+
async function get_transaction_body(actions, ast_list) {
|
|
29
|
+
let actions_list_to_serialize = [];
|
|
30
|
+
|
|
31
|
+
for (const action of actions) {
|
|
32
|
+
if (Object.values(action).length > 1) validate_actions(action);
|
|
33
|
+
|
|
34
|
+
const [contract] = Object.keys(action);
|
|
35
|
+
const [values] = Object.values(action);
|
|
36
|
+
const action_fields = Object.keys(values);
|
|
37
|
+
if (action_fields.length > 1) validate_actions(action);
|
|
38
|
+
|
|
39
|
+
actions_list_to_serialize.push(
|
|
40
|
+
...action_fields.map((action) => ({
|
|
41
|
+
contract,
|
|
42
|
+
action,
|
|
43
|
+
data: values[action]
|
|
44
|
+
}))
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let _actions = [];
|
|
49
|
+
let _context_free_actions = [];
|
|
50
|
+
|
|
51
|
+
let transaction_extensions =
|
|
52
|
+
"000000000000000000000000000000000000000000000000000000000000000000";
|
|
53
|
+
|
|
54
|
+
for (const action of actions_list_to_serialize) {
|
|
55
|
+
const {
|
|
56
|
+
contract,
|
|
57
|
+
action: action_name,
|
|
58
|
+
data: { authorization, ...data }
|
|
59
|
+
} = action;
|
|
60
|
+
|
|
61
|
+
const build_serialize_list = async (data, instructions) => {
|
|
62
|
+
let serialize_list = [];
|
|
63
|
+
for (const instruction of instructions) {
|
|
64
|
+
const { $info, name, type } = instruction;
|
|
65
|
+
const datum = data[name];
|
|
66
|
+
const next_instruction = ast_list[contract][type]; // Indicates that the AST type is not serialisable, but is another type on the AST list.
|
|
67
|
+
|
|
68
|
+
// Handles ABI variant types see https://en.cppreference.com/w/cpp/utility/variant
|
|
69
|
+
if ($info.variant) {
|
|
70
|
+
if (Object.keys(data).length > 1)
|
|
71
|
+
throw new Error(`Must only include one type for variant.`);
|
|
72
|
+
if (!datum) continue;
|
|
73
|
+
else
|
|
74
|
+
serialize_list.push({
|
|
75
|
+
type: "varuint32",
|
|
76
|
+
value: instructions.findIndex((i) => i.type == type)
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if ($info.binary_ex) $info.optional = false; // Binary extentions are optional (GraphQL types) but should not serialize an optional type.
|
|
81
|
+
|
|
82
|
+
if ($info.optional)
|
|
83
|
+
serialize_list.push({ type: "bool", value: datum != undefined }); // Add an optional item to serialize list.
|
|
84
|
+
|
|
85
|
+
if ($info.list)
|
|
86
|
+
if (datum !== undefined)
|
|
87
|
+
serialize_list.push({ type: "varuint32", value: datum.length }); // Add an length of list to serialize list.
|
|
88
|
+
|
|
89
|
+
// Indicates that we need to recursion loop through each data item.
|
|
90
|
+
if (next_instruction)
|
|
91
|
+
if ($info.list) {
|
|
92
|
+
if (datum != undefined && !$info.binary_ex)
|
|
93
|
+
for await (const d of datum)
|
|
94
|
+
serialize_list.push(
|
|
95
|
+
...(await build_serialize_list(await d, next_instruction))
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
// None list recursion
|
|
99
|
+
else
|
|
100
|
+
serialize_list.push(
|
|
101
|
+
...(await build_serialize_list(datum, next_instruction))
|
|
102
|
+
);
|
|
103
|
+
// Indicates that the list of data can be serilaized and so is pushed into serialize_list.
|
|
104
|
+
else if ($info.list && datum !== undefined)
|
|
105
|
+
for await (const d of datum) serialize_list.push({ type, value: d });
|
|
106
|
+
else if (datum !== undefined)
|
|
107
|
+
serialize_list.push({ type, value: datum }); // Native eoio types than can be serialized.
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return serialize_list;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const hex_string = await build_serialize_list(
|
|
114
|
+
data,
|
|
115
|
+
ast_list[contract][action_name]
|
|
116
|
+
).then(async (list) => {
|
|
117
|
+
let hex_string = "";
|
|
118
|
+
for await (const { type, value } of list)
|
|
119
|
+
hex_string += await serialize[type](await value);
|
|
120
|
+
return hex_string;
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
if (authorization?.length)
|
|
124
|
+
_actions.push({
|
|
125
|
+
account: contract.replace(/_/gmu, "."),
|
|
126
|
+
action: action_name.replace(/_/gmu, "."),
|
|
127
|
+
authorization,
|
|
128
|
+
data,
|
|
129
|
+
hex_data: hex_string
|
|
130
|
+
});
|
|
131
|
+
else
|
|
132
|
+
_context_free_actions.push({
|
|
133
|
+
account: contract.replace(/_/gmu, "."),
|
|
134
|
+
action: action_name.replace(/_/gmu, "."),
|
|
135
|
+
authorization: [],
|
|
136
|
+
data,
|
|
137
|
+
hex_data: hex_string
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
context_free_actions: _context_free_actions.map(
|
|
143
|
+
({ action: name, ...action }) => ({ ...action, name })
|
|
144
|
+
),
|
|
145
|
+
actions: _actions.map(({ action: name, ...action }) => ({
|
|
146
|
+
...action,
|
|
147
|
+
name
|
|
148
|
+
})),
|
|
149
|
+
transaction_extensions: [],
|
|
150
|
+
transaction_body:
|
|
151
|
+
serialize.actions(_context_free_actions) +
|
|
152
|
+
serialize.actions(_actions) +
|
|
153
|
+
transaction_extensions
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Mutation resolver for serializing EOSIO transactions.
|
|
159
|
+
* @param {Object} args Args.
|
|
160
|
+
* @param {Object} args.actions Actions list to be serialized.
|
|
161
|
+
* @param {Object} [args.configuration] Action configuaration.
|
|
162
|
+
* @param {AntelopeQLRPC} network AntelopeQL context contain fetch and url string.
|
|
163
|
+
* @param {Object} ast_list Abstract syntax tree list of the contract actions.
|
|
164
|
+
* @returns {Object} Transaction object.
|
|
165
|
+
*/
|
|
166
|
+
async function mutation_resolver(
|
|
167
|
+
{ actions, configuration = defeaul_config },
|
|
168
|
+
network,
|
|
169
|
+
ast_list
|
|
170
|
+
) {
|
|
171
|
+
if (configuration.max_cpu_usage_ms > 0xff)
|
|
172
|
+
throw new Error("Invalid max_cpu_usage_ms value (maximum 255).");
|
|
173
|
+
if (configuration.max_net_usage_words > 0xffffffff)
|
|
174
|
+
throw new Error(
|
|
175
|
+
"Invalid max_net_usage_words value (maximum 4,294,967,295)."
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
const { fetch, rpc_url, ...fetchOptions } = network;
|
|
179
|
+
const { transaction_body, ...transaction_list } = await get_transaction_body(
|
|
180
|
+
actions,
|
|
181
|
+
ast_list
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
const { chain_id, head_block_num } = await fetch(
|
|
185
|
+
`${rpc_url}/v1/chain/get_info`,
|
|
186
|
+
{
|
|
187
|
+
method: "POST",
|
|
188
|
+
...fetchOptions
|
|
189
|
+
}
|
|
190
|
+
).then((req) => req.json());
|
|
191
|
+
|
|
192
|
+
const block_num_or_id = head_block_num - configuration.blocksBehind;
|
|
193
|
+
|
|
194
|
+
const { timestamp, block_num, ref_block_prefix } = await fetch(
|
|
195
|
+
`${rpc_url}/v1/chain/get_block`,
|
|
196
|
+
{
|
|
197
|
+
method: "POST",
|
|
198
|
+
...fetchOptions,
|
|
199
|
+
body: JSON.stringify({
|
|
200
|
+
block_num_or_id
|
|
201
|
+
})
|
|
202
|
+
}
|
|
203
|
+
).then((req) => req.json());
|
|
204
|
+
|
|
205
|
+
// // TaPoS expiry time.
|
|
206
|
+
const expiration =
|
|
207
|
+
Math.round(Date.parse(timestamp + "Z") / 1000) +
|
|
208
|
+
configuration.expireSeconds;
|
|
209
|
+
|
|
210
|
+
const txn_header = {
|
|
211
|
+
expiration,
|
|
212
|
+
ref_block_num: block_num & 0xffff,
|
|
213
|
+
ref_block_prefix,
|
|
214
|
+
max_net_usage_words: configuration.max_net_usage_words,
|
|
215
|
+
max_cpu_usage_ms: configuration.max_cpu_usage_ms,
|
|
216
|
+
delay_sec: configuration.delay_sec
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// Generates a transaction header for a EOS transaction.
|
|
220
|
+
const transaction_header = serialize_transaction_header(txn_header);
|
|
221
|
+
txn_header.expiration = timestamp;
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
chain_id,
|
|
225
|
+
transaction_header,
|
|
226
|
+
transaction_body,
|
|
227
|
+
transaction: {
|
|
228
|
+
...txn_header,
|
|
229
|
+
...transaction_list
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export default mutation_resolver;
|
package/package.json
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "antelopeql",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A GraphQL implementation for interacting with Antelope based blockchains.",
|
|
5
|
+
"repository": "github:pur3miish/antelopeql",
|
|
6
|
+
"bugs": "https://github.com/pur3miish/antelopeql/issues",
|
|
7
|
+
"homepage": "https://github.com/pur3miish/antelopeql#readme",
|
|
8
|
+
"author": "pur3miish",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"eslint": "eslint .",
|
|
12
|
+
"prettier": "prettier -c .",
|
|
13
|
+
"prettier:readme": "prettier --write readme.md",
|
|
14
|
+
"types": "tsc -p jsconfig.json",
|
|
15
|
+
"snapshot": "SAVE_SNAPSHOTS=1 coverage-node test/index.test.mjs",
|
|
16
|
+
"coverage": "coverage-node test/index.test.mjs",
|
|
17
|
+
"tests": "node test/index.test.mjs",
|
|
18
|
+
"test": "npm run eslint && npm run prettier && npm run types && npm run tests",
|
|
19
|
+
"prepublishOnly": "npm test"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": "^16.0.0 || >= 17.0.0 || >= 18.0.0"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"blockchain/*.mjs",
|
|
26
|
+
"eosio_types/*.mjs",
|
|
27
|
+
"graphql_input_types/*.mjs",
|
|
28
|
+
"graphql_object_types/*.mjs",
|
|
29
|
+
"blockchain_query_field.mjs",
|
|
30
|
+
"build_graphql_fields_from_abis.mjs",
|
|
31
|
+
"eosio_abi_to_graphql_ast.mjs",
|
|
32
|
+
"eosio_types.mjs",
|
|
33
|
+
"mutation_resolver.mjs",
|
|
34
|
+
"push_serialized_transaction.mjs",
|
|
35
|
+
"push_transaction_rpc.mjs",
|
|
36
|
+
"push_transaction.mjs",
|
|
37
|
+
"query_resolver.mjs",
|
|
38
|
+
"serialize_transaction.mjs",
|
|
39
|
+
"antelopeql.mjs",
|
|
40
|
+
"types.mjs"
|
|
41
|
+
],
|
|
42
|
+
"sideEffects": false,
|
|
43
|
+
"exports": {
|
|
44
|
+
"./blockchain/*.mjs": "./blockchain/*.mjs",
|
|
45
|
+
"./eosio_types/*.mjs": "./eosio_types/*.mjs",
|
|
46
|
+
"./graphql_input_types/*.mjs": "./graphql_input_types/*.mjs",
|
|
47
|
+
"./graphql_object_types/*.mjs": "./graphql_object_types/*.mjs",
|
|
48
|
+
"./blockchain_query_field.mjs": "./blockchain_query_field.mjs",
|
|
49
|
+
"./build_graphql_fields_from_abis.mjs": "./build_graphql_fields_from_abis.mjs",
|
|
50
|
+
"./eosio_abi_to_graphql_ast.mjs": "./eosio_abi_to_graphql_ast.mjs",
|
|
51
|
+
"./eosio_types.mjs": "./eosio_types.mjs",
|
|
52
|
+
"./mutation_resolver.mjs": "./mutation_resolver.mjs",
|
|
53
|
+
"./push_serialized_transaction.mjs": "./push_serialized_transaction.mjs",
|
|
54
|
+
"./push_transaction_rpc.mjs": "./push_transaction_rpc.mjs",
|
|
55
|
+
"./push_transaction.mjs": "./push_transaction.mjs",
|
|
56
|
+
"./query_resolver.mjs": "./query_resolver.mjs",
|
|
57
|
+
"./serialize_transaction.mjs": "./serialize_transaction.mjs",
|
|
58
|
+
"./antelopeql.mjs": "./antelopeql.mjs",
|
|
59
|
+
"./types.mjs": "./types.mjs"
|
|
60
|
+
},
|
|
61
|
+
"browserslist": [
|
|
62
|
+
"> 0.5%, not OperaMini all, not IE > 0, not dead"
|
|
63
|
+
],
|
|
64
|
+
"keywords": [
|
|
65
|
+
"blockchain",
|
|
66
|
+
"graphql",
|
|
67
|
+
"smart",
|
|
68
|
+
"contract",
|
|
69
|
+
"bitcoin",
|
|
70
|
+
"eosio",
|
|
71
|
+
"eos",
|
|
72
|
+
"query",
|
|
73
|
+
"language"
|
|
74
|
+
],
|
|
75
|
+
"devDependencies": {
|
|
76
|
+
"@types/node": "^18.13.0",
|
|
77
|
+
"coverage-node": "^8.0.0",
|
|
78
|
+
"eslint": "^8.34.0",
|
|
79
|
+
"eslint-plugin-simple-import-sort": "^10.0.0",
|
|
80
|
+
"graphql": "^16.6.0",
|
|
81
|
+
"node-fetch": "^3.3.0",
|
|
82
|
+
"nodemon": "^2.0.20",
|
|
83
|
+
"prettier": "^2.8.4",
|
|
84
|
+
"snapshot-assertion": "^5.0.0",
|
|
85
|
+
"test-director": "^10.0.0",
|
|
86
|
+
"typescript": "^4.9.5"
|
|
87
|
+
},
|
|
88
|
+
"peerDependencies": {
|
|
89
|
+
"graphql": "^16.6.0"
|
|
90
|
+
},
|
|
91
|
+
"dependencies": {
|
|
92
|
+
"base58-js": "^2.0.0",
|
|
93
|
+
"eosio-ecc": "^1.0.1",
|
|
94
|
+
"eosio-wasm-js": "^4.0.1",
|
|
95
|
+
"ripemd160-js": "*"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { GraphQLList, GraphQLNonNull } from "graphql";
|
|
2
|
+
|
|
3
|
+
import bytes_type from "./eosio_types/bytes_type.mjs";
|
|
4
|
+
import signature_type from "./eosio_types/signature_type.mjs";
|
|
5
|
+
import transaction_receipt from "./graphql_object_types/transaction_receipt.mjs";
|
|
6
|
+
import push_transaction_rpc from "./push_transaction_rpc.mjs";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Push transaction type.
|
|
10
|
+
*/
|
|
11
|
+
const push_serialized_transaction = {
|
|
12
|
+
description: "Pushes a serialized transaction to the blockchain.",
|
|
13
|
+
type: new GraphQLNonNull(transaction_receipt),
|
|
14
|
+
args: {
|
|
15
|
+
transaction_header: { type: new GraphQLNonNull(bytes_type) },
|
|
16
|
+
transaction_body: { type: new GraphQLNonNull(bytes_type) },
|
|
17
|
+
signaures: { type: new GraphQLNonNull(new GraphQLList(signature_type)) }
|
|
18
|
+
},
|
|
19
|
+
resolve(_, args, ctx) {
|
|
20
|
+
return push_transaction_rpc(args, ctx.network);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default push_serialized_transaction;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import private_key_to_legacy from "eosio-ecc/private_key_to_legacy.mjs";
|
|
2
|
+
import get_public_key from "eosio-ecc/public_key_from_private.mjs";
|
|
3
|
+
import sign_packed_txn from "eosio-ecc/sign_packed_txn.mjs";
|
|
4
|
+
import { GraphQLError, GraphQLNonNull } from "graphql";
|
|
5
|
+
|
|
6
|
+
import configuration_type from "./graphql_input_types/configuration.mjs";
|
|
7
|
+
import transaction_receipt from "./graphql_object_types/transaction_receipt.mjs";
|
|
8
|
+
import mutation_resolver from "./mutation_resolver.mjs";
|
|
9
|
+
import push_transaction_rpc from "./push_transaction_rpc.mjs";
|
|
10
|
+
|
|
11
|
+
const push_transaction = (actions, ast_list) => ({
|
|
12
|
+
description:
|
|
13
|
+
"Serialize a list of actions and push them to the blockchain in one step, requires private keys to be supplied to AntelopeQL.",
|
|
14
|
+
type: new GraphQLNonNull(transaction_receipt),
|
|
15
|
+
args: {
|
|
16
|
+
actions: {
|
|
17
|
+
type: actions
|
|
18
|
+
},
|
|
19
|
+
configuration: {
|
|
20
|
+
type: configuration_type
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
async resolve(_, args, { network, private_keys }) {
|
|
24
|
+
const { chain_id, transaction_header, transaction_body, transaction } =
|
|
25
|
+
await mutation_resolver(args, network, ast_list);
|
|
26
|
+
|
|
27
|
+
const key_pairs = {};
|
|
28
|
+
for await (const key of private_keys) {
|
|
29
|
+
const PVT = await private_key_to_legacy(key);
|
|
30
|
+
const PUB = await get_public_key(PVT);
|
|
31
|
+
key_pairs[PUB] = PVT;
|
|
32
|
+
}
|
|
33
|
+
const available_keys = Object.keys(key_pairs);
|
|
34
|
+
|
|
35
|
+
const { fetch, rpc_url, ...fetchOptions } = network;
|
|
36
|
+
|
|
37
|
+
if (!available_keys.length)
|
|
38
|
+
throw new GraphQLError("No private keys found.");
|
|
39
|
+
|
|
40
|
+
const { required_keys, ...errors } = await fetch(
|
|
41
|
+
`${rpc_url}/v1/chain/get_required_keys`,
|
|
42
|
+
{
|
|
43
|
+
method: "POST",
|
|
44
|
+
...fetchOptions,
|
|
45
|
+
body: JSON.stringify({
|
|
46
|
+
available_keys,
|
|
47
|
+
transaction
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
).then((res) => res.json());
|
|
51
|
+
|
|
52
|
+
if (errors.message)
|
|
53
|
+
throw new GraphQLError("No transaction sent", {
|
|
54
|
+
extensions: errors
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const signatures = await Promise.all(
|
|
58
|
+
required_keys.map((pub) =>
|
|
59
|
+
sign_packed_txn({
|
|
60
|
+
chain_id,
|
|
61
|
+
transaction_body,
|
|
62
|
+
transaction_header,
|
|
63
|
+
wif_private_key: key_pairs[pub]
|
|
64
|
+
})
|
|
65
|
+
)
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
return push_transaction_rpc(
|
|
69
|
+
{ transaction_body, transaction_header, signatures },
|
|
70
|
+
network
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
export default push_transaction;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { GraphQLError } from "graphql";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pushes a serialized transaction to the blockchain.
|
|
5
|
+
* @param {Object} root Argument
|
|
6
|
+
* @param {String} root.transaction_header Serialized transaction header.
|
|
7
|
+
* @param {String} root.transaction_body Serialized transaction body.
|
|
8
|
+
* @param {Array<String>} root.signatures List of signatures to validate transaction.
|
|
9
|
+
* @param {Object} network Argument
|
|
10
|
+
* @param {fetch} network.fetch Custom fetch.
|
|
11
|
+
* @param {String} network.rpc_url Chain rpc url.
|
|
12
|
+
* @param {Object} network.headers transaction headers.
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
export default async function push_transaction_rpc(
|
|
16
|
+
{ transaction_header, transaction_body, signatures },
|
|
17
|
+
network
|
|
18
|
+
) {
|
|
19
|
+
const { fetch, rpc_url, ...fetchOptions } = network;
|
|
20
|
+
const pushed_txn_req = await fetch(`${rpc_url}/v1/chain/push_transaction`, {
|
|
21
|
+
method: "POST",
|
|
22
|
+
...fetchOptions,
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
signatures,
|
|
25
|
+
compression: 0,
|
|
26
|
+
packed_context_free_data: "",
|
|
27
|
+
packed_trx: transaction_header + transaction_body
|
|
28
|
+
})
|
|
29
|
+
});
|
|
30
|
+
const pushed_transaction = await pushed_txn_req.json();
|
|
31
|
+
if (pushed_transaction.error)
|
|
32
|
+
throw new GraphQLError(pushed_transaction.message, {
|
|
33
|
+
extensions: pushed_transaction.error
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return pushed_transaction;
|
|
37
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { GraphQLError } from "graphql";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AntelopeQL Query resolver.
|
|
5
|
+
* @param {Object} root GraphQL resolver root query.
|
|
6
|
+
* @param {String} root.code Contract code calling, passed from antelopeql_fields resolver.
|
|
7
|
+
* @param {Object} args Query arguments.
|
|
8
|
+
* @param {Object} args.arg argument data.
|
|
9
|
+
* @param {Object} ctx GraphQL context.
|
|
10
|
+
* @param {AntelopeQLRPC} ctx.network Object containing connection url and fetch.
|
|
11
|
+
* @param {Object} info GraphQL resovler info argument.
|
|
12
|
+
* @returns {Object} Returned data from table.
|
|
13
|
+
*/
|
|
14
|
+
export default async function query_resolver(
|
|
15
|
+
{ code },
|
|
16
|
+
{ arg },
|
|
17
|
+
{ network },
|
|
18
|
+
info
|
|
19
|
+
) {
|
|
20
|
+
const { fetch, rpc_url, ...fetchOptions } = network;
|
|
21
|
+
const { fieldName: query_name } = info;
|
|
22
|
+
const table = query_name.replace(/_/gmu, ".");
|
|
23
|
+
|
|
24
|
+
if (
|
|
25
|
+
arg.key_type == "i256" ||
|
|
26
|
+
arg.key_type == "ripemd160" ||
|
|
27
|
+
arg.key_type == "sha256"
|
|
28
|
+
) {
|
|
29
|
+
arg.encode_type = "hex";
|
|
30
|
+
arg.lower_bound = arg.lower_bound ?? "00";
|
|
31
|
+
}
|
|
32
|
+
const uri = rpc_url + "/v1/chain/get_table_rows";
|
|
33
|
+
|
|
34
|
+
const data = await fetch(uri, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
...fetchOptions,
|
|
37
|
+
body: JSON.stringify({ json: true, code, table, ...arg })
|
|
38
|
+
}).then((req) => req.json());
|
|
39
|
+
|
|
40
|
+
if (data.error) throw new GraphQLError(data.message, { extensions: data });
|
|
41
|
+
|
|
42
|
+
return data.rows;
|
|
43
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# AntelopeQL
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.org/package/antelopeql) [](https://github.com/pur3miish/antelopeql/blob/main/LICENSE)
|
|
6
|
+
|
|
7
|
+
AntelopeQL is a [GraphQL](https://graphql.org/) implementation for interacting with [Antelope](https://antelope.io/) blockchains. Query and mutate your smart contracts with a GraphQL tool that provides comprehensive documentation about the entire blockchain.
|
|
8
|
+
|
|
9
|
+
**For a live example of AntelopeQL GUI see: [antelope.relocke.io](https://antelope.relocke.io).**
|
|
10
|
+
|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
For [Node.js](https://nodejs.org), to install [`AntelopeQL`](https://npm.im/antelopeql) and the peer dependency [`graphql`](https://npm.im/graphql) run:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm install antelopeql graphql
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
For [Deno.js](https://deno.land), to install [`AntelopeQL`](https://deno.land/x/antelopeql) add to your `deno.json` configuration file these imports:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"imports": {
|
|
26
|
+
"universal-sha256-js/": "https://deno.land/x/sha256js/",
|
|
27
|
+
"universal-hmac-sha256-js/": "https://deno.land/x/hmacsha256/",
|
|
28
|
+
"universal-hmac-sha256-js/hmac-sha256-node.mjs": "https://deno.land/x/hmacsha256/hmac-sha256-deno.mjs",
|
|
29
|
+
"base58-js/": "https://deno.land/x/base58/",
|
|
30
|
+
"isomorphic-secp256k1-js/": "https://deno.land/x/secp256k1js/",
|
|
31
|
+
"ripemd160-js/": "https://deno.land/x/ripemd160js@v2.0.3/",
|
|
32
|
+
"eosio-wasm-js/": "https://deno.land/x/eosio_wasm_js/",
|
|
33
|
+
"eosio-ecc/": "https://deno.land/x/eosio_ecc/",
|
|
34
|
+
"graphql": "https://cdn.skypack.dev/graphql"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Examples
|
|
40
|
+
|
|
41
|
+
See the examples folder on how to run AntelopeQL as a [Node.js](https://nodejs.org) endpoint.
|
|
42
|
+
|
|
43
|
+
### Query a blockchain account
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
import fetch from "node-fetch";
|
|
47
|
+
import AntelopeQL from "antelopeql/antelopeql.mjs";
|
|
48
|
+
|
|
49
|
+
const { data } = await AntelopeQL(
|
|
50
|
+
{
|
|
51
|
+
query: /*GraphQL*/ `{
|
|
52
|
+
blockchain{
|
|
53
|
+
get_account(account_name:"relockeblock") {
|
|
54
|
+
core_liquid_balance
|
|
55
|
+
ram_quota
|
|
56
|
+
net_weight
|
|
57
|
+
cpu_weight
|
|
58
|
+
ram_usage
|
|
59
|
+
permissions {
|
|
60
|
+
linked_actions {
|
|
61
|
+
account
|
|
62
|
+
action
|
|
63
|
+
}
|
|
64
|
+
required_auth {
|
|
65
|
+
keys {
|
|
66
|
+
key
|
|
67
|
+
weight
|
|
68
|
+
}
|
|
69
|
+
threshold
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}`
|
|
75
|
+
fetch,
|
|
76
|
+
rpc_url: "https://jungle.relocke.io",
|
|
77
|
+
headers: {
|
|
78
|
+
"content-type": "application/json"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
console.log(data);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
> Logged output included an account infomation.
|
|
87
|
+
|
|
88
|
+
### Transfer EOS cryptocurrency
|
|
89
|
+
|
|
90
|
+
```js
|
|
91
|
+
import fetch from "node-fetch";
|
|
92
|
+
import AntelopeQL from "antelopeql/antelopeql.mjs";
|
|
93
|
+
|
|
94
|
+
const { data } = await AntelopeQL({
|
|
95
|
+
query: /*GraphQL*/ `mutation{
|
|
96
|
+
push_transaction(actions: [{
|
|
97
|
+
eosio_token:{
|
|
98
|
+
transfer: {
|
|
99
|
+
authorization:{
|
|
100
|
+
actor:"relockeblock"
|
|
101
|
+
}
|
|
102
|
+
to:"relockechain"
|
|
103
|
+
from:"relockeblock"
|
|
104
|
+
memo: ""
|
|
105
|
+
quantity: "0.0002 EOS"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}]) {
|
|
109
|
+
transaction_id
|
|
110
|
+
block_num
|
|
111
|
+
}
|
|
112
|
+
}`,
|
|
113
|
+
contracts: ["eosio.token"],
|
|
114
|
+
private_keys: ["PVT_K1_…"], // legacy keys support.
|
|
115
|
+
fetch,
|
|
116
|
+
rpc_url: "https://eos.relocke.io", // eos blockchain.
|
|
117
|
+
headers: {
|
|
118
|
+
"content-type": "application/json"
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
console.log(data);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
> Logged output includes transaction_id and block_num
|
|
126
|
+
|
|
127
|
+
### Ways to require in CJS
|
|
128
|
+
|
|
129
|
+
> **Note**
|
|
130
|
+
>
|
|
131
|
+
> As this package is [ESM](https://nodejs.org/docs/latest-v16.x/api/esm.html) if you need to require it in a [Common JS](https://nodejs.org/docs/latest-v16.x/api/modules.html) package, then you can import like this:
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
(async function () {
|
|
135
|
+
const { default: AntelopeQL } = await import("antelopeql/antelopeql.mjs");
|
|
136
|
+
const { data } = await AntelopeQL({…})
|
|
137
|
+
})();
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Requirements
|
|
141
|
+
|
|
142
|
+
Supported runtime environments:
|
|
143
|
+
|
|
144
|
+
- [Node.js](https://nodejs.org) versions `>=16.0.0`.
|
|
145
|
+
- Browsers matching the [Browserslist](https://browsersl.ist) query [`> 0.5%, not OperaMini all, not dead`](https://browsersl.ist/?q=%3E+0.5%25%2C+not+OperaMini+all%2C+not+dead).
|
|
146
|
+
- [Deno](https://deno.land) version `>=1.30.0`.
|
|
147
|
+
|
|
148
|
+
## Exports
|
|
149
|
+
|
|
150
|
+
The [npm](https://npmjs.com) package [`AntelopeQL`](https://npm.im/antelopeql) features [optimal JavaScript module design](https://jaydenseric.com/blog/optimal-javascript-module-design). It doesn’t have a main index module, so use deep imports from the ECMAScript modules that are exported via the [`package.json`](./package.json) field [`exports`](https://nodejs.org/api/packages.html#exports):
|
|
151
|
+
|
|
152
|
+
- [`antelopeql.mjs`](./antelopeql.mjs)
|
|
153
|
+
- [`blockchain_query_field.mjs`](blockchain_query_field.mjs)
|
|
154
|
+
- [`build_graphql_fields_from_abis.mjs`](build_graphql_fields_from_abis.mjs)
|
|
155
|
+
- [`eosio_abi_to_graphql_ast.mjs`](eosio_abi_to_graphql_ast.mjs)
|
|
156
|
+
- [`eosio_types.mjs`](eosio_types.mjs)
|
|
157
|
+
- [`mutation_resolver.mjs`](mutation_resolver.mjs)
|
|
158
|
+
- [`push_serialized_transaction.mjs`](push_serialized_transaction.mjs)
|
|
159
|
+
- [`push_transaction_rpc.mjs`](push_transaction_rpc.mjs)
|
|
160
|
+
- [`push_transaction.mjs`](push_transaction.mjs)
|
|
161
|
+
- [`query_resolver.mjs`](query_resolver.mjs)
|
|
162
|
+
- [`serialize_transaction.mjs`](serialize_transaction.mjs)
|
|
163
|
+
- [`antelopeql.mjs`](antelopeql.mjs)
|
|
164
|
+
- [`types.mjs`](types.mjs)
|