@xelis/sdk 0.11.31 → 0.11.33
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/cjs/contract/contract.js +126 -84
- package/dist/cjs/contract/typed_contract.js +134 -88
- package/dist/cjs/contract/xvm_serializer.js +252 -29
- package/dist/cjs/daemon/rpc.js +21 -0
- package/dist/cjs/daemon/types.js +14 -2
- package/dist/cjs/daemon/websocket.js +21 -0
- package/dist/cjs/rpc/websocket.js +10 -4
- package/dist/esm/contract/contract.js +125 -83
- package/dist/esm/contract/typed_contract.js +131 -85
- package/dist/esm/contract/xvm_serializer.js +244 -27
- package/dist/esm/daemon/rpc.js +21 -0
- package/dist/esm/daemon/types.js +13 -1
- package/dist/esm/daemon/websocket.js +21 -0
- package/dist/esm/rpc/websocket.js +10 -4
- package/dist/types/contract/contract.d.ts +46 -10
- package/dist/types/contract/typed_contract.d.ts +50 -15
- package/dist/types/contract/xvm_serializer.d.ts +68 -4
- package/dist/types/daemon/rpc.d.ts +8 -1
- package/dist/types/daemon/types.d.ts +82 -2
- package/dist/types/daemon/websocket.d.ts +8 -1
- package/package.json +1 -1
|
@@ -1,37 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ContractFactory = exports.
|
|
3
|
+
exports.ContractFactory = exports.create_contract = exports.Contract = void 0;
|
|
4
4
|
const xvm_serializer_1 = require("./xvm_serializer");
|
|
5
|
-
;
|
|
6
|
-
// Convert ABI type to our validator type
|
|
7
|
-
function normalizeType(abiType) {
|
|
8
|
-
const typeMap = {
|
|
9
|
-
'Hash': 'Hash',
|
|
10
|
-
'Address': 'Address',
|
|
11
|
-
'PublicKey': 'PublicKey',
|
|
12
|
-
'Blob': 'Blob',
|
|
13
|
-
'u256': 'u256',
|
|
14
|
-
'u128': 'u128',
|
|
15
|
-
'u64': 'u64',
|
|
16
|
-
'u32': 'u32',
|
|
17
|
-
'u16': 'u16',
|
|
18
|
-
'u8': 'u8',
|
|
19
|
-
'boolean': 'boolean',
|
|
20
|
-
'bool': 'boolean',
|
|
21
|
-
'string': 'string',
|
|
22
|
-
'String': 'string',
|
|
23
|
-
'Boolean': 'boolean',
|
|
24
|
-
'U64': 'u64',
|
|
25
|
-
'U32': 'u32',
|
|
26
|
-
'U16': 'u16',
|
|
27
|
-
'U8': 'u8'
|
|
28
|
-
};
|
|
29
|
-
const normalized = typeMap[abiType];
|
|
30
|
-
if (!normalized) {
|
|
31
|
-
throw new Error(`Unknown ABI type: ${abiType}`);
|
|
32
|
-
}
|
|
33
|
-
return normalized;
|
|
34
|
-
}
|
|
35
5
|
/**
|
|
36
6
|
* Contract class that dynamically generates methods based on ABI
|
|
37
7
|
*/
|
|
@@ -40,107 +10,179 @@ class Contract {
|
|
|
40
10
|
this.address = address;
|
|
41
11
|
this.abi = abi;
|
|
42
12
|
this.methods = new Map();
|
|
43
|
-
|
|
13
|
+
this.register_internal_types();
|
|
44
14
|
for (const entry of abi.data) {
|
|
45
15
|
if (entry.type === 'entry') {
|
|
46
16
|
this.methods.set(entry.name, entry);
|
|
47
|
-
|
|
48
|
-
|
|
17
|
+
this.create_dynamic_method(entry);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Register all custom types from ABI
|
|
23
|
+
*/
|
|
24
|
+
register_internal_types() {
|
|
25
|
+
if (!this.abi.internal_types)
|
|
26
|
+
return;
|
|
27
|
+
for (const type_def of this.abi.internal_types) {
|
|
28
|
+
if (type_def.kind === 'enum' && type_def.variants) {
|
|
29
|
+
xvm_serializer_1.typeRegistry.register((0, xvm_serializer_1.defineEnum)(type_def.name, type_def.variants));
|
|
30
|
+
}
|
|
31
|
+
else if (type_def.kind === 'struct' && type_def.fields) {
|
|
32
|
+
xvm_serializer_1.typeRegistry.register((0, xvm_serializer_1.defineStruct)(type_def.name, type_def.fields));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Helper to create struct values with positional arguments
|
|
38
|
+
* Validates field types immediately
|
|
39
|
+
* @param type_name - Name of the struct type
|
|
40
|
+
* @param field_values - Field values in the order defined in ABI
|
|
41
|
+
*/
|
|
42
|
+
struct(type_name, ...field_values) {
|
|
43
|
+
const type_def = this.abi.internal_types?.find(t => t.name === type_name && t.kind === 'struct');
|
|
44
|
+
if (!type_def || !type_def.fields) {
|
|
45
|
+
throw new Error(`Struct type '${type_name}' not found in contract ABI`);
|
|
46
|
+
}
|
|
47
|
+
if (field_values.length !== type_def.fields.length) {
|
|
48
|
+
throw new Error(`Struct '${type_name}' expects ${type_def.fields.length} fields ` +
|
|
49
|
+
`(${type_def.fields.map(f => f.name).join(', ')}), ` +
|
|
50
|
+
`but got ${field_values.length}`);
|
|
51
|
+
}
|
|
52
|
+
const result = {};
|
|
53
|
+
for (let i = 0; i < type_def.fields.length; i++) {
|
|
54
|
+
const field = type_def.fields[i];
|
|
55
|
+
const value = field_values[i];
|
|
56
|
+
try {
|
|
57
|
+
(0, xvm_serializer_1.createVMParameter)(value, field.type);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
throw new Error(`Invalid value for field '${field.name}' (position ${i}) of struct '${type_name}': ${error}`);
|
|
61
|
+
}
|
|
62
|
+
result[field.name] = value;
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Helper to create enum values with positional arguments
|
|
68
|
+
* Validates field types immediately
|
|
69
|
+
* @param type_name - Name of the enum type
|
|
70
|
+
* @param variant_name - Name of the variant
|
|
71
|
+
* @param field_values - Field values in the order defined in ABI
|
|
72
|
+
*/
|
|
73
|
+
enum(type_name, variant_name, ...field_values) {
|
|
74
|
+
const type_def = this.abi.internal_types?.find(t => t.name === type_name && t.kind === 'enum');
|
|
75
|
+
if (!type_def || !type_def.variants) {
|
|
76
|
+
throw new Error(`Enum type '${type_name}' not found in contract ABI`);
|
|
77
|
+
}
|
|
78
|
+
const variant = type_def.variants.find(v => v.name === variant_name);
|
|
79
|
+
if (!variant) {
|
|
80
|
+
const available = type_def.variants.map(v => v.name).join(', ');
|
|
81
|
+
throw new Error(`Unknown variant '${variant_name}' for enum '${type_name}'. ` +
|
|
82
|
+
`Available variants: ${available}`);
|
|
83
|
+
}
|
|
84
|
+
if (field_values.length !== variant.fields.length) {
|
|
85
|
+
throw new Error(`Variant '${variant_name}' of enum '${type_name}' expects ${variant.fields.length} fields ` +
|
|
86
|
+
`(${variant.fields.map(f => f.name).join(', ')}), ` +
|
|
87
|
+
`but got ${field_values.length}`);
|
|
88
|
+
}
|
|
89
|
+
const result = { type: variant_name };
|
|
90
|
+
for (let i = 0; i < variant.fields.length; i++) {
|
|
91
|
+
const field = variant.fields[i];
|
|
92
|
+
const value = field_values[i];
|
|
93
|
+
try {
|
|
94
|
+
(0, xvm_serializer_1.createVMParameter)(value, field.type);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
throw new Error(`Invalid value for field '${field.name}' (position ${i}) of variant '${variant_name}' in enum '${type_name}': ${error}`);
|
|
49
98
|
}
|
|
99
|
+
result[field.name] = value;
|
|
50
100
|
}
|
|
101
|
+
return result;
|
|
51
102
|
}
|
|
52
103
|
/**
|
|
53
104
|
* Creates a dynamic method on the contract instance
|
|
54
105
|
*/
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
// Create a method that properly binds 'this'
|
|
106
|
+
create_dynamic_method(entry) {
|
|
107
|
+
const method_name = entry.name;
|
|
58
108
|
const method = (params) => {
|
|
59
|
-
return this.invoke(
|
|
109
|
+
return this.invoke(method_name, params);
|
|
60
110
|
};
|
|
61
|
-
|
|
62
|
-
this[methodName] = method;
|
|
111
|
+
this[method_name] = method;
|
|
63
112
|
}
|
|
64
113
|
/**
|
|
65
114
|
* Invoke a contract method by name
|
|
66
|
-
* @param
|
|
115
|
+
* @param method_name - Name of the method from the ABI
|
|
67
116
|
* @param params - Parameters for the method call
|
|
68
117
|
*/
|
|
69
|
-
invoke(
|
|
70
|
-
const entry = this.methods.get(
|
|
118
|
+
invoke(method_name, params = { permission: "all" }) {
|
|
119
|
+
const entry = this.methods.get(method_name);
|
|
71
120
|
if (!entry) {
|
|
72
|
-
throw new Error(`Method '${
|
|
121
|
+
throw new Error(`Method '${method_name}' not found in contract ABI`);
|
|
73
122
|
}
|
|
74
|
-
|
|
75
|
-
const { maxGas, deposits, ...methodParams } = params;
|
|
76
|
-
// Build parameter list according to ABI
|
|
123
|
+
const { maxGas, deposits, permission, ...method_params } = params;
|
|
77
124
|
const parameters = [];
|
|
78
|
-
for (const
|
|
79
|
-
const value =
|
|
125
|
+
for (const abi_param of entry.params) {
|
|
126
|
+
const value = method_params[abi_param.name];
|
|
80
127
|
if (value === undefined) {
|
|
81
|
-
throw new Error(`Missing required parameter '${
|
|
128
|
+
throw new Error(`Missing required parameter '${abi_param.name}' for method '${method_name}'`);
|
|
82
129
|
}
|
|
83
130
|
try {
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
parameters.push(vmParam);
|
|
131
|
+
const VMParam = (0, xvm_serializer_1.createVMParameter)(value, abi_param.type);
|
|
132
|
+
parameters.push(VMParam);
|
|
87
133
|
}
|
|
88
134
|
catch (error) {
|
|
89
|
-
throw new Error(`Invalid parameter '${
|
|
135
|
+
throw new Error(`Invalid parameter '${abi_param.name}' for method '${method_name}': ${error}`);
|
|
90
136
|
}
|
|
91
137
|
}
|
|
92
|
-
|
|
93
|
-
const invocationParams = {
|
|
138
|
+
const invocation_params = {
|
|
94
139
|
contract: this.address,
|
|
95
|
-
|
|
140
|
+
chunk_id: entry.chunk_id,
|
|
96
141
|
parameters,
|
|
97
|
-
|
|
142
|
+
permission,
|
|
143
|
+
maxGas: maxGas || 50000000
|
|
98
144
|
};
|
|
99
145
|
if (deposits && Object.keys(deposits).length > 0) {
|
|
100
|
-
|
|
146
|
+
invocation_params.deposits = deposits;
|
|
101
147
|
}
|
|
102
|
-
return (0, xvm_serializer_1.createContractInvocation)(
|
|
148
|
+
return (0, xvm_serializer_1.createContractInvocation)(invocation_params);
|
|
103
149
|
}
|
|
104
150
|
/**
|
|
105
151
|
* Get list of available methods
|
|
106
152
|
*/
|
|
107
|
-
|
|
153
|
+
get_methods() {
|
|
108
154
|
return Array.from(this.methods.keys());
|
|
109
155
|
}
|
|
110
156
|
/**
|
|
111
157
|
* Get method signature information
|
|
112
158
|
*/
|
|
113
|
-
|
|
114
|
-
return this.methods.get(
|
|
159
|
+
get_method_signature(method_name) {
|
|
160
|
+
return this.methods.get(method_name);
|
|
115
161
|
}
|
|
116
162
|
/**
|
|
117
163
|
* Validate parameters for a method without creating the transaction
|
|
118
164
|
*/
|
|
119
|
-
|
|
120
|
-
const entry = this.methods.get(
|
|
165
|
+
validate_params(method_name, params) {
|
|
166
|
+
const entry = this.methods.get(method_name);
|
|
121
167
|
if (!entry) {
|
|
122
|
-
throw new Error(`Method '${
|
|
168
|
+
throw new Error(`Method '${method_name}' not found in contract ABI`);
|
|
123
169
|
}
|
|
124
|
-
const { deposits, maxGas, ...
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
throw new Error(`Missing required parameter '${abiParam.name}'`);
|
|
170
|
+
const { deposits, maxGas, ...method_params } = params;
|
|
171
|
+
for (const abi_param of entry.params) {
|
|
172
|
+
if (!(abi_param.name in method_params)) {
|
|
173
|
+
throw new Error(`Missing required parameter '${abi_param.name}'`);
|
|
129
174
|
}
|
|
130
|
-
// Validate type
|
|
131
175
|
try {
|
|
132
|
-
|
|
133
|
-
(0, xvm_serializer_1.createVMParameter)(methodParams[abiParam.name], normalizedType, true);
|
|
176
|
+
(0, xvm_serializer_1.createVMParameter)(method_params[abi_param.name], abi_param.type, true);
|
|
134
177
|
}
|
|
135
178
|
catch (error) {
|
|
136
|
-
throw new Error(`Invalid parameter '${
|
|
179
|
+
throw new Error(`Invalid parameter '${abi_param.name}': ${error}`);
|
|
137
180
|
}
|
|
138
181
|
}
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
console.warn(`Warning: Unexpected parameter '${key}' for method '${methodName}'`);
|
|
182
|
+
const expected_params = new Set(entry.params.map(p => p.name));
|
|
183
|
+
for (const key in method_params) {
|
|
184
|
+
if (!expected_params.has(key)) {
|
|
185
|
+
console.warn(`Warning: Unexpected parameter '${key}' for method '${method_name}'`);
|
|
144
186
|
}
|
|
145
187
|
}
|
|
146
188
|
return true;
|
|
@@ -151,10 +193,10 @@ exports.Contract = Contract;
|
|
|
151
193
|
* Helper function to create a typed contract instance
|
|
152
194
|
* This provides better TypeScript support when the ABI is known at compile time
|
|
153
195
|
*/
|
|
154
|
-
function
|
|
196
|
+
function create_contract(address, abi) {
|
|
155
197
|
return new Contract(address, abi);
|
|
156
198
|
}
|
|
157
|
-
exports.
|
|
199
|
+
exports.create_contract = create_contract;
|
|
158
200
|
/**
|
|
159
201
|
* Factory for creating multiple contracts with the same ABI
|
|
160
202
|
*/
|
|
@@ -166,12 +208,12 @@ class ContractFactory {
|
|
|
166
208
|
* Create a new contract instance at the specified address
|
|
167
209
|
*/
|
|
168
210
|
at(address) {
|
|
169
|
-
return
|
|
211
|
+
return create_contract(address, this.abi);
|
|
170
212
|
}
|
|
171
213
|
/**
|
|
172
214
|
* Get the ABI
|
|
173
215
|
*/
|
|
174
|
-
|
|
216
|
+
get_abi() {
|
|
175
217
|
return this.abi;
|
|
176
218
|
}
|
|
177
219
|
}
|
|
@@ -1,38 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.create_contract_from_json = exports.validate_abi = exports.TypedContractFactory = exports.create_typed_contract = exports.TypedContract = void 0;
|
|
4
4
|
const xvm_serializer_1 = require("./xvm_serializer");
|
|
5
|
-
// Convert ABI type to validator type
|
|
6
|
-
function normalizeType(abiType) {
|
|
7
|
-
const typeMap = {
|
|
8
|
-
'Hash': 'Hash',
|
|
9
|
-
'Address': 'Address',
|
|
10
|
-
'PublicKey': 'PublicKey',
|
|
11
|
-
'Blob': 'Blob',
|
|
12
|
-
'u256': 'u256',
|
|
13
|
-
'u128': 'u128',
|
|
14
|
-
'u64': 'u64',
|
|
15
|
-
'u32': 'u32',
|
|
16
|
-
'u16': 'u16',
|
|
17
|
-
'u8': 'u8',
|
|
18
|
-
'boolean': 'boolean',
|
|
19
|
-
'bool': 'boolean',
|
|
20
|
-
'string': 'string',
|
|
21
|
-
'String': 'string',
|
|
22
|
-
'Boolean': 'boolean',
|
|
23
|
-
'U256': 'u256',
|
|
24
|
-
'U128': 'u128',
|
|
25
|
-
'U64': 'u64',
|
|
26
|
-
'U32': 'u32',
|
|
27
|
-
'U16': 'u16',
|
|
28
|
-
'U8': 'u8'
|
|
29
|
-
};
|
|
30
|
-
const normalized = typeMap[abiType];
|
|
31
|
-
if (!normalized) {
|
|
32
|
-
throw new Error(`Unknown ABI type: ${abiType}`);
|
|
33
|
-
}
|
|
34
|
-
return normalized;
|
|
35
|
-
}
|
|
36
5
|
/**
|
|
37
6
|
* Strongly typed contract class
|
|
38
7
|
*/
|
|
@@ -41,21 +10,17 @@ class TypedContract {
|
|
|
41
10
|
this.address = address;
|
|
42
11
|
this.abi = abi;
|
|
43
12
|
this.methods = new Map();
|
|
44
|
-
|
|
13
|
+
this.register_internal_types();
|
|
45
14
|
for (const entry of abi.data) {
|
|
46
15
|
if (entry.type === 'entry') {
|
|
47
|
-
console.log("new method", entry.name);
|
|
48
16
|
this.methods.set(entry.name, entry);
|
|
49
17
|
}
|
|
50
18
|
}
|
|
51
|
-
// Return a Proxy to handle dynamic method calls
|
|
52
19
|
return new Proxy(this, {
|
|
53
20
|
get(target, prop, receiver) {
|
|
54
|
-
// If it's a known property/method, return it
|
|
55
21
|
if (prop in target) {
|
|
56
22
|
return Reflect.get(target, prop, receiver);
|
|
57
23
|
}
|
|
58
|
-
// If it's a string property that matches a method name, create dynamic method
|
|
59
24
|
if (typeof prop === 'string' && target.methods.has(prop)) {
|
|
60
25
|
return (params) => target.invokeUnsafe(prop, params);
|
|
61
26
|
}
|
|
@@ -63,81 +28,159 @@ class TypedContract {
|
|
|
63
28
|
}
|
|
64
29
|
});
|
|
65
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Register all custom types from ABI
|
|
33
|
+
*/
|
|
34
|
+
register_internal_types() {
|
|
35
|
+
if (!this.abi.internal_types)
|
|
36
|
+
return;
|
|
37
|
+
for (const type_def of this.abi.internal_types) {
|
|
38
|
+
if (type_def.kind === 'enum' && type_def.variants) {
|
|
39
|
+
xvm_serializer_1.typeRegistry.register((0, xvm_serializer_1.defineEnum)(type_def.name, type_def.variants));
|
|
40
|
+
}
|
|
41
|
+
else if (type_def.kind === 'struct' && type_def.fields) {
|
|
42
|
+
xvm_serializer_1.typeRegistry.register((0, xvm_serializer_1.defineStruct)(type_def.name, type_def.fields));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Helper to create struct values with positional arguments
|
|
48
|
+
* Validates field types immediately
|
|
49
|
+
* @param type_name - Name of the struct type
|
|
50
|
+
* @param field_values - Field values in the order defined in ABI
|
|
51
|
+
*/
|
|
52
|
+
struct(type_name, ...field_values) {
|
|
53
|
+
const type_def = this.abi.internal_types?.find(t => t.name === type_name && t.kind === 'struct');
|
|
54
|
+
if (!type_def || !type_def.fields) {
|
|
55
|
+
throw new Error(`Struct type '${type_name}' not found in contract ABI`);
|
|
56
|
+
}
|
|
57
|
+
if (field_values.length !== type_def.fields.length) {
|
|
58
|
+
throw new Error(`Struct '${type_name}' expects ${type_def.fields.length} fields ` +
|
|
59
|
+
`(${type_def.fields.map(f => f.name).join(', ')}), ` +
|
|
60
|
+
`but got ${field_values.length}`);
|
|
61
|
+
}
|
|
62
|
+
const result = {};
|
|
63
|
+
for (let i = 0; i < type_def.fields.length; i++) {
|
|
64
|
+
const field = type_def.fields[i];
|
|
65
|
+
const value = field_values[i];
|
|
66
|
+
try {
|
|
67
|
+
(0, xvm_serializer_1.createVMParameter)(value, field.type);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
throw new Error(`Invalid value for field '${field.name}' (position ${i}) of struct '${type_name}': ${error}`);
|
|
71
|
+
}
|
|
72
|
+
result[field.name] = value;
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Helper to create enum values with positional arguments
|
|
78
|
+
* Validates field types immediately
|
|
79
|
+
* @param type_name - Name of the enum type
|
|
80
|
+
* @param variant_name - Name of the variant
|
|
81
|
+
* @param field_values - Field values in the order defined in ABI
|
|
82
|
+
*/
|
|
83
|
+
enum(type_name, variant_name, ...field_values) {
|
|
84
|
+
const type_def = this.abi.internal_types?.find(t => t.name === type_name && t.kind === 'enum');
|
|
85
|
+
if (!type_def || !type_def.variants) {
|
|
86
|
+
throw new Error(`Enum type '${type_name}' not found in contract ABI`);
|
|
87
|
+
}
|
|
88
|
+
const variant = type_def.variants.find(v => v.name === variant_name);
|
|
89
|
+
if (!variant) {
|
|
90
|
+
const available = type_def.variants.map(v => v.name).join(', ');
|
|
91
|
+
throw new Error(`Unknown variant '${variant_name}' for enum '${type_name}'. ` +
|
|
92
|
+
`Available variants: ${available}`);
|
|
93
|
+
}
|
|
94
|
+
if (field_values.length !== variant.fields.length) {
|
|
95
|
+
throw new Error(`Variant '${variant_name}' of enum '${type_name}' expects ${variant.fields.length} fields ` +
|
|
96
|
+
`(${variant.fields.map(f => f.name).join(', ')}), ` +
|
|
97
|
+
`but got ${field_values.length}`);
|
|
98
|
+
}
|
|
99
|
+
const result = { type: variant_name };
|
|
100
|
+
for (let i = 0; i < variant.fields.length; i++) {
|
|
101
|
+
const field = variant.fields[i];
|
|
102
|
+
const value = field_values[i];
|
|
103
|
+
try {
|
|
104
|
+
(0, xvm_serializer_1.createVMParameter)(value, field.type);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
throw new Error(`Invalid value for field '${field.name}' (position ${i}) of variant '${variant_name}' in enum '${type_name}': ${error}`);
|
|
108
|
+
}
|
|
109
|
+
result[field.name] = value;
|
|
110
|
+
}
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
66
113
|
/**
|
|
67
114
|
* Internal method to invoke contract functions
|
|
68
115
|
*/
|
|
69
|
-
invokeUnsafe(
|
|
70
|
-
const entry = this.methods.get(
|
|
116
|
+
invokeUnsafe(method_name, params = {}) {
|
|
117
|
+
const entry = this.methods.get(method_name);
|
|
71
118
|
if (!entry) {
|
|
72
|
-
throw new Error(`Method '${
|
|
119
|
+
throw new Error(`Method '${method_name}' not found in contract ABI`);
|
|
73
120
|
}
|
|
74
|
-
|
|
75
|
-
const { maxGas, deposits, ...methodParams } = params;
|
|
76
|
-
// Build parameter list according to ABI
|
|
121
|
+
const { maxGas, deposits, permission, ...method_params } = params;
|
|
77
122
|
const parameters = [];
|
|
78
|
-
for (const
|
|
79
|
-
const value =
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
methodParams[abiParam.name] = abiParam.default;
|
|
123
|
+
for (const abi_param of entry.params) {
|
|
124
|
+
const value = method_params[abi_param.name];
|
|
125
|
+
if (value === undefined && !abi_param.optional) {
|
|
126
|
+
if (abi_param.default !== undefined) {
|
|
127
|
+
method_params[abi_param.name] = abi_param.default;
|
|
84
128
|
}
|
|
85
129
|
else {
|
|
86
|
-
throw new Error(`Missing required parameter '${
|
|
130
|
+
throw new Error(`Missing required parameter '${abi_param.name}' for method '${method_name}'`);
|
|
87
131
|
}
|
|
88
132
|
}
|
|
89
133
|
if (value !== undefined) {
|
|
90
134
|
try {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
parameters.push(vmParam);
|
|
135
|
+
const VMParam = (0, xvm_serializer_1.createVMParameter)(value, abi_param.type);
|
|
136
|
+
parameters.push(VMParam);
|
|
94
137
|
}
|
|
95
138
|
catch (error) {
|
|
96
|
-
throw new Error(`Invalid parameter '${
|
|
139
|
+
throw new Error(`Invalid parameter '${abi_param.name}' for method '${method_name}': ${error}`);
|
|
97
140
|
}
|
|
98
141
|
}
|
|
99
142
|
}
|
|
100
|
-
|
|
101
|
-
const invocationParams = {
|
|
143
|
+
const invocation_params = {
|
|
102
144
|
contract: this.address,
|
|
103
|
-
|
|
145
|
+
chunk_id: entry.chunk_id,
|
|
104
146
|
parameters,
|
|
105
|
-
|
|
147
|
+
permission,
|
|
148
|
+
maxGas: maxGas || 50000000
|
|
106
149
|
};
|
|
107
150
|
if (deposits && Object.keys(deposits).length > 0) {
|
|
108
|
-
|
|
151
|
+
invocation_params.deposits = deposits;
|
|
109
152
|
}
|
|
110
|
-
return (0, xvm_serializer_1.createContractInvocation)(
|
|
153
|
+
return (0, xvm_serializer_1.createContractInvocation)(invocation_params);
|
|
111
154
|
}
|
|
112
155
|
/**
|
|
113
156
|
* Type-safe invoke method
|
|
114
157
|
*/
|
|
115
|
-
invoke(
|
|
116
|
-
return this.invokeUnsafe(
|
|
158
|
+
invoke(method_name, params) {
|
|
159
|
+
return this.invokeUnsafe(method_name, params);
|
|
117
160
|
}
|
|
118
161
|
/**
|
|
119
162
|
* Get list of available methods
|
|
120
163
|
*/
|
|
121
|
-
|
|
164
|
+
get_methods() {
|
|
122
165
|
return Array.from(this.methods.keys());
|
|
123
166
|
}
|
|
124
167
|
/**
|
|
125
168
|
* Get method signature information
|
|
126
169
|
*/
|
|
127
|
-
|
|
128
|
-
return this.methods.get(
|
|
170
|
+
get_method_signature(method_name) {
|
|
171
|
+
return this.methods.get(method_name);
|
|
129
172
|
}
|
|
130
173
|
/**
|
|
131
174
|
* Generate TypeScript interface for the contract
|
|
132
175
|
*/
|
|
133
|
-
|
|
176
|
+
generate_interface() {
|
|
134
177
|
const lines = [
|
|
135
178
|
`interface ${this.constructor.name}Methods {`
|
|
136
179
|
];
|
|
137
180
|
for (const [name, entry] of this.methods) {
|
|
138
181
|
const params = entry.params.map(p => {
|
|
139
182
|
const optional = p.optional ? '?' : '';
|
|
140
|
-
return ` ${p.name}${optional}: ${this.
|
|
183
|
+
return ` ${p.name}${optional}: ${this.get_typescript_type(p.type)};`;
|
|
141
184
|
}).join('\n');
|
|
142
185
|
lines.push(` ${name}(params: {`);
|
|
143
186
|
lines.push(params);
|
|
@@ -149,8 +192,8 @@ class TypedContract {
|
|
|
149
192
|
lines.push('}');
|
|
150
193
|
return lines.join('\n');
|
|
151
194
|
}
|
|
152
|
-
|
|
153
|
-
const
|
|
195
|
+
get_typescript_type(abi_type) {
|
|
196
|
+
const type_map = {
|
|
154
197
|
'Hash': 'string',
|
|
155
198
|
'Address': 'string',
|
|
156
199
|
'PublicKey': 'string',
|
|
@@ -173,54 +216,57 @@ class TypedContract {
|
|
|
173
216
|
'U8': 'number',
|
|
174
217
|
'u8': 'number'
|
|
175
218
|
};
|
|
176
|
-
return
|
|
219
|
+
return type_map[abi_type] || 'any';
|
|
177
220
|
}
|
|
178
221
|
}
|
|
179
222
|
exports.TypedContract = TypedContract;
|
|
180
223
|
/**
|
|
181
224
|
* Create a typed contract instance with full TypeScript support
|
|
182
225
|
*/
|
|
183
|
-
function
|
|
226
|
+
function create_typed_contract(address, abi) {
|
|
184
227
|
return new TypedContract(address, abi);
|
|
185
228
|
}
|
|
186
|
-
exports.
|
|
229
|
+
exports.create_typed_contract = create_typed_contract;
|
|
187
230
|
/**
|
|
188
231
|
* Contract factory with strong typing
|
|
189
232
|
*/
|
|
190
233
|
class TypedContractFactory {
|
|
191
|
-
constructor(abi,
|
|
234
|
+
constructor(abi, contract_name = 'Contract') {
|
|
192
235
|
this.abi = abi;
|
|
193
|
-
this.
|
|
236
|
+
this.contract_name = contract_name;
|
|
194
237
|
}
|
|
195
238
|
/**
|
|
196
239
|
* Create a new contract instance at the specified address
|
|
197
240
|
*/
|
|
198
241
|
at(address) {
|
|
199
|
-
return
|
|
242
|
+
return create_typed_contract(address, this.abi);
|
|
200
243
|
}
|
|
201
244
|
/**
|
|
202
245
|
* Get the ABI
|
|
203
246
|
*/
|
|
204
|
-
|
|
247
|
+
get_abi() {
|
|
205
248
|
return this.abi;
|
|
206
249
|
}
|
|
207
250
|
/**
|
|
208
251
|
* Generate TypeScript definitions for this contract
|
|
209
252
|
*/
|
|
210
|
-
|
|
253
|
+
generate_type_definitions() {
|
|
211
254
|
const contract = new TypedContract('0x0', this.abi);
|
|
212
|
-
return contract.
|
|
255
|
+
return contract.generate_interface();
|
|
213
256
|
}
|
|
214
257
|
}
|
|
215
258
|
exports.TypedContractFactory = TypedContractFactory;
|
|
216
259
|
/**
|
|
217
260
|
* Utility to validate ABI structure
|
|
218
261
|
*/
|
|
219
|
-
function
|
|
220
|
-
if (!
|
|
262
|
+
function validate_abi(abi) {
|
|
263
|
+
if (!abi || typeof abi !== 'object') {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
if (!Array.isArray(abi.data)) {
|
|
221
267
|
return false;
|
|
222
268
|
}
|
|
223
|
-
for (const entry of abi) {
|
|
269
|
+
for (const entry of abi.data) {
|
|
224
270
|
if (typeof entry !== 'object' || !entry) {
|
|
225
271
|
return false;
|
|
226
272
|
}
|
|
@@ -233,7 +279,7 @@ function validateABI(abi) {
|
|
|
233
279
|
if (!Array.isArray(entry.params)) {
|
|
234
280
|
return false;
|
|
235
281
|
}
|
|
236
|
-
if (entry.type !== 'entry'
|
|
282
|
+
if (entry.type !== 'entry') {
|
|
237
283
|
return false;
|
|
238
284
|
}
|
|
239
285
|
for (const param of entry.params) {
|
|
@@ -244,16 +290,16 @@ function validateABI(abi) {
|
|
|
244
290
|
}
|
|
245
291
|
return true;
|
|
246
292
|
}
|
|
247
|
-
exports.
|
|
293
|
+
exports.validate_abi = validate_abi;
|
|
248
294
|
/**
|
|
249
295
|
* Helper to create a contract from JSON ABI
|
|
250
296
|
*/
|
|
251
|
-
async function
|
|
252
|
-
const response = await fetch(
|
|
297
|
+
async function create_contract_from_json(address, abi_path) {
|
|
298
|
+
const response = await fetch(abi_path);
|
|
253
299
|
const abi = await response.json();
|
|
254
|
-
if (!
|
|
300
|
+
if (!validate_abi(abi)) {
|
|
255
301
|
throw new Error('Invalid ABI structure');
|
|
256
302
|
}
|
|
257
|
-
return
|
|
303
|
+
return create_typed_contract(address, abi);
|
|
258
304
|
}
|
|
259
|
-
exports.
|
|
305
|
+
exports.create_contract_from_json = create_contract_from_json;
|