koilib 2.6.0 → 2.6.1
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/dist/koinos.js +2 -567
- package/dist/koinos.min.js +1 -1
- package/lib/browser/Contract.d.ts +202 -0
- package/lib/browser/Contract.js +298 -0
- package/lib/browser/Contract.js.map +1 -0
- package/lib/browser/Provider.d.ts +153 -0
- package/lib/browser/Provider.js +244 -0
- package/lib/browser/Provider.js.map +1 -0
- package/lib/browser/Serializer.d.ts +81 -0
- package/lib/browser/Serializer.js +169 -0
- package/lib/browser/Serializer.js.map +1 -0
- package/lib/browser/Signer.d.ts +296 -0
- package/lib/browser/Signer.js +421 -0
- package/lib/browser/Signer.js.map +1 -0
- package/lib/browser/index.d.ts +7 -0
- package/lib/browser/index.js +34 -0
- package/lib/browser/index.js.map +1 -0
- package/lib/browser/index2.d.ts +2 -0
- package/lib/browser/index2.js +33 -0
- package/lib/browser/index2.js.map +1 -0
- package/lib/browser/interface.d.ts +278 -0
- package/lib/browser/interface.js +3 -0
- package/lib/browser/interface.js.map +1 -0
- package/lib/browser/jsonDescriptors/krc20-proto.json +183 -0
- package/lib/browser/jsonDescriptors/protocol-proto.json +246 -0
- package/lib/browser/utils.d.ts +326 -0
- package/lib/browser/utils.js +252 -0
- package/lib/browser/utils.js.map +1 -0
- package/package.json +9 -6
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Provider = void 0;
|
|
4
|
+
async function sleep(ms) {
|
|
5
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Class to connect with the RPC node
|
|
9
|
+
*/
|
|
10
|
+
class Provider {
|
|
11
|
+
/**
|
|
12
|
+
*
|
|
13
|
+
* @param rpcNodes - URL of the rpc node, or array of urls
|
|
14
|
+
* to switch between them when someone is down
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const provider = new Provider([
|
|
18
|
+
* "http://45.56.104.152:8080",
|
|
19
|
+
* "http://159.203.119.0:8080"
|
|
20
|
+
* ]);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
constructor(rpcNodes) {
|
|
24
|
+
if (Array.isArray(rpcNodes))
|
|
25
|
+
this.rpcNodes = rpcNodes;
|
|
26
|
+
else
|
|
27
|
+
this.rpcNodes = [rpcNodes];
|
|
28
|
+
this.currentNodeId = 0;
|
|
29
|
+
this.onError = () => false;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Function to make jsonrpc requests to the RPC node
|
|
33
|
+
* @param method - jsonrpc method
|
|
34
|
+
* @param params - jsonrpc params
|
|
35
|
+
* @returns Result of jsonrpc response
|
|
36
|
+
*/
|
|
37
|
+
async call(method, params) {
|
|
38
|
+
/* eslint-disable no-await-in-loop */
|
|
39
|
+
// eslint-disable-next-line no-constant-condition
|
|
40
|
+
while (true) {
|
|
41
|
+
try {
|
|
42
|
+
const data = {
|
|
43
|
+
id: Math.round(Math.random() * 1000),
|
|
44
|
+
jsonrpc: "2.0",
|
|
45
|
+
method,
|
|
46
|
+
params,
|
|
47
|
+
};
|
|
48
|
+
const url = this.rpcNodes[this.currentNodeId];
|
|
49
|
+
const response = await fetch(url, {
|
|
50
|
+
method: "POST",
|
|
51
|
+
body: JSON.stringify(data),
|
|
52
|
+
});
|
|
53
|
+
const json = (await response.json());
|
|
54
|
+
if (json.error && json.error.message) {
|
|
55
|
+
const error = new Error(json.error.message);
|
|
56
|
+
error.request = {
|
|
57
|
+
method,
|
|
58
|
+
params,
|
|
59
|
+
};
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
return json.result;
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
const currentNode = this.rpcNodes[this.currentNodeId];
|
|
66
|
+
this.currentNodeId = (this.currentNodeId + 1) % this.rpcNodes.length;
|
|
67
|
+
const newNode = this.rpcNodes[this.currentNodeId];
|
|
68
|
+
const abort = this.onError(e, currentNode, newNode);
|
|
69
|
+
if (abort)
|
|
70
|
+
throw e;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Function to call "chain.get_account_nonce" to return the number of
|
|
76
|
+
* transactions for a particular account. This call is used
|
|
77
|
+
* when creating new transactions.
|
|
78
|
+
* @param account - account address
|
|
79
|
+
* @returns Nonce
|
|
80
|
+
*/
|
|
81
|
+
async getNonce(account) {
|
|
82
|
+
const { nonce } = await this.call("chain.get_account_nonce", { account });
|
|
83
|
+
if (!nonce)
|
|
84
|
+
return 0;
|
|
85
|
+
return Number(nonce);
|
|
86
|
+
}
|
|
87
|
+
async getAccountRc(account) {
|
|
88
|
+
const { rc } = await this.call("chain.get_account_rc", {
|
|
89
|
+
account,
|
|
90
|
+
});
|
|
91
|
+
if (!rc)
|
|
92
|
+
return "0";
|
|
93
|
+
return rc;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get transactions by id and their corresponding block ids
|
|
97
|
+
*/
|
|
98
|
+
async getTransactionsById(transactionIds) {
|
|
99
|
+
return this.call("transaction_store.get_transactions_by_id", {
|
|
100
|
+
transaction_ids: transactionIds,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
async getBlocksById(blockIds) {
|
|
104
|
+
return this.call("block_store.get_blocks_by_id", {
|
|
105
|
+
block_id: blockIds,
|
|
106
|
+
return_block: true,
|
|
107
|
+
return_receipt: false,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Function to get info from the head block in the blockchain
|
|
112
|
+
*/
|
|
113
|
+
async getHeadInfo() {
|
|
114
|
+
return this.call("chain.get_head_info", {});
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Function to get consecutive blocks in descending order
|
|
118
|
+
* @param height - Starting block height
|
|
119
|
+
* @param numBlocks - Number of blocks to fetch
|
|
120
|
+
* @param idRef - Block ID reference to speed up searching blocks.
|
|
121
|
+
* This ID must be from a greater block height. By default it
|
|
122
|
+
* gets the ID from the block head.
|
|
123
|
+
*/
|
|
124
|
+
async getBlocks(height, numBlocks = 1, idRef) {
|
|
125
|
+
let blockIdRef = idRef;
|
|
126
|
+
if (!blockIdRef) {
|
|
127
|
+
const head = await this.getHeadInfo();
|
|
128
|
+
blockIdRef = head.head_topology.id;
|
|
129
|
+
}
|
|
130
|
+
return (await this.call("block_store.get_blocks_by_height", {
|
|
131
|
+
head_block_id: blockIdRef,
|
|
132
|
+
ancestor_start_height: height,
|
|
133
|
+
num_blocks: numBlocks,
|
|
134
|
+
return_block: true,
|
|
135
|
+
return_receipt: false,
|
|
136
|
+
})).block_items;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Function to get a block by its height
|
|
140
|
+
*/
|
|
141
|
+
async getBlock(height) {
|
|
142
|
+
return (await this.getBlocks(height, 1))[0];
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Function to call "chain.submit_transaction" to send a signed
|
|
146
|
+
* transaction to the blockchain. It returns an object with the async
|
|
147
|
+
* function "wait", which can be called to wait for the
|
|
148
|
+
* transaction to be mined (see [[SendTransactionResponse]]).
|
|
149
|
+
* @param transaction - Signed transaction
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* const { transactionResponse } = await provider.sendTransaction({
|
|
153
|
+
* id: "1220...",
|
|
154
|
+
* active: "...",
|
|
155
|
+
* signatureData: "...",
|
|
156
|
+
* });
|
|
157
|
+
* console.log("Transaction submitted to the mempool");
|
|
158
|
+
* // wait to be mined
|
|
159
|
+
* const blockNumber = await transactionResponse.wait();
|
|
160
|
+
* // const blockNumber = await transactionResponse.wait("byBlock", 30000);
|
|
161
|
+
* // const blockId = await transactionResponse.wait("byTransactionId", 30000);
|
|
162
|
+
* console.log("Transaction mined")
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
async sendTransaction(transaction) {
|
|
166
|
+
await this.call("chain.submit_transaction", { transaction });
|
|
167
|
+
return {
|
|
168
|
+
wait: async (type = "byBlock", timeout = 30000) => {
|
|
169
|
+
const iniTime = Date.now();
|
|
170
|
+
if (type === "byTransactionId") {
|
|
171
|
+
while (Date.now() < iniTime + timeout) {
|
|
172
|
+
await sleep(1000);
|
|
173
|
+
const { transactions } = await this.getTransactionsById([
|
|
174
|
+
transaction.id,
|
|
175
|
+
]);
|
|
176
|
+
if (transactions &&
|
|
177
|
+
transactions[0] &&
|
|
178
|
+
transactions[0].containing_blocks)
|
|
179
|
+
return transactions[0].containing_blocks[0];
|
|
180
|
+
}
|
|
181
|
+
throw new Error(`Transaction not mined after ${timeout} ms`);
|
|
182
|
+
}
|
|
183
|
+
// byBlock
|
|
184
|
+
const findTxInBlocks = async (ini, numBlocks, idRef) => {
|
|
185
|
+
const blocks = await this.getBlocks(ini, numBlocks, idRef);
|
|
186
|
+
let bNum = 0;
|
|
187
|
+
blocks.forEach((block) => {
|
|
188
|
+
if (!block ||
|
|
189
|
+
!block.block ||
|
|
190
|
+
!block.block_id ||
|
|
191
|
+
!block.block.transactions)
|
|
192
|
+
return;
|
|
193
|
+
const tx = block.block.transactions.find((t) => t.id === transaction.id);
|
|
194
|
+
if (tx)
|
|
195
|
+
bNum = Number(block.block_height);
|
|
196
|
+
});
|
|
197
|
+
const lastId = blocks[blocks.length - 1].block_id;
|
|
198
|
+
return [bNum, lastId];
|
|
199
|
+
};
|
|
200
|
+
let blockNumber = 0;
|
|
201
|
+
let iniBlock = 0;
|
|
202
|
+
let previousId = "";
|
|
203
|
+
while (Date.now() < iniTime + timeout) {
|
|
204
|
+
await sleep(1000);
|
|
205
|
+
const { head_topology: headTopology } = await this.getHeadInfo();
|
|
206
|
+
if (blockNumber === 0) {
|
|
207
|
+
blockNumber = Number(headTopology.height);
|
|
208
|
+
iniBlock = blockNumber;
|
|
209
|
+
}
|
|
210
|
+
if (Number(headTopology.height) === blockNumber - 1 &&
|
|
211
|
+
previousId &&
|
|
212
|
+
previousId !== headTopology.id) {
|
|
213
|
+
const [bNum, lastId] = await findTxInBlocks(iniBlock, Number(headTopology.height) - iniBlock + 1, headTopology.id);
|
|
214
|
+
if (bNum)
|
|
215
|
+
return bNum;
|
|
216
|
+
previousId = lastId;
|
|
217
|
+
blockNumber = Number(headTopology.height) + 1;
|
|
218
|
+
}
|
|
219
|
+
// eslint-disable-next-line no-continue
|
|
220
|
+
if (blockNumber > Number(headTopology.height))
|
|
221
|
+
continue;
|
|
222
|
+
const [bNum, lastId] = await findTxInBlocks(blockNumber, 1, headTopology.id);
|
|
223
|
+
if (bNum)
|
|
224
|
+
return bNum;
|
|
225
|
+
if (!previousId)
|
|
226
|
+
previousId = lastId;
|
|
227
|
+
blockNumber += 1;
|
|
228
|
+
}
|
|
229
|
+
throw new Error(`Transaction not mined after ${timeout} ms. Blocks checked from ${iniBlock} to ${blockNumber}`);
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Function to call "chain.read_contract" to read a contract.
|
|
235
|
+
* This function is used by [[Contract]] class when read methods
|
|
236
|
+
* are invoked.
|
|
237
|
+
*/
|
|
238
|
+
async readContract(operation) {
|
|
239
|
+
return this.call("chain.read_contract", operation);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
exports.Provider = Provider;
|
|
243
|
+
exports.default = Provider;
|
|
244
|
+
//# sourceMappingURL=Provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Provider.js","sourceRoot":"","sources":["../../src/Provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Root, Type, INamespace } from "protobufjs/light";
|
|
2
|
+
/**
|
|
3
|
+
* The serializer class serialize and deserialize data using
|
|
4
|
+
* protocol buffers.
|
|
5
|
+
*
|
|
6
|
+
* NOTE: This class uses the [protobufjs/light](https://www.npmjs.com/package/protobufjs)
|
|
7
|
+
* library internally, which uses reflection (use of _eval_
|
|
8
|
+
* and _new Function_) for the construction of the types.
|
|
9
|
+
* This could cause issues in environments where _eval_ is not
|
|
10
|
+
* allowed, like in browser extensions. In such cases, this class
|
|
11
|
+
* must be confined in a [sandbox environment](https://developer.chrome.com/docs/apps/app_external/#sandboxing)
|
|
12
|
+
* where _eval_ is allowed. This is the principal reason of
|
|
13
|
+
* having the serializer in a separate class.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* const descriptorJson = {
|
|
19
|
+
* nested: {
|
|
20
|
+
* awesomepackage: {
|
|
21
|
+
* nested: {
|
|
22
|
+
* AwesomeMessage: {
|
|
23
|
+
* fields: {
|
|
24
|
+
* awesomeField: {
|
|
25
|
+
* type: "string",
|
|
26
|
+
* id: 1
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
* }
|
|
34
|
+
* const serializer = new Serializer(descriptorJson)
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare class Serializer {
|
|
38
|
+
/**
|
|
39
|
+
* Protobuffers descriptor in JSON format.
|
|
40
|
+
* See https://www.npmjs.com/package/protobufjs#using-json-descriptors
|
|
41
|
+
*/
|
|
42
|
+
types: INamespace;
|
|
43
|
+
/**
|
|
44
|
+
* Protobuffer definitions
|
|
45
|
+
*/
|
|
46
|
+
root: Root;
|
|
47
|
+
/**
|
|
48
|
+
* Default type for all serializations
|
|
49
|
+
*/
|
|
50
|
+
defaultType?: Type;
|
|
51
|
+
/**
|
|
52
|
+
* Preformat bytes for base64, base58 or hex string
|
|
53
|
+
*/
|
|
54
|
+
bytesConversion: boolean;
|
|
55
|
+
constructor(types: INamespace, opts?: {
|
|
56
|
+
/**
|
|
57
|
+
* Default type name. Use this option when you
|
|
58
|
+
* always want to serialize/deserialize the same type
|
|
59
|
+
*/
|
|
60
|
+
defaultTypeName?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Bytes conversion. Option to preformat bytes
|
|
63
|
+
* when "(koinos_bytes_type)" is defined in the type
|
|
64
|
+
* definitions. By default it is true.
|
|
65
|
+
*/
|
|
66
|
+
bytesConversion?: boolean;
|
|
67
|
+
});
|
|
68
|
+
/**
|
|
69
|
+
* Function to encode a type using the protobuffer definitions
|
|
70
|
+
* It also prepares the bytes for special cases (base58, hex string)
|
|
71
|
+
* when bytesConversion param is true.
|
|
72
|
+
*/
|
|
73
|
+
serialize(valueDecoded: Record<string, unknown>, typeName?: string): Promise<Uint8Array>;
|
|
74
|
+
/**
|
|
75
|
+
* Function to decode bytes using the protobuffer definitions
|
|
76
|
+
* It also encodes the bytes for special cases (base58, hex string)
|
|
77
|
+
* when bytesConversion param is true.
|
|
78
|
+
*/
|
|
79
|
+
deserialize<T = Record<string, unknown>>(valueEncoded: string | Uint8Array, typeName?: string): Promise<T>;
|
|
80
|
+
}
|
|
81
|
+
export default Serializer;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Serializer = void 0;
|
|
4
|
+
/* eslint-disable @typescript-eslint/require-await */
|
|
5
|
+
const light_1 = require("protobufjs/light");
|
|
6
|
+
const utils_1 = require("./utils");
|
|
7
|
+
const OP_BYTES = "(koinos_bytes_type)";
|
|
8
|
+
/**
|
|
9
|
+
* Makes a copy of a value. The returned value can be modified
|
|
10
|
+
* without altering the original one. Although this is not needed
|
|
11
|
+
* for strings or numbers and only needed for objects and arrays,
|
|
12
|
+
* all these options are covered in a single function
|
|
13
|
+
*
|
|
14
|
+
* It is assumed that the argument is number, string, or contructions
|
|
15
|
+
* of these types inside objects or arrays.
|
|
16
|
+
*/
|
|
17
|
+
function copyValue(value) {
|
|
18
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
return JSON.parse(JSON.stringify(value));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The serializer class serialize and deserialize data using
|
|
25
|
+
* protocol buffers.
|
|
26
|
+
*
|
|
27
|
+
* NOTE: This class uses the [protobufjs/light](https://www.npmjs.com/package/protobufjs)
|
|
28
|
+
* library internally, which uses reflection (use of _eval_
|
|
29
|
+
* and _new Function_) for the construction of the types.
|
|
30
|
+
* This could cause issues in environments where _eval_ is not
|
|
31
|
+
* allowed, like in browser extensions. In such cases, this class
|
|
32
|
+
* must be confined in a [sandbox environment](https://developer.chrome.com/docs/apps/app_external/#sandboxing)
|
|
33
|
+
* where _eval_ is allowed. This is the principal reason of
|
|
34
|
+
* having the serializer in a separate class.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
*
|
|
38
|
+
* ```ts
|
|
39
|
+
* const descriptorJson = {
|
|
40
|
+
* nested: {
|
|
41
|
+
* awesomepackage: {
|
|
42
|
+
* nested: {
|
|
43
|
+
* AwesomeMessage: {
|
|
44
|
+
* fields: {
|
|
45
|
+
* awesomeField: {
|
|
46
|
+
* type: "string",
|
|
47
|
+
* id: 1
|
|
48
|
+
* }
|
|
49
|
+
* }
|
|
50
|
+
* }
|
|
51
|
+
* }
|
|
52
|
+
* }
|
|
53
|
+
* }
|
|
54
|
+
* }
|
|
55
|
+
* const serializer = new Serializer(descriptorJson)
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
class Serializer {
|
|
59
|
+
constructor(types, opts) {
|
|
60
|
+
/**
|
|
61
|
+
* Preformat bytes for base64, base58 or hex string
|
|
62
|
+
*/
|
|
63
|
+
this.bytesConversion = true;
|
|
64
|
+
this.types = types;
|
|
65
|
+
this.root = light_1.Root.fromJSON(this.types);
|
|
66
|
+
if (opts === null || opts === void 0 ? void 0 : opts.defaultTypeName)
|
|
67
|
+
this.defaultType = this.root.lookupType(opts.defaultTypeName);
|
|
68
|
+
if (opts && typeof opts.bytesConversion !== "undefined")
|
|
69
|
+
this.bytesConversion = opts.bytesConversion;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Function to encode a type using the protobuffer definitions
|
|
73
|
+
* It also prepares the bytes for special cases (base58, hex string)
|
|
74
|
+
* when bytesConversion param is true.
|
|
75
|
+
*/
|
|
76
|
+
async serialize(valueDecoded, typeName) {
|
|
77
|
+
const protobufType = this.defaultType || this.root.lookupType(typeName);
|
|
78
|
+
let object = {};
|
|
79
|
+
if (this.bytesConversion) {
|
|
80
|
+
// TODO: format from Buffer to base58/base64 for nested fields
|
|
81
|
+
Object.keys(protobufType.fields).forEach((fieldName) => {
|
|
82
|
+
const { options, name, type } = protobufType.fields[fieldName];
|
|
83
|
+
// No byte conversion
|
|
84
|
+
if (type !== "bytes") {
|
|
85
|
+
object[name] = copyValue(valueDecoded[name]);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
// Default byte conversion
|
|
89
|
+
if (!options || !options[OP_BYTES]) {
|
|
90
|
+
object[name] = (0, utils_1.decodeBase64)(valueDecoded[name]);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// Specific byte conversion
|
|
94
|
+
switch (options[OP_BYTES]) {
|
|
95
|
+
case "BASE58":
|
|
96
|
+
case "CONTRACT_ID":
|
|
97
|
+
case "ADDRESS":
|
|
98
|
+
object[name] = (0, utils_1.decodeBase58)(valueDecoded[name]);
|
|
99
|
+
break;
|
|
100
|
+
case "BASE64":
|
|
101
|
+
object[name] = (0, utils_1.decodeBase64)(valueDecoded[name]);
|
|
102
|
+
break;
|
|
103
|
+
case "HEX":
|
|
104
|
+
case "BLOCK_ID":
|
|
105
|
+
case "TRANSACTION_ID":
|
|
106
|
+
object[name] = (0, utils_1.toUint8Array)(valueDecoded[name].replace("0x", ""));
|
|
107
|
+
break;
|
|
108
|
+
default:
|
|
109
|
+
throw new Error(`unknown koinos_byte_type ${options[OP_BYTES]}`);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
object = valueDecoded;
|
|
115
|
+
}
|
|
116
|
+
const message = protobufType.create(object);
|
|
117
|
+
const buffer = protobufType.encode(message).finish();
|
|
118
|
+
return buffer;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Function to decode bytes using the protobuffer definitions
|
|
122
|
+
* It also encodes the bytes for special cases (base58, hex string)
|
|
123
|
+
* when bytesConversion param is true.
|
|
124
|
+
*/
|
|
125
|
+
async deserialize(valueEncoded, typeName) {
|
|
126
|
+
const valueBuffer = typeof valueEncoded === "string"
|
|
127
|
+
? (0, utils_1.decodeBase64)(valueEncoded)
|
|
128
|
+
: valueEncoded;
|
|
129
|
+
const protobufType = this.defaultType || this.root.lookupType(typeName);
|
|
130
|
+
const message = protobufType.decode(valueBuffer);
|
|
131
|
+
const object = protobufType.toObject(message, { longs: String });
|
|
132
|
+
if (!this.bytesConversion)
|
|
133
|
+
return object;
|
|
134
|
+
// TODO: format from Buffer to base58/base64 for nested fields
|
|
135
|
+
Object.keys(protobufType.fields).forEach((fieldName) => {
|
|
136
|
+
const { options, name, type } = protobufType.fields[fieldName];
|
|
137
|
+
// No byte conversion
|
|
138
|
+
if (type !== "bytes")
|
|
139
|
+
return;
|
|
140
|
+
// Default byte conversion
|
|
141
|
+
if (!options || !options[OP_BYTES]) {
|
|
142
|
+
object[name] = (0, utils_1.encodeBase64)(object[name]);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
// Specific byte conversion
|
|
146
|
+
switch (options[OP_BYTES]) {
|
|
147
|
+
case "BASE58":
|
|
148
|
+
case "CONTRACT_ID":
|
|
149
|
+
case "ADDRESS":
|
|
150
|
+
object[name] = (0, utils_1.encodeBase58)(object[name]);
|
|
151
|
+
break;
|
|
152
|
+
case "BASE64":
|
|
153
|
+
object[name] = (0, utils_1.encodeBase64)(object[name]);
|
|
154
|
+
break;
|
|
155
|
+
case "HEX":
|
|
156
|
+
case "BLOCK_ID":
|
|
157
|
+
case "TRANSACTION_ID":
|
|
158
|
+
object[name] = `0x${(0, utils_1.toHexString)(object[name])}`;
|
|
159
|
+
break;
|
|
160
|
+
default:
|
|
161
|
+
throw new Error(`unknown koinos_byte_type ${options[OP_BYTES]}`);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
return object;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
exports.Serializer = Serializer;
|
|
168
|
+
exports.default = Serializer;
|
|
169
|
+
//# sourceMappingURL=Serializer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Serializer.js","sourceRoot":"","sources":["../../src/Serializer.ts"],"names":[],"mappings":"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"}
|