koilib 2.1.0 → 2.4.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/README.md +17 -8
- package/dist/koinos.js +5849 -5744
- package/dist/koinos.min.js +1 -1
- package/dist/koinos.min.js.LICENSE.txt +1 -10
- package/lib/Contract.d.ts +48 -149
- package/lib/Contract.js +82 -156
- package/lib/Contract.js.map +1 -1
- package/lib/Provider.d.ts +2 -5
- package/lib/Provider.js +42 -11
- package/lib/Provider.js.map +1 -1
- package/lib/Serializer.d.ts +81 -0
- package/lib/Serializer.js +169 -0
- package/lib/Serializer.js.map +1 -0
- package/lib/Signer.d.ts +130 -24
- package/lib/Signer.js +162 -59
- package/lib/Signer.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/index2.js +2 -0
- package/lib/index2.js.map +1 -1
- package/lib/interface.d.ts +161 -24
- package/lib/{krc20-proto.json → jsonDescriptors/krc20-proto.json} +1 -1
- package/lib/{protocol-proto.json → jsonDescriptors/protocol-proto.json} +22 -18
- package/lib/utils.d.ts +250 -2
- package/lib/utils.js +29 -34
- package/lib/utils.js.map +1 -1
- package/package.json +7 -9
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
/*! koilib - MIT License (c) Julian Gonzalez (joticajulian@gmail.com) */
|
|
2
2
|
|
|
3
|
-
/*! noble-
|
|
3
|
+
/*! noble-hashes - MIT License (c) 2021 Paul Miller (paulmillr.com) */
|
|
4
4
|
|
|
5
5
|
/*! noble-secp256k1 - MIT License (c) Paul Miller (paulmillr.com) */
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* [js-sha256]{@link https://github.com/emn178/js-sha256}
|
|
9
|
-
*
|
|
10
|
-
* @version 0.9.0
|
|
11
|
-
* @author Chen, Yi-Cyuan [emn178@gmail.com]
|
|
12
|
-
* @copyright Chen, Yi-Cyuan 2014-2017
|
|
13
|
-
* @license MIT
|
|
14
|
-
*/
|
package/lib/Contract.d.ts
CHANGED
|
@@ -1,120 +1,7 @@
|
|
|
1
|
-
import { Root, INamespace } from "protobufjs/light";
|
|
2
1
|
import { Signer, SignerInterface } from "./Signer";
|
|
3
|
-
import { Provider
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
* Application Binary Interface (ABI)
|
|
7
|
-
*
|
|
8
|
-
* ABIs are composed of 2 elements: methods and types.
|
|
9
|
-
* - The methods define the names of the entries of the smart contract,
|
|
10
|
-
* the corresponding endpoints and the name of the types used.
|
|
11
|
-
* - The types all the description to serialize and deserialize
|
|
12
|
-
* using proto buffers.
|
|
13
|
-
*
|
|
14
|
-
* To generate the types is necessary to use the dependency
|
|
15
|
-
* protobufjs. The following example shows how to generate the
|
|
16
|
-
* protobuf descriptor from a .proto file.
|
|
17
|
-
*
|
|
18
|
-
* ```js
|
|
19
|
-
* const fs = require("fs");
|
|
20
|
-
* const pbjs = require("protobufjs/cli/pbjs");
|
|
21
|
-
*
|
|
22
|
-
* pbjs.main(
|
|
23
|
-
* ["--target", "json", "./token.proto"],
|
|
24
|
-
* (err, output) => {
|
|
25
|
-
* if (err) throw err;
|
|
26
|
-
* fs.writeFileSync("./token-proto.json", output);
|
|
27
|
-
* }
|
|
28
|
-
* );
|
|
29
|
-
* ```
|
|
30
|
-
*
|
|
31
|
-
* Then this descriptor can be loaded to define the ABI:
|
|
32
|
-
* ```js
|
|
33
|
-
* const tokenJson = require("./token-proto.json");
|
|
34
|
-
* const abiToken = {
|
|
35
|
-
* methods: {
|
|
36
|
-
* balanceOf: {
|
|
37
|
-
* entryPoint: 0x15619248,
|
|
38
|
-
* inputs: "balance_of_arguments",
|
|
39
|
-
* outputs: "balance_of_result",
|
|
40
|
-
* readOnly: true,
|
|
41
|
-
* defaultOutput: { value: "0" },
|
|
42
|
-
* },
|
|
43
|
-
* transfer: {
|
|
44
|
-
* entryPoint: 0x62efa292,
|
|
45
|
-
* inputs: "transfer_arguments",
|
|
46
|
-
* outputs: "transfer_result",
|
|
47
|
-
* },
|
|
48
|
-
* mint: {
|
|
49
|
-
* entryPoint: 0xc2f82bdc,
|
|
50
|
-
* inputs: "mint_argumnets",
|
|
51
|
-
* outputs: "mint_result",
|
|
52
|
-
* },
|
|
53
|
-
* },
|
|
54
|
-
* types: tokenJson,
|
|
55
|
-
* };
|
|
56
|
-
* ```
|
|
57
|
-
*
|
|
58
|
-
* Note that this example uses "defaultOutput" for the method
|
|
59
|
-
* "balanceOf". This is used when the smart contract returns an
|
|
60
|
-
* empty response (for instance when there are no balance records
|
|
61
|
-
* for a specific address) and you require a default output in
|
|
62
|
-
* such cases.
|
|
63
|
-
*/
|
|
64
|
-
export interface Abi {
|
|
65
|
-
methods: {
|
|
66
|
-
/** Name of the method */
|
|
67
|
-
[x: string]: {
|
|
68
|
-
/** Entry point ID */
|
|
69
|
-
entryPoint: number;
|
|
70
|
-
/** Protobuffer type for input */
|
|
71
|
-
inputs?: string;
|
|
72
|
-
/** Protobuffer type for output */
|
|
73
|
-
outputs?: string;
|
|
74
|
-
/** Boolean to differentiate write methods
|
|
75
|
-
* (using transactions) from read methods
|
|
76
|
-
* (query the contract)
|
|
77
|
-
*/
|
|
78
|
-
readOnly?: boolean;
|
|
79
|
-
/** Default value when the output is undefined */
|
|
80
|
-
defaultOutput?: unknown;
|
|
81
|
-
/** Description of the method */
|
|
82
|
-
description?: string;
|
|
83
|
-
};
|
|
84
|
-
};
|
|
85
|
-
/**
|
|
86
|
-
* Protobuffers descriptor in JSON format.
|
|
87
|
-
* See https://www.npmjs.com/package/protobufjs#using-json-descriptors
|
|
88
|
-
*/
|
|
89
|
-
types: INamespace;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Human readable format operation
|
|
93
|
-
*
|
|
94
|
-
* @example
|
|
95
|
-
* ```ts
|
|
96
|
-
* const opDecoded = {
|
|
97
|
-
* name: "transfer",
|
|
98
|
-
* args: {
|
|
99
|
-
* from: "1Krs7v1rtpgRyfwEZncuKMQQnY5JhqXVSx",
|
|
100
|
-
* to: "1BqtgWBcqm9cSZ97avLGZGJdgso7wx6pCA",
|
|
101
|
-
* value: 1000,
|
|
102
|
-
* },
|
|
103
|
-
* };
|
|
104
|
-
* ```
|
|
105
|
-
*/
|
|
106
|
-
export interface DecodedOperationJson {
|
|
107
|
-
/** Operation name */
|
|
108
|
-
name: string;
|
|
109
|
-
/** Arguments decoded. See [[Abi]] */
|
|
110
|
-
args?: Record<string, unknown>;
|
|
111
|
-
}
|
|
112
|
-
export interface TransactionOptions {
|
|
113
|
-
rcLimit?: number | bigint | string;
|
|
114
|
-
nonce?: number;
|
|
115
|
-
sendTransaction?: boolean;
|
|
116
|
-
sendAbis?: boolean;
|
|
117
|
-
}
|
|
2
|
+
import { Provider } from "./Provider";
|
|
3
|
+
import { Serializer } from "./Serializer";
|
|
4
|
+
import { CallContractOperationNested, UploadContractOperationNested, TransactionJson, Abi, TransactionOptions, DecodedOperationJson, SendTransactionResponse } from "./interface";
|
|
118
5
|
/**
|
|
119
6
|
* The contract class contains the contract ID and contract entries
|
|
120
7
|
* definition needed to encode/decode operations during the
|
|
@@ -125,9 +12,9 @@ export interface TransactionOptions {
|
|
|
125
12
|
* ```ts
|
|
126
13
|
* const { Contract, Provider, Signer, utils } = require("koilib");
|
|
127
14
|
* const rpcNodes = ["http://api.koinos.io:8080"];
|
|
128
|
-
* const
|
|
15
|
+
* const privateKey = "f186a5de49797bfd52dc42505c33d75a46822ed5b60046e09d7c336242e20200";
|
|
129
16
|
* const provider = new Provider(rpcNodes);
|
|
130
|
-
* const signer = new Signer(
|
|
17
|
+
* const signer = new Signer({ privateKey, provider });
|
|
131
18
|
* const koinContract = new Contract({
|
|
132
19
|
* id: "19JntSm8pSNETT9aHTwAUHC5RMoaSmgZPJ",
|
|
133
20
|
* abi: utils.Krc20Abi,
|
|
@@ -136,18 +23,26 @@ export interface TransactionOptions {
|
|
|
136
23
|
* });
|
|
137
24
|
* const koin = koinContract.functions;
|
|
138
25
|
*
|
|
26
|
+
* // optional: preformat input/output
|
|
27
|
+
* koinContract.abi.methods.balanceOf.preformatInput = (owner) =>
|
|
28
|
+
* ({ owner });
|
|
29
|
+
* koinContract.abi.methods.balanceOf.preformatOutput = (res) =>
|
|
30
|
+
* utils.formatUnits(res.value, 8);
|
|
31
|
+
* koinContract.abi.methods.transfer.preformatInput = (input) => ({
|
|
32
|
+
* from: signer.getAddress(),
|
|
33
|
+
* to: input.to,
|
|
34
|
+
* value: utils.parseUnits(input.value, 8),
|
|
35
|
+
* });
|
|
36
|
+
*
|
|
139
37
|
* async funtion main() {
|
|
140
38
|
* // Get balance
|
|
141
|
-
* const { result } = await koin.balanceOf(
|
|
142
|
-
*
|
|
143
|
-
* });
|
|
144
|
-
* console.log(balance.result)
|
|
39
|
+
* const { result } = await koin.balanceOf("12fN2CQnuJM8cMnWZ1hPtM4knjLME8E4PD");
|
|
40
|
+
* console.log(result)
|
|
145
41
|
*
|
|
146
42
|
* // Transfer
|
|
147
43
|
* const { transaction, transactionResponse } = await koin.transfer({
|
|
148
|
-
* from: "12fN2CQnuJM8cMnWZ1hPtM4knjLME8E4PD",
|
|
149
44
|
* to: "172AB1FgCsYrRAW5cwQ8KjadgxofvgPFd6",
|
|
150
|
-
* value: "
|
|
45
|
+
* value: "10.0001",
|
|
151
46
|
* });
|
|
152
47
|
* console.log(`Transaction id ${transaction.id} submitted`);
|
|
153
48
|
*
|
|
@@ -164,17 +59,19 @@ export declare class Contract {
|
|
|
164
59
|
* Contract ID
|
|
165
60
|
*/
|
|
166
61
|
id?: Uint8Array;
|
|
167
|
-
/**
|
|
168
|
-
* Protobuffer definitions
|
|
169
|
-
*/
|
|
170
|
-
protobuffers?: Root;
|
|
171
62
|
/**
|
|
172
63
|
* Set of functions to interact with the smart
|
|
173
64
|
* contract. These functions are automatically generated
|
|
174
65
|
* in the constructor of the class
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* const owner = "1Gvqdo9if6v6tFomEuTuMWP1D7H7U9yksb";
|
|
70
|
+
* await koinContract.functions.balanceOf({ owner });
|
|
71
|
+
* ```
|
|
175
72
|
*/
|
|
176
73
|
functions: {
|
|
177
|
-
[x: string]: <T = Record<string, unknown>>(args?:
|
|
74
|
+
[x: string]: <T = Record<string, unknown>>(args?: unknown, opts?: TransactionOptions) => Promise<{
|
|
178
75
|
operation: CallContractOperationNested;
|
|
179
76
|
transaction?: TransactionJson;
|
|
180
77
|
transactionResponse?: SendTransactionResponse;
|
|
@@ -193,13 +90,17 @@ export declare class Contract {
|
|
|
193
90
|
* Provider to connect with the blockchain
|
|
194
91
|
*/
|
|
195
92
|
provider?: Provider;
|
|
93
|
+
/**
|
|
94
|
+
* Serializer to serialize/deserialize data types
|
|
95
|
+
*/
|
|
96
|
+
serializer?: Serializer;
|
|
196
97
|
/**
|
|
197
98
|
* Bytecode. Needed to deploy the smart contract.
|
|
198
99
|
*/
|
|
199
100
|
bytecode?: Uint8Array;
|
|
200
101
|
/**
|
|
201
102
|
* Options to apply when creating transactions.
|
|
202
|
-
* By default it set
|
|
103
|
+
* By default it set rc_limit to 1e8, sendTransaction true,
|
|
203
104
|
* sendAbis true, and nonce undefined (to get it from the blockchain)
|
|
204
105
|
*/
|
|
205
106
|
options: TransactionOptions;
|
|
@@ -210,6 +111,13 @@ export declare class Contract {
|
|
|
210
111
|
options?: TransactionOptions;
|
|
211
112
|
signer?: Signer;
|
|
212
113
|
provider?: Provider;
|
|
114
|
+
/**
|
|
115
|
+
* Set this option if you can not use _eval_ functions
|
|
116
|
+
* in the current environment. In such cases, the
|
|
117
|
+
* serializer must come from an environment where it
|
|
118
|
+
* is able to use those functions.
|
|
119
|
+
*/
|
|
120
|
+
serializer?: Serializer;
|
|
213
121
|
});
|
|
214
122
|
/**
|
|
215
123
|
* Compute contract Id
|
|
@@ -224,8 +132,9 @@ export declare class Contract {
|
|
|
224
132
|
* The Bytecode must be defined in the constructor of the class
|
|
225
133
|
* @example
|
|
226
134
|
* ```ts
|
|
227
|
-
* const
|
|
135
|
+
* const privateKey = "f186a5de49797bfd52dc42505c33d75a46822ed5b60046e09d7c336242e20200";
|
|
228
136
|
* const provider = new Provider(["http://api.koinos.io:8080"]);
|
|
137
|
+
* const signer = new Signer({ privateKey, provider });
|
|
229
138
|
* const bytecode = new Uint8Array([1, 2, 3, 4]);
|
|
230
139
|
* const contract = new Contract({ signer, provider, bytecode });
|
|
231
140
|
* const { transactionResponse } = await contract.deploy();
|
|
@@ -257,23 +166,23 @@ export declare class Contract {
|
|
|
257
166
|
*
|
|
258
167
|
* console.log(opEncoded);
|
|
259
168
|
* // {
|
|
260
|
-
* //
|
|
261
|
-
* //
|
|
262
|
-
* //
|
|
169
|
+
* // call_contract: {
|
|
170
|
+
* // contract_id: "19JntSm8pSNETT9aHTwAUHC5RMoaSmgZPJ",
|
|
171
|
+
* // entry_point: 0x62efa292,
|
|
263
172
|
* // args: "MBWFsaWNlA2JvYgAAAAAAAAPo",
|
|
264
173
|
* // }
|
|
265
174
|
* // }
|
|
266
175
|
* ```
|
|
267
176
|
*/
|
|
268
|
-
encodeOperation(op: DecodedOperationJson): CallContractOperationNested
|
|
177
|
+
encodeOperation(op: DecodedOperationJson): Promise<CallContractOperationNested>;
|
|
269
178
|
/**
|
|
270
179
|
* Decodes a contract operation to be human readable
|
|
271
180
|
* @example
|
|
272
181
|
* ```ts
|
|
273
182
|
* const opDecoded = contract.decodeOperation({
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
183
|
+
* call_contract: {
|
|
184
|
+
* contract_id: "19JntSm8pSNETT9aHTwAUHC5RMoaSmgZPJ",
|
|
185
|
+
* entry_point: 0x62efa292,
|
|
277
186
|
* args: "MBWFsaWNlA2JvYgAAAAAAAAPo",
|
|
278
187
|
* }
|
|
279
188
|
* });
|
|
@@ -288,16 +197,6 @@ export declare class Contract {
|
|
|
288
197
|
* // }
|
|
289
198
|
* ```
|
|
290
199
|
*/
|
|
291
|
-
decodeOperation(op: CallContractOperationNested): DecodedOperationJson
|
|
292
|
-
/**
|
|
293
|
-
* Function to encode a type using the protobuffer definitions
|
|
294
|
-
* It also prepares the bytes for special cases (base58, hex string)
|
|
295
|
-
*/
|
|
296
|
-
encodeType(valueDecoded: Record<string, unknown>, typeName: string): Uint8Array;
|
|
297
|
-
/**
|
|
298
|
-
* Function to decode bytes using the protobuffer definitions
|
|
299
|
-
* It also encodes the bytes for special cases (base58, hex string)
|
|
300
|
-
*/
|
|
301
|
-
decodeType<T = Record<string, unknown>>(valueEncoded: string | Uint8Array, typeName: string): T;
|
|
200
|
+
decodeOperation(op: CallContractOperationNested): Promise<DecodedOperationJson>;
|
|
302
201
|
}
|
|
303
202
|
export default Contract;
|
package/lib/Contract.js
CHANGED
|
@@ -1,24 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Contract = void 0;
|
|
4
|
-
const
|
|
4
|
+
const Serializer_1 = require("./Serializer");
|
|
5
5
|
const utils_1 = require("./utils");
|
|
6
|
-
const OP_BYTES = "(koinos_bytes_type)";
|
|
7
|
-
/**
|
|
8
|
-
* Makes a copy of a value. The returned value can be modified
|
|
9
|
-
* without altering the original one. Although this is not needed
|
|
10
|
-
* for strings or numbers and only needed for objects and arrays,
|
|
11
|
-
* all these options are covered in a single function
|
|
12
|
-
*
|
|
13
|
-
* It is assumed that the argument is number, string, or contructions
|
|
14
|
-
* of these types inside objects or arrays.
|
|
15
|
-
*/
|
|
16
|
-
function copyValue(value) {
|
|
17
|
-
if (typeof value === "string" || typeof value === "number") {
|
|
18
|
-
return value;
|
|
19
|
-
}
|
|
20
|
-
return JSON.parse(JSON.stringify(value));
|
|
21
|
-
}
|
|
22
6
|
/**
|
|
23
7
|
* The contract class contains the contract ID and contract entries
|
|
24
8
|
* definition needed to encode/decode operations during the
|
|
@@ -29,9 +13,9 @@ function copyValue(value) {
|
|
|
29
13
|
* ```ts
|
|
30
14
|
* const { Contract, Provider, Signer, utils } = require("koilib");
|
|
31
15
|
* const rpcNodes = ["http://api.koinos.io:8080"];
|
|
32
|
-
* const
|
|
16
|
+
* const privateKey = "f186a5de49797bfd52dc42505c33d75a46822ed5b60046e09d7c336242e20200";
|
|
33
17
|
* const provider = new Provider(rpcNodes);
|
|
34
|
-
* const signer = new Signer(
|
|
18
|
+
* const signer = new Signer({ privateKey, provider });
|
|
35
19
|
* const koinContract = new Contract({
|
|
36
20
|
* id: "19JntSm8pSNETT9aHTwAUHC5RMoaSmgZPJ",
|
|
37
21
|
* abi: utils.Krc20Abi,
|
|
@@ -40,18 +24,26 @@ function copyValue(value) {
|
|
|
40
24
|
* });
|
|
41
25
|
* const koin = koinContract.functions;
|
|
42
26
|
*
|
|
27
|
+
* // optional: preformat input/output
|
|
28
|
+
* koinContract.abi.methods.balanceOf.preformatInput = (owner) =>
|
|
29
|
+
* ({ owner });
|
|
30
|
+
* koinContract.abi.methods.balanceOf.preformatOutput = (res) =>
|
|
31
|
+
* utils.formatUnits(res.value, 8);
|
|
32
|
+
* koinContract.abi.methods.transfer.preformatInput = (input) => ({
|
|
33
|
+
* from: signer.getAddress(),
|
|
34
|
+
* to: input.to,
|
|
35
|
+
* value: utils.parseUnits(input.value, 8),
|
|
36
|
+
* });
|
|
37
|
+
*
|
|
43
38
|
* async funtion main() {
|
|
44
39
|
* // Get balance
|
|
45
|
-
* const { result } = await koin.balanceOf(
|
|
46
|
-
*
|
|
47
|
-
* });
|
|
48
|
-
* console.log(balance.result)
|
|
40
|
+
* const { result } = await koin.balanceOf("12fN2CQnuJM8cMnWZ1hPtM4knjLME8E4PD");
|
|
41
|
+
* console.log(result)
|
|
49
42
|
*
|
|
50
43
|
* // Transfer
|
|
51
44
|
* const { transaction, transactionResponse } = await koin.transfer({
|
|
52
|
-
* from: "12fN2CQnuJM8cMnWZ1hPtM4knjLME8E4PD",
|
|
53
45
|
* to: "172AB1FgCsYrRAW5cwQ8KjadgxofvgPFd6",
|
|
54
|
-
* value: "
|
|
46
|
+
* value: "10.0001",
|
|
55
47
|
* });
|
|
56
48
|
* console.log(`Transaction id ${transaction.id} submitted`);
|
|
57
49
|
*
|
|
@@ -65,46 +57,67 @@ function copyValue(value) {
|
|
|
65
57
|
*/
|
|
66
58
|
class Contract {
|
|
67
59
|
constructor(c) {
|
|
68
|
-
var _a
|
|
60
|
+
var _a;
|
|
69
61
|
if (c.id)
|
|
70
62
|
this.id = utils_1.decodeBase58(c.id);
|
|
71
63
|
this.signer = c.signer;
|
|
72
64
|
this.provider = c.provider || ((_a = c.signer) === null || _a === void 0 ? void 0 : _a.provider);
|
|
73
65
|
this.abi = c.abi;
|
|
74
66
|
this.bytecode = c.bytecode;
|
|
75
|
-
if (
|
|
76
|
-
this.
|
|
67
|
+
if (c.serializer) {
|
|
68
|
+
this.serializer = c.serializer;
|
|
69
|
+
}
|
|
70
|
+
else if (c.abi && c.abi.types) {
|
|
71
|
+
this.serializer = new Serializer_1.Serializer(c.abi.types);
|
|
72
|
+
}
|
|
77
73
|
this.options = {
|
|
78
|
-
|
|
74
|
+
rc_limit: 1e8,
|
|
79
75
|
sendTransaction: true,
|
|
80
76
|
sendAbis: true,
|
|
81
77
|
...c.options,
|
|
82
78
|
};
|
|
83
79
|
this.functions = {};
|
|
84
|
-
if (this.signer &&
|
|
80
|
+
if (this.signer &&
|
|
81
|
+
this.provider &&
|
|
82
|
+
this.abi &&
|
|
83
|
+
this.abi.methods &&
|
|
84
|
+
this.serializer) {
|
|
85
85
|
Object.keys(this.abi.methods).forEach((name) => {
|
|
86
|
-
this.functions[name] = async (
|
|
86
|
+
this.functions[name] = async (argu = {}, options) => {
|
|
87
87
|
if (!this.provider)
|
|
88
88
|
throw new Error("provider not found");
|
|
89
89
|
if (!this.abi || !this.abi.methods)
|
|
90
90
|
throw new Error("Methods are not defined");
|
|
91
|
+
if (!this.abi.methods[name])
|
|
92
|
+
throw new Error(`Method ${name} not defined in the ABI`);
|
|
91
93
|
const opts = {
|
|
92
94
|
...this.options,
|
|
93
95
|
...options,
|
|
94
96
|
};
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
const { readOnly, output, defaultOutput, preformatInput, preformatOutput, } = this.abi.methods[name];
|
|
98
|
+
let args;
|
|
99
|
+
if (typeof preformatInput === "function") {
|
|
100
|
+
args = preformatInput(argu);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
args = argu;
|
|
104
|
+
}
|
|
105
|
+
const operation = await this.encodeOperation({ name, args });
|
|
106
|
+
if (readOnly) {
|
|
107
|
+
if (!output)
|
|
108
|
+
throw new Error(`No output defined for ${name}`);
|
|
99
109
|
// read contract
|
|
100
110
|
const { result: resultEncoded } = await this.provider.readContract({
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
args: utils_1.encodeBase64(operation.
|
|
111
|
+
contract_id: utils_1.encodeBase58(operation.call_contract.contract_id),
|
|
112
|
+
entry_point: operation.call_contract.entry_point,
|
|
113
|
+
args: utils_1.encodeBase64(operation.call_contract.args),
|
|
104
114
|
});
|
|
105
|
-
let result =
|
|
115
|
+
let result = defaultOutput;
|
|
106
116
|
if (resultEncoded) {
|
|
107
|
-
result = this.
|
|
117
|
+
result = await this.serializer.deserialize(resultEncoded, output);
|
|
118
|
+
}
|
|
119
|
+
if (typeof preformatOutput === "function") {
|
|
120
|
+
result = preformatOutput(result);
|
|
108
121
|
}
|
|
109
122
|
return { operation, result };
|
|
110
123
|
}
|
|
@@ -148,8 +161,9 @@ class Contract {
|
|
|
148
161
|
* The Bytecode must be defined in the constructor of the class
|
|
149
162
|
* @example
|
|
150
163
|
* ```ts
|
|
151
|
-
* const
|
|
164
|
+
* const privateKey = "f186a5de49797bfd52dc42505c33d75a46822ed5b60046e09d7c336242e20200";
|
|
152
165
|
* const provider = new Provider(["http://api.koinos.io:8080"]);
|
|
166
|
+
* const signer = new Signer({ privateKey, provider });
|
|
153
167
|
* const bytecode = new Uint8Array([1, 2, 3, 4]);
|
|
154
168
|
* const contract = new Contract({ signer, provider, bytecode });
|
|
155
169
|
* const { transactionResponse } = await contract.deploy();
|
|
@@ -168,8 +182,8 @@ class Contract {
|
|
|
168
182
|
...options,
|
|
169
183
|
};
|
|
170
184
|
const operation = {
|
|
171
|
-
|
|
172
|
-
|
|
185
|
+
upload_contract: {
|
|
186
|
+
contract_id: Contract.computeContractId(this.signer.getAddress()),
|
|
173
187
|
bytecode: this.bytecode,
|
|
174
188
|
},
|
|
175
189
|
};
|
|
@@ -201,32 +215,32 @@ class Contract {
|
|
|
201
215
|
*
|
|
202
216
|
* console.log(opEncoded);
|
|
203
217
|
* // {
|
|
204
|
-
* //
|
|
205
|
-
* //
|
|
206
|
-
* //
|
|
218
|
+
* // call_contract: {
|
|
219
|
+
* // contract_id: "19JntSm8pSNETT9aHTwAUHC5RMoaSmgZPJ",
|
|
220
|
+
* // entry_point: 0x62efa292,
|
|
207
221
|
* // args: "MBWFsaWNlA2JvYgAAAAAAAAPo",
|
|
208
222
|
* // }
|
|
209
223
|
* // }
|
|
210
224
|
* ```
|
|
211
225
|
*/
|
|
212
|
-
encodeOperation(op) {
|
|
226
|
+
async encodeOperation(op) {
|
|
213
227
|
if (!this.abi || !this.abi.methods || !this.abi.methods[op.name])
|
|
214
228
|
throw new Error(`Operation ${op.name} unknown`);
|
|
215
|
-
if (!this.
|
|
216
|
-
throw new Error("
|
|
229
|
+
if (!this.serializer)
|
|
230
|
+
throw new Error("Serializer is not defined");
|
|
217
231
|
if (!this.id)
|
|
218
232
|
throw new Error("Contract id is not defined");
|
|
219
233
|
const method = this.abi.methods[op.name];
|
|
220
234
|
let bufferInputs = new Uint8Array(0);
|
|
221
|
-
if (method.
|
|
235
|
+
if (method.input) {
|
|
222
236
|
if (!op.args)
|
|
223
|
-
throw new Error(`No arguments defined for type '${method.
|
|
224
|
-
bufferInputs = this.
|
|
237
|
+
throw new Error(`No arguments defined for type '${method.input}'`);
|
|
238
|
+
bufferInputs = await this.serializer.serialize(op.args, method.input);
|
|
225
239
|
}
|
|
226
240
|
return {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
241
|
+
call_contract: {
|
|
242
|
+
contract_id: this.id,
|
|
243
|
+
entry_point: method.entryPoint,
|
|
230
244
|
args: bufferInputs,
|
|
231
245
|
},
|
|
232
246
|
};
|
|
@@ -236,9 +250,9 @@ class Contract {
|
|
|
236
250
|
* @example
|
|
237
251
|
* ```ts
|
|
238
252
|
* const opDecoded = contract.decodeOperation({
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
*
|
|
253
|
+
* call_contract: {
|
|
254
|
+
* contract_id: "19JntSm8pSNETT9aHTwAUHC5RMoaSmgZPJ",
|
|
255
|
+
* entry_point: 0x62efa292,
|
|
242
256
|
* args: "MBWFsaWNlA2JvYgAAAAAAAAPo",
|
|
243
257
|
* }
|
|
244
258
|
* });
|
|
@@ -253,118 +267,30 @@ class Contract {
|
|
|
253
267
|
* // }
|
|
254
268
|
* ```
|
|
255
269
|
*/
|
|
256
|
-
decodeOperation(op) {
|
|
270
|
+
async decodeOperation(op) {
|
|
257
271
|
if (!this.id)
|
|
258
272
|
throw new Error("Contract id is not defined");
|
|
259
273
|
if (!this.abi || !this.abi.methods)
|
|
260
274
|
throw new Error("Methods are not defined");
|
|
261
|
-
if (!
|
|
275
|
+
if (!this.serializer)
|
|
276
|
+
throw new Error("Serializer is not defined");
|
|
277
|
+
if (!op.call_contract)
|
|
262
278
|
throw new Error("Operation is not CallContractOperation");
|
|
263
|
-
if (op.
|
|
264
|
-
throw new Error(`Invalid contract id. Expected: ${utils_1.encodeBase58(this.id)}. Received: ${utils_1.encodeBase58(op.
|
|
279
|
+
if (op.call_contract.contract_id !== this.id)
|
|
280
|
+
throw new Error(`Invalid contract id. Expected: ${utils_1.encodeBase58(this.id)}. Received: ${utils_1.encodeBase58(op.call_contract.contract_id)}`);
|
|
265
281
|
for (let i = 0; i < Object.keys(this.abi.methods).length; i += 1) {
|
|
266
282
|
const opName = Object.keys(this.abi.methods)[i];
|
|
267
283
|
const method = this.abi.methods[opName];
|
|
268
|
-
if (op.
|
|
269
|
-
if (!method.
|
|
284
|
+
if (op.call_contract.entry_point === method.entryPoint) {
|
|
285
|
+
if (!method.input)
|
|
270
286
|
return { name: opName };
|
|
271
287
|
return {
|
|
272
288
|
name: opName,
|
|
273
|
-
args: this.
|
|
289
|
+
args: await this.serializer.deserialize(op.call_contract.args, method.input),
|
|
274
290
|
};
|
|
275
291
|
}
|
|
276
292
|
}
|
|
277
|
-
throw new Error(`Unknown method id ${op.
|
|
278
|
-
}
|
|
279
|
-
/**
|
|
280
|
-
* Function to encode a type using the protobuffer definitions
|
|
281
|
-
* It also prepares the bytes for special cases (base58, hex string)
|
|
282
|
-
*/
|
|
283
|
-
encodeType(valueDecoded, typeName) {
|
|
284
|
-
if (!this.protobuffers)
|
|
285
|
-
throw new Error("Protobuffers are not defined");
|
|
286
|
-
const protobufType = this.protobuffers.lookupType(typeName);
|
|
287
|
-
const object = {};
|
|
288
|
-
// TODO: format from Buffer to base58/base64 for nested fields
|
|
289
|
-
Object.keys(protobufType.fields).forEach((fieldName) => {
|
|
290
|
-
const { options, name, type } = protobufType.fields[fieldName];
|
|
291
|
-
// No byte conversion
|
|
292
|
-
if (type !== "bytes") {
|
|
293
|
-
object[name] = copyValue(valueDecoded[name]);
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
// Default byte conversion
|
|
297
|
-
if (!options || !options[OP_BYTES]) {
|
|
298
|
-
object[name] = utils_1.decodeBase64(valueDecoded[name]);
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
// Specific byte conversion
|
|
302
|
-
switch (options[OP_BYTES]) {
|
|
303
|
-
case "BASE58":
|
|
304
|
-
case "CONTRACT_ID":
|
|
305
|
-
case "ADDRESS":
|
|
306
|
-
object[name] = utils_1.decodeBase58(valueDecoded[name]);
|
|
307
|
-
break;
|
|
308
|
-
case "BASE64":
|
|
309
|
-
object[name] = utils_1.decodeBase64(valueDecoded[name]);
|
|
310
|
-
break;
|
|
311
|
-
case "HEX":
|
|
312
|
-
case "BLOCK_ID":
|
|
313
|
-
case "TRANSACTION_ID":
|
|
314
|
-
object[name] = utils_1.toUint8Array(valueDecoded[name].replace("0x", ""));
|
|
315
|
-
break;
|
|
316
|
-
default:
|
|
317
|
-
throw new Error(`unknown koinos_byte_type ${options[OP_BYTES]}`);
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
const message = protobufType.create(object);
|
|
321
|
-
const buffer = protobufType.encode(message).finish();
|
|
322
|
-
return buffer;
|
|
323
|
-
}
|
|
324
|
-
/**
|
|
325
|
-
* Function to decode bytes using the protobuffer definitions
|
|
326
|
-
* It also encodes the bytes for special cases (base58, hex string)
|
|
327
|
-
*/
|
|
328
|
-
decodeType(valueEncoded, typeName) {
|
|
329
|
-
if (!this.protobuffers)
|
|
330
|
-
throw new Error("Protobuffers are not defined");
|
|
331
|
-
const valueBuffer = typeof valueEncoded === "string"
|
|
332
|
-
? utils_1.decodeBase64(valueEncoded)
|
|
333
|
-
: valueEncoded;
|
|
334
|
-
const protobufType = this.protobuffers.lookupType(typeName);
|
|
335
|
-
const message = protobufType.decode(valueBuffer);
|
|
336
|
-
const object = protobufType.toObject(message, { longs: String });
|
|
337
|
-
// TODO: format from Buffer to base58/base64 for nested fields
|
|
338
|
-
Object.keys(protobufType.fields).forEach((fieldName) => {
|
|
339
|
-
const { options, name, type } = protobufType.fields[fieldName];
|
|
340
|
-
// No byte conversion
|
|
341
|
-
if (type !== "bytes")
|
|
342
|
-
return;
|
|
343
|
-
// Default byte conversion
|
|
344
|
-
if (!options || !options[OP_BYTES]) {
|
|
345
|
-
object[name] = utils_1.encodeBase64(object[name]);
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
|
-
// Specific byte conversion
|
|
349
|
-
switch (options[OP_BYTES]) {
|
|
350
|
-
case "BASE58":
|
|
351
|
-
case "CONTRACT_ID":
|
|
352
|
-
case "ADDRESS":
|
|
353
|
-
object[name] = utils_1.encodeBase58(object[name]);
|
|
354
|
-
break;
|
|
355
|
-
case "BASE64":
|
|
356
|
-
object[name] = utils_1.encodeBase64(object[name]);
|
|
357
|
-
break;
|
|
358
|
-
case "HEX":
|
|
359
|
-
case "BLOCK_ID":
|
|
360
|
-
case "TRANSACTION_ID":
|
|
361
|
-
object[name] = `0x${utils_1.toHexString(object[name])}`;
|
|
362
|
-
break;
|
|
363
|
-
default:
|
|
364
|
-
throw new Error(`unknown koinos_byte_type ${options[OP_BYTES]}`);
|
|
365
|
-
}
|
|
366
|
-
});
|
|
367
|
-
return object;
|
|
293
|
+
throw new Error(`Unknown method id ${op.call_contract.entry_point}`);
|
|
368
294
|
}
|
|
369
295
|
}
|
|
370
296
|
exports.Contract = Contract;
|