@alephium/web3 2.0.0-rc.2 → 2.0.0-rc.3
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/alephium-web3.min.js +1 -1
- package/dist/alephium-web3.min.js.map +1 -1
- package/dist/src/api/api-alephium.d.ts +7 -1
- package/dist/src/api/api-alephium.js +1 -1
- package/dist/src/api/types.d.ts +1 -0
- package/dist/src/api/types.js +24 -1
- package/dist/src/contract/contract.d.ts +2 -0
- package/dist/src/contract/contract.js +45 -3
- package/dist/src/contract/ralph.js +23 -0
- package/dist/src/signer/tx-builder.js +2 -1
- package/dist/src/signer/types.d.ts +8 -2
- package/dist/src/signer/types.js +14 -3
- package/package.json +2 -2
- package/src/api/api-alephium.ts +7 -1
- package/src/api/types.ts +20 -0
- package/src/contract/contract.ts +54 -5
- package/src/contract/ralph.ts +37 -1
- package/src/signer/tx-builder.ts +2 -1
- package/src/signer/types.ts +17 -4
|
@@ -250,6 +250,8 @@ export interface BuildExecuteScriptTx {
|
|
|
250
250
|
group?: number;
|
|
251
251
|
/** @format double */
|
|
252
252
|
gasEstimationMultiplier?: number;
|
|
253
|
+
/** @format uint256 */
|
|
254
|
+
dustAmount?: string;
|
|
253
255
|
}
|
|
254
256
|
/** BuildExecuteScriptTxResult */
|
|
255
257
|
export type BuildExecuteScriptTxResult = BuildGrouplessExecuteScriptTxResult | BuildSimpleExecuteScriptTxResult;
|
|
@@ -958,6 +960,8 @@ export interface RichAssetInput {
|
|
|
958
960
|
/** @format address */
|
|
959
961
|
address: string;
|
|
960
962
|
tokens: Token[];
|
|
963
|
+
/** @format 32-byte-hash */
|
|
964
|
+
outputRefTxId: string;
|
|
961
965
|
}
|
|
962
966
|
/** RichBlockAndEvents */
|
|
963
967
|
export interface RichBlockAndEvents {
|
|
@@ -1004,6 +1008,8 @@ export interface RichContractInput {
|
|
|
1004
1008
|
/** @format address */
|
|
1005
1009
|
address: string;
|
|
1006
1010
|
tokens: Token[];
|
|
1011
|
+
/** @format 32-byte-hash */
|
|
1012
|
+
outputRefTxId: string;
|
|
1007
1013
|
}
|
|
1008
1014
|
/** RichTransaction */
|
|
1009
1015
|
export interface RichTransaction {
|
|
@@ -1421,7 +1427,7 @@ export declare class HttpClient<SecurityDataType = unknown> {
|
|
|
1421
1427
|
}
|
|
1422
1428
|
/**
|
|
1423
1429
|
* @title Alephium API
|
|
1424
|
-
* @version
|
|
1430
|
+
* @version 4.0.0
|
|
1425
1431
|
* @baseUrl ../
|
|
1426
1432
|
*/
|
|
1427
1433
|
export declare class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDataType> {
|
package/dist/src/api/types.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export declare function toApiAddress(v0: Val): string;
|
|
|
22
22
|
export declare function toApiArray(tpe: string, v: Val): node.Val;
|
|
23
23
|
export declare function toApiVal(v: Val, tpe: string): node.Val;
|
|
24
24
|
export declare function fromApiPrimitiveVal(value: node.Val, tpe: string, systemEvent?: boolean): Val;
|
|
25
|
+
export declare function decodeTupleType(tpe: string): string[];
|
|
25
26
|
export declare function decodeArrayType(tpe: string): [string, number];
|
|
26
27
|
export declare function getDefaultPrimitiveValue(tpe: string): Val;
|
|
27
28
|
export interface ApiRequestArguments {
|
package/dist/src/api/types.js
CHANGED
|
@@ -17,7 +17,7 @@ You should have received a copy of the GNU Lesser General Public License
|
|
|
17
17
|
along with the library. If not, see <http://www.gnu.org/licenses/>.
|
|
18
18
|
*/
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.StdInterfaceIds = exports.request = exports.requestWithLog = exports.forwardRequests = exports.getDefaultPrimitiveValue = exports.decodeArrayType = exports.fromApiPrimitiveVal = exports.toApiVal = exports.toApiArray = exports.toApiAddress = exports.toApiByteVec = exports.fromApiNumber256 = exports.toApiNumber256Optional = exports.toApiNumber256 = exports.toApiBoolean = exports.fromApiTokens = exports.fromApiToken = exports.toApiTokens = exports.toApiToken = exports.PrimitiveTypes = void 0;
|
|
20
|
+
exports.StdInterfaceIds = exports.request = exports.requestWithLog = exports.forwardRequests = exports.getDefaultPrimitiveValue = exports.decodeArrayType = exports.decodeTupleType = exports.fromApiPrimitiveVal = exports.toApiVal = exports.toApiArray = exports.toApiAddress = exports.toApiByteVec = exports.fromApiNumber256 = exports.toApiNumber256Optional = exports.toApiNumber256 = exports.toApiBoolean = exports.fromApiTokens = exports.fromApiToken = exports.toApiTokens = exports.toApiToken = exports.PrimitiveTypes = void 0;
|
|
21
21
|
const address_1 = require("../address");
|
|
22
22
|
const constants_1 = require("../constants");
|
|
23
23
|
const debug_1 = require("../debug");
|
|
@@ -159,6 +159,29 @@ function fromApiPrimitiveVal(value, tpe, systemEvent = false) {
|
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
exports.fromApiPrimitiveVal = fromApiPrimitiveVal;
|
|
162
|
+
function decodeTupleType(tpe) {
|
|
163
|
+
const str = tpe.slice(1, -1);
|
|
164
|
+
const types = [];
|
|
165
|
+
let current = '';
|
|
166
|
+
let depth = 0;
|
|
167
|
+
for (const char of str) {
|
|
168
|
+
if (char === ',' && depth === 0) {
|
|
169
|
+
types.push(current);
|
|
170
|
+
current = '';
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
if (char === '(')
|
|
174
|
+
depth++;
|
|
175
|
+
if (char === ')')
|
|
176
|
+
depth--;
|
|
177
|
+
current += char;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (current !== '')
|
|
181
|
+
types.push(current);
|
|
182
|
+
return types;
|
|
183
|
+
}
|
|
184
|
+
exports.decodeTupleType = decodeTupleType;
|
|
162
185
|
function decodeArrayType(tpe) {
|
|
163
186
|
const semiColonIndex = tpe.lastIndexOf(';');
|
|
164
187
|
if (semiColonIndex === -1) {
|
|
@@ -216,6 +216,7 @@ export interface ExecuteScriptParams<P extends Fields = Fields> {
|
|
|
216
216
|
tokens?: Token[];
|
|
217
217
|
gasAmount?: number;
|
|
218
218
|
gasPrice?: Number256;
|
|
219
|
+
dustAmount?: Number256;
|
|
219
220
|
}
|
|
220
221
|
export interface ExecuteScriptResult {
|
|
221
222
|
groupIndex: number;
|
|
@@ -259,6 +260,7 @@ export interface SignExecuteContractMethodParams<T extends Arguments = Arguments
|
|
|
259
260
|
tokens?: Token[];
|
|
260
261
|
gasAmount?: number;
|
|
261
262
|
gasPrice?: Number256;
|
|
263
|
+
dustAmount?: Number256;
|
|
262
264
|
}
|
|
263
265
|
export declare const CreateContractEventAddresses: string[];
|
|
264
266
|
export declare const DestroyContractEventAddresses: string[];
|
|
@@ -43,6 +43,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
43
43
|
exports.getContractCodeByCodeHash = exports.getTokenIdFromUnsignedTx = exports.getContractIdFromUnsignedTx = exports.getContractEventsCurrentCount = exports.multicallMethods = exports.signExecuteMethod = exports.callMethod = exports.subscribeContractEvents = exports.subscribeContractEvent = exports.decodeEvent = exports.subscribeContractDestroyedEvent = exports.subscribeContractCreatedEvent = exports.fetchContractState = exports.ContractInstance = exports.getMapItem = exports.RalphMap = exports.printDebugMessagesFromTx = exports.getDebugMessagesFromTx = exports.testMethod = exports.extractMapsFromApiResult = exports.addStdIdToFields = exports.subscribeEventsFromContract = exports.decodeContractDestroyedEvent = exports.decodeContractCreatedEvent = exports.DestroyContractEventAddresses = exports.CreateContractEventAddresses = exports.ExecutableScript = exports.ContractFactory = exports.randomTxId = exports.fromApiEventFields = exports.fromApiArray = exports.getDefaultValue = exports.fromApiFields = exports.Script = exports.Contract = exports.Artifact = exports.Struct = exports.DEFAULT_COMPILER_OPTIONS = exports.DEFAULT_NODE_COMPILER_OPTIONS = exports.StdIdFieldName = void 0;
|
|
44
44
|
const fs_1 = require("fs");
|
|
45
45
|
const api_1 = require("../api");
|
|
46
|
+
const signer_1 = require("../signer");
|
|
46
47
|
const ralph = __importStar(require("./ralph"));
|
|
47
48
|
const utils_1 = require("../utils");
|
|
48
49
|
const address_1 = require("../address");
|
|
@@ -53,6 +54,7 @@ const blake = __importStar(require("blakejs"));
|
|
|
53
54
|
const debug_1 = require("../debug");
|
|
54
55
|
const codec_1 = require("../codec");
|
|
55
56
|
const error_1 = require("../error");
|
|
57
|
+
const script_codec_1 = require("../codec/script-codec");
|
|
56
58
|
const crypto = new utils_1.WebCrypto();
|
|
57
59
|
exports.StdIdFieldName = '__stdInterfaceId';
|
|
58
60
|
exports.DEFAULT_NODE_COMPILER_OPTIONS = {
|
|
@@ -522,14 +524,18 @@ class Script extends Artifact {
|
|
|
522
524
|
}
|
|
523
525
|
async txParamsForExecution(params) {
|
|
524
526
|
const selectedAccount = await params.signer.getSelectedAccount();
|
|
527
|
+
const bytecode = this.buildByteCodeToDeploy(params.initialFields ?? {});
|
|
528
|
+
const group = getGroupFromTxScript(bytecode, selectedAccount);
|
|
525
529
|
const signerParams = {
|
|
526
530
|
signerAddress: selectedAccount.address,
|
|
527
531
|
signerKeyType: selectedAccount.keyType,
|
|
528
|
-
bytecode
|
|
532
|
+
bytecode,
|
|
529
533
|
attoAlphAmount: params.attoAlphAmount,
|
|
530
534
|
tokens: params.tokens,
|
|
531
535
|
gasAmount: params.gasAmount,
|
|
532
|
-
gasPrice: params.gasPrice
|
|
536
|
+
gasPrice: params.gasPrice,
|
|
537
|
+
group,
|
|
538
|
+
dustAmount: params.dustAmount
|
|
533
539
|
};
|
|
534
540
|
return signerParams;
|
|
535
541
|
}
|
|
@@ -543,6 +549,33 @@ class Script extends Artifact {
|
|
|
543
549
|
}
|
|
544
550
|
}
|
|
545
551
|
exports.Script = Script;
|
|
552
|
+
function getGroupFromTxScript(bytecode, account) {
|
|
553
|
+
if ((0, signer_1.isGroupedAccount)(account))
|
|
554
|
+
return account.group;
|
|
555
|
+
const script = script_codec_1.scriptCodec.decode((0, utils_1.hexToBinUnsafe)(bytecode));
|
|
556
|
+
const instrs = script.methods.flatMap((method) => method.instrs);
|
|
557
|
+
for (let index = 0; index < instrs.length - 1; index += 1) {
|
|
558
|
+
const instr = instrs[`${index}`];
|
|
559
|
+
const nextInstr = instrs[index + 1];
|
|
560
|
+
if (instr.name === 'BytesConst' &&
|
|
561
|
+
instr.value.length === 32 &&
|
|
562
|
+
(nextInstr.name === 'CallExternal' || nextInstr.name === 'CallExternalBySelector')) {
|
|
563
|
+
const groupIndex = instr.value[instr.value.length - 1];
|
|
564
|
+
if (groupIndex >= 0 && groupIndex < constants_1.TOTAL_NUMBER_OF_GROUPS) {
|
|
565
|
+
return groupIndex;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
for (const instr of instrs) {
|
|
570
|
+
if (instr.name === 'BytesConst' && instr.value.length === 32) {
|
|
571
|
+
const groupIndex = instr.value[instr.value.length - 1];
|
|
572
|
+
if (groupIndex >= 0 && groupIndex < constants_1.TOTAL_NUMBER_OF_GROUPS) {
|
|
573
|
+
return groupIndex;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
return (0, address_1.groupOfAddress)(account.address);
|
|
578
|
+
}
|
|
546
579
|
function fromApiFields(immFields, mutFields, fieldsSig, structs) {
|
|
547
580
|
let [immIndex, mutIndex] = [0, 0];
|
|
548
581
|
const func = (type, isMutable) => {
|
|
@@ -562,6 +595,13 @@ function buildVal(isMutable, type, structs, func) {
|
|
|
562
595
|
const [baseType, size] = (0, api_1.decodeArrayType)(type);
|
|
563
596
|
return Array.from(Array(size).keys()).map(() => buildVal(isMutable, baseType, structs, func));
|
|
564
597
|
}
|
|
598
|
+
if (type.startsWith('(')) {
|
|
599
|
+
const tuple = (0, api_1.decodeTupleType)(type);
|
|
600
|
+
return tuple.reduce((acc, fieldType) => {
|
|
601
|
+
acc.push(buildVal(isMutable, fieldType, structs, func));
|
|
602
|
+
return acc;
|
|
603
|
+
}, []);
|
|
604
|
+
}
|
|
565
605
|
const struct = structs.find((s) => s.name === type);
|
|
566
606
|
if (struct !== undefined) {
|
|
567
607
|
return struct.fieldNames.reduce((acc, name, index) => {
|
|
@@ -1265,7 +1305,9 @@ async function signExecuteMethod(contract, instance, methodName, params) {
|
|
|
1265
1305
|
attoAlphAmount: params.attoAlphAmount,
|
|
1266
1306
|
tokens: params.tokens,
|
|
1267
1307
|
gasAmount: params.gasAmount,
|
|
1268
|
-
gasPrice: params.gasPrice
|
|
1308
|
+
gasPrice: params.gasPrice,
|
|
1309
|
+
group: instance.groupIndex,
|
|
1310
|
+
dustAmount: params.dustAmount
|
|
1269
1311
|
};
|
|
1270
1312
|
const result = (await signer.signAndSubmitExecuteScriptTx(signerParams));
|
|
1271
1313
|
if ((0, debug_1.isContractDebugMessageEnabled)() && isDevnet) {
|
|
@@ -178,6 +178,16 @@ function calcFieldSize(type, isMutable, structs) {
|
|
|
178
178
|
const base = calcFieldSize(baseType, isMutable, structs);
|
|
179
179
|
return { immFields: base.immFields * size, mutFields: base.mutFields * size };
|
|
180
180
|
}
|
|
181
|
+
if (type.startsWith('(')) {
|
|
182
|
+
const tuple = (0, api_1.decodeTupleType)(type);
|
|
183
|
+
return tuple.reduce((acc, fieldType) => {
|
|
184
|
+
const subFieldSize = calcFieldSize(fieldType, isMutable, structs);
|
|
185
|
+
return {
|
|
186
|
+
immFields: acc.immFields + subFieldSize.immFields,
|
|
187
|
+
mutFields: acc.mutFields + subFieldSize.mutFields
|
|
188
|
+
};
|
|
189
|
+
}, { immFields: 0, mutFields: 0 });
|
|
190
|
+
}
|
|
181
191
|
return isMutable ? { immFields: 0, mutFields: 1 } : { immFields: 1, mutFields: 0 };
|
|
182
192
|
}
|
|
183
193
|
exports.calcFieldSize = calcFieldSize;
|
|
@@ -251,6 +261,10 @@ function typeLength(typ, structs) {
|
|
|
251
261
|
const [baseType, size] = (0, api_1.decodeArrayType)(typ);
|
|
252
262
|
return size * typeLength(baseType, structs);
|
|
253
263
|
}
|
|
264
|
+
if (typ.startsWith('(')) {
|
|
265
|
+
const tuple = (0, api_1.decodeTupleType)(typ);
|
|
266
|
+
return tuple.reduce((acc, fieldType) => acc + typeLength(fieldType, structs), 0);
|
|
267
|
+
}
|
|
254
268
|
const struct = structs.find((s) => s.name === typ);
|
|
255
269
|
if (struct !== undefined) {
|
|
256
270
|
return struct.fieldTypes.reduce((acc, fieldType) => acc + typeLength(fieldType, structs), 0);
|
|
@@ -277,6 +291,15 @@ function flattenField(isMutable, name, type, value, structs) {
|
|
|
277
291
|
return flattenField(isMutable, `${name}[${index}]`, baseType, item, structs);
|
|
278
292
|
});
|
|
279
293
|
}
|
|
294
|
+
if (Array.isArray(value) && type.startsWith('(')) {
|
|
295
|
+
const tuple = (0, api_1.decodeTupleType)(type);
|
|
296
|
+
if (value.length !== tuple.length) {
|
|
297
|
+
throw Error(`Invalid tuple length, expected ${tuple.length}, got ${value.length}`);
|
|
298
|
+
}
|
|
299
|
+
return tuple.flatMap((fieldType, index) => {
|
|
300
|
+
return flattenField(isMutable, `${name}._${index}`, fieldType, value[`${index}`], structs);
|
|
301
|
+
});
|
|
302
|
+
}
|
|
280
303
|
const struct = structs.find((s) => s.name === type);
|
|
281
304
|
if (struct !== undefined) {
|
|
282
305
|
if (typeof value !== 'object') {
|
|
@@ -149,13 +149,14 @@ class TransactionBuilder {
|
|
|
149
149
|
}
|
|
150
150
|
buildExecuteScriptTxParams(params, publicKey) {
|
|
151
151
|
TransactionBuilder.validatePublicKey(params, publicKey, params.signerKeyType);
|
|
152
|
-
const { attoAlphAmount, tokens, gasPrice, ...rest } = params;
|
|
152
|
+
const { attoAlphAmount, tokens, gasPrice, dustAmount, ...rest } = params;
|
|
153
153
|
return {
|
|
154
154
|
fromPublicKey: publicKey,
|
|
155
155
|
fromPublicKeyType: params.signerKeyType,
|
|
156
156
|
attoAlphAmount: (0, api_1.toApiNumber256Optional)(attoAlphAmount),
|
|
157
157
|
tokens: (0, api_1.toApiTokens)(tokens),
|
|
158
158
|
gasPrice: (0, api_1.toApiNumber256Optional)(gasPrice),
|
|
159
|
+
dustAmount: (0, api_1.toApiNumber256Optional)(dustAmount),
|
|
159
160
|
...rest
|
|
160
161
|
};
|
|
161
162
|
}
|
|
@@ -11,8 +11,11 @@ export interface Destination {
|
|
|
11
11
|
lockTime?: number;
|
|
12
12
|
message?: string;
|
|
13
13
|
}
|
|
14
|
-
export
|
|
15
|
-
export
|
|
14
|
+
export declare const groupedKeyTypes: readonly ["default", "bip340-schnorr"];
|
|
15
|
+
export declare const grouplessKeyTypes: readonly ["gl-secp256k1", "gl-secp256r1", "gl-ed25519", "gl-webauthn"];
|
|
16
|
+
export declare const keyTypes: readonly ["default", "bip340-schnorr", "gl-secp256k1", "gl-secp256r1", "gl-ed25519", "gl-webauthn"];
|
|
17
|
+
export type GroupedKeyType = (typeof groupedKeyTypes)[number];
|
|
18
|
+
export type GrouplessKeyType = (typeof grouplessKeyTypes)[number];
|
|
16
19
|
export type KeyType = GroupedKeyType | GrouplessKeyType;
|
|
17
20
|
export interface GroupedAccount {
|
|
18
21
|
keyType: GroupedKeyType;
|
|
@@ -26,6 +29,8 @@ export interface GrouplessAccount {
|
|
|
26
29
|
publicKey: string;
|
|
27
30
|
}
|
|
28
31
|
export type Account = GroupedAccount | GrouplessAccount;
|
|
32
|
+
export declare function isGroupedKeyType(keyType: KeyType): keyType is GroupedKeyType;
|
|
33
|
+
export declare function isGrouplessKeyType(keyType: KeyType): keyType is GrouplessKeyType;
|
|
29
34
|
export declare function isGroupedAccount(account: Account): account is GroupedAccount;
|
|
30
35
|
export declare function isGrouplessAccount(account: Account): account is GrouplessAccount;
|
|
31
36
|
export type SignerAddress = {
|
|
@@ -82,6 +87,7 @@ export interface SignExecuteScriptTxParams {
|
|
|
82
87
|
gasPrice?: Number256;
|
|
83
88
|
gasEstimationMultiplier?: number;
|
|
84
89
|
group?: number;
|
|
90
|
+
dustAmount?: Number256;
|
|
85
91
|
}
|
|
86
92
|
export interface SignExecuteScriptTxResult {
|
|
87
93
|
groupIndex: number;
|
package/dist/src/signer/types.js
CHANGED
|
@@ -17,15 +17,26 @@ You should have received a copy of the GNU Lesser General Public License
|
|
|
17
17
|
along with the library. If not, see <http://www.gnu.org/licenses/>.
|
|
18
18
|
*/
|
|
19
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
-
exports.isGrouplessAccount = exports.isGroupedAccount = void 0;
|
|
20
|
+
exports.isGrouplessAccount = exports.isGroupedAccount = exports.isGrouplessKeyType = exports.isGroupedKeyType = exports.keyTypes = exports.grouplessKeyTypes = exports.groupedKeyTypes = void 0;
|
|
21
21
|
const utils_1 = require("../utils");
|
|
22
22
|
utils_1.assertType;
|
|
23
|
+
exports.groupedKeyTypes = ['default', 'bip340-schnorr'];
|
|
24
|
+
exports.grouplessKeyTypes = ['gl-secp256k1', 'gl-secp256r1', 'gl-ed25519', 'gl-webauthn'];
|
|
25
|
+
exports.keyTypes = [...exports.groupedKeyTypes, ...exports.grouplessKeyTypes];
|
|
26
|
+
function isGroupedKeyType(keyType) {
|
|
27
|
+
return keyType === 'default' || keyType === 'bip340-schnorr';
|
|
28
|
+
}
|
|
29
|
+
exports.isGroupedKeyType = isGroupedKeyType;
|
|
30
|
+
function isGrouplessKeyType(keyType) {
|
|
31
|
+
return keyType !== 'default' && keyType !== 'bip340-schnorr';
|
|
32
|
+
}
|
|
33
|
+
exports.isGrouplessKeyType = isGrouplessKeyType;
|
|
23
34
|
function isGroupedAccount(account) {
|
|
24
|
-
return account.keyType
|
|
35
|
+
return isGroupedKeyType(account.keyType);
|
|
25
36
|
}
|
|
26
37
|
exports.isGroupedAccount = isGroupedAccount;
|
|
27
38
|
function isGrouplessAccount(account) {
|
|
28
|
-
return account.keyType
|
|
39
|
+
return isGrouplessKeyType(account.keyType);
|
|
29
40
|
}
|
|
30
41
|
exports.isGrouplessAccount = isGrouplessAccount;
|
|
31
42
|
(0, utils_1.assertType)();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alephium/web3",
|
|
3
|
-
"version": "2.0.0-rc.
|
|
3
|
+
"version": "2.0.0-rc.3",
|
|
4
4
|
"description": "A JS/TS library to interact with the Alephium platform",
|
|
5
5
|
"license": "GPL",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"author": "Alephium dev <dev@alephium.org>",
|
|
35
35
|
"config": {
|
|
36
|
-
"alephium_version": "
|
|
36
|
+
"alephium_version": "4.0.0",
|
|
37
37
|
"explorer_backend_version": "2.3.2"
|
|
38
38
|
},
|
|
39
39
|
"type": "commonjs",
|
package/src/api/api-alephium.ts
CHANGED
|
@@ -292,6 +292,8 @@ export interface BuildExecuteScriptTx {
|
|
|
292
292
|
group?: number
|
|
293
293
|
/** @format double */
|
|
294
294
|
gasEstimationMultiplier?: number
|
|
295
|
+
/** @format uint256 */
|
|
296
|
+
dustAmount?: string
|
|
295
297
|
}
|
|
296
298
|
|
|
297
299
|
/** BuildExecuteScriptTxResult */
|
|
@@ -1085,6 +1087,8 @@ export interface RichAssetInput {
|
|
|
1085
1087
|
/** @format address */
|
|
1086
1088
|
address: string
|
|
1087
1089
|
tokens: Token[]
|
|
1090
|
+
/** @format 32-byte-hash */
|
|
1091
|
+
outputRefTxId: string
|
|
1088
1092
|
}
|
|
1089
1093
|
|
|
1090
1094
|
/** RichBlockAndEvents */
|
|
@@ -1135,6 +1139,8 @@ export interface RichContractInput {
|
|
|
1135
1139
|
/** @format address */
|
|
1136
1140
|
address: string
|
|
1137
1141
|
tokens: Token[]
|
|
1142
|
+
/** @format 32-byte-hash */
|
|
1143
|
+
outputRefTxId: string
|
|
1138
1144
|
}
|
|
1139
1145
|
|
|
1140
1146
|
/** RichTransaction */
|
|
@@ -1754,7 +1760,7 @@ export class HttpClient<SecurityDataType = unknown> {
|
|
|
1754
1760
|
|
|
1755
1761
|
/**
|
|
1756
1762
|
* @title Alephium API
|
|
1757
|
-
* @version
|
|
1763
|
+
* @version 4.0.0
|
|
1758
1764
|
* @baseUrl ../
|
|
1759
1765
|
*/
|
|
1760
1766
|
export class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDataType> {
|
package/src/api/types.ts
CHANGED
|
@@ -160,6 +160,26 @@ export function fromApiPrimitiveVal(value: node.Val, tpe: string, systemEvent =
|
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
export function decodeTupleType(tpe: string): string[] {
|
|
164
|
+
const str = tpe.slice(1, -1)
|
|
165
|
+
const types: string[] = []
|
|
166
|
+
let current = ''
|
|
167
|
+
let depth = 0
|
|
168
|
+
|
|
169
|
+
for (const char of str) {
|
|
170
|
+
if (char === ',' && depth === 0) {
|
|
171
|
+
types.push(current)
|
|
172
|
+
current = ''
|
|
173
|
+
} else {
|
|
174
|
+
if (char === '(') depth++
|
|
175
|
+
if (char === ')') depth--
|
|
176
|
+
current += char
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (current !== '') types.push(current)
|
|
180
|
+
return types
|
|
181
|
+
}
|
|
182
|
+
|
|
163
183
|
export function decodeArrayType(tpe: string): [string, number] {
|
|
164
184
|
const semiColonIndex = tpe.lastIndexOf(';')
|
|
165
185
|
if (semiColonIndex === -1) {
|
package/src/contract/contract.ts
CHANGED
|
@@ -33,7 +33,8 @@ import {
|
|
|
33
33
|
PrimitiveTypes,
|
|
34
34
|
decodeArrayType,
|
|
35
35
|
fromApiPrimitiveVal,
|
|
36
|
-
tryGetCallResult
|
|
36
|
+
tryGetCallResult,
|
|
37
|
+
decodeTupleType
|
|
37
38
|
} from '../api'
|
|
38
39
|
import {
|
|
39
40
|
SignDeployContractTxParams,
|
|
@@ -41,7 +42,9 @@ import {
|
|
|
41
42
|
SignExecuteScriptTxParams,
|
|
42
43
|
SignerProvider,
|
|
43
44
|
Address,
|
|
44
|
-
SignExecuteScriptTxResult
|
|
45
|
+
SignExecuteScriptTxResult,
|
|
46
|
+
Account,
|
|
47
|
+
isGroupedAccount
|
|
45
48
|
} from '../signer'
|
|
46
49
|
import * as ralph from './ralph'
|
|
47
50
|
import {
|
|
@@ -97,6 +100,7 @@ import {
|
|
|
97
100
|
} from '../codec'
|
|
98
101
|
import { TraceableError } from '../error'
|
|
99
102
|
import { SimulationResult } from '../api/api-alephium'
|
|
103
|
+
import { scriptCodec } from '../codec/script-codec'
|
|
100
104
|
|
|
101
105
|
const crypto = new WebCrypto()
|
|
102
106
|
|
|
@@ -794,14 +798,18 @@ export class Script extends Artifact {
|
|
|
794
798
|
|
|
795
799
|
async txParamsForExecution<P extends Fields>(params: ExecuteScriptParams<P>): Promise<SignExecuteScriptTxParams> {
|
|
796
800
|
const selectedAccount = await params.signer.getSelectedAccount()
|
|
801
|
+
const bytecode = this.buildByteCodeToDeploy(params.initialFields ?? {})
|
|
802
|
+
const group = getGroupFromTxScript(bytecode, selectedAccount)
|
|
797
803
|
const signerParams: SignExecuteScriptTxParams = {
|
|
798
804
|
signerAddress: selectedAccount.address,
|
|
799
805
|
signerKeyType: selectedAccount.keyType,
|
|
800
|
-
bytecode
|
|
806
|
+
bytecode,
|
|
801
807
|
attoAlphAmount: params.attoAlphAmount,
|
|
802
808
|
tokens: params.tokens,
|
|
803
809
|
gasAmount: params.gasAmount,
|
|
804
|
-
gasPrice: params.gasPrice
|
|
810
|
+
gasPrice: params.gasPrice,
|
|
811
|
+
group,
|
|
812
|
+
dustAmount: params.dustAmount
|
|
805
813
|
}
|
|
806
814
|
return signerParams
|
|
807
815
|
}
|
|
@@ -815,6 +823,36 @@ export class Script extends Artifact {
|
|
|
815
823
|
}
|
|
816
824
|
}
|
|
817
825
|
|
|
826
|
+
function getGroupFromTxScript(bytecode: string, account: Account): number {
|
|
827
|
+
if (isGroupedAccount(account)) return account.group
|
|
828
|
+
|
|
829
|
+
const script = scriptCodec.decode(hexToBinUnsafe(bytecode))
|
|
830
|
+
const instrs = script.methods.flatMap((method) => method.instrs)
|
|
831
|
+
for (let index = 0; index < instrs.length - 1; index += 1) {
|
|
832
|
+
const instr = instrs[`${index}`]
|
|
833
|
+
const nextInstr = instrs[index + 1]
|
|
834
|
+
if (
|
|
835
|
+
instr.name === 'BytesConst' &&
|
|
836
|
+
instr.value.length === 32 &&
|
|
837
|
+
(nextInstr.name === 'CallExternal' || nextInstr.name === 'CallExternalBySelector')
|
|
838
|
+
) {
|
|
839
|
+
const groupIndex = instr.value[instr.value.length - 1]
|
|
840
|
+
if (groupIndex >= 0 && groupIndex < TOTAL_NUMBER_OF_GROUPS) {
|
|
841
|
+
return groupIndex
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
for (const instr of instrs) {
|
|
846
|
+
if (instr.name === 'BytesConst' && instr.value.length === 32) {
|
|
847
|
+
const groupIndex = instr.value[instr.value.length - 1]
|
|
848
|
+
if (groupIndex >= 0 && groupIndex < TOTAL_NUMBER_OF_GROUPS) {
|
|
849
|
+
return groupIndex
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
return groupOfAddress(account.address)
|
|
854
|
+
}
|
|
855
|
+
|
|
818
856
|
export function fromApiFields(
|
|
819
857
|
immFields: node.Val[],
|
|
820
858
|
mutFields: node.Val[],
|
|
@@ -845,6 +883,13 @@ function buildVal(
|
|
|
845
883
|
const [baseType, size] = decodeArrayType(type)
|
|
846
884
|
return Array.from(Array(size).keys()).map(() => buildVal(isMutable, baseType, structs, func))
|
|
847
885
|
}
|
|
886
|
+
if (type.startsWith('(')) {
|
|
887
|
+
const tuple = decodeTupleType(type)
|
|
888
|
+
return tuple.reduce<Val[]>((acc, fieldType) => {
|
|
889
|
+
acc.push(buildVal(isMutable, fieldType, structs, func))
|
|
890
|
+
return acc
|
|
891
|
+
}, [])
|
|
892
|
+
}
|
|
848
893
|
const struct = structs.find((s) => s.name === type)
|
|
849
894
|
if (struct !== undefined) {
|
|
850
895
|
return struct.fieldNames.reduce((acc, name, index) => {
|
|
@@ -1190,6 +1235,7 @@ export interface ExecuteScriptParams<P extends Fields = Fields> {
|
|
|
1190
1235
|
tokens?: Token[]
|
|
1191
1236
|
gasAmount?: number
|
|
1192
1237
|
gasPrice?: Number256
|
|
1238
|
+
dustAmount?: Number256
|
|
1193
1239
|
}
|
|
1194
1240
|
|
|
1195
1241
|
export interface ExecuteScriptResult {
|
|
@@ -1239,6 +1285,7 @@ export interface SignExecuteContractMethodParams<T extends Arguments = Arguments
|
|
|
1239
1285
|
tokens?: Token[]
|
|
1240
1286
|
gasAmount?: number
|
|
1241
1287
|
gasPrice?: Number256
|
|
1288
|
+
dustAmount?: Number256
|
|
1242
1289
|
}
|
|
1243
1290
|
|
|
1244
1291
|
function specialContractAddress(eventIndex: number, groupIndex: number): string {
|
|
@@ -1963,7 +2010,9 @@ export async function signExecuteMethod<I extends ContractInstance, F extends Fi
|
|
|
1963
2010
|
attoAlphAmount: params.attoAlphAmount,
|
|
1964
2011
|
tokens: params.tokens,
|
|
1965
2012
|
gasAmount: params.gasAmount,
|
|
1966
|
-
gasPrice: params.gasPrice
|
|
2013
|
+
gasPrice: params.gasPrice,
|
|
2014
|
+
group: instance.groupIndex,
|
|
2015
|
+
dustAmount: params.dustAmount
|
|
1967
2016
|
}
|
|
1968
2017
|
|
|
1969
2018
|
const result = (await signer.signAndSubmitExecuteScriptTx(signerParams)) as SignExecuteScriptTxResult
|
package/src/contract/ralph.ts
CHANGED
|
@@ -16,7 +16,16 @@ You should have received a copy of the GNU Lesser General Public License
|
|
|
16
16
|
along with the library. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
Val,
|
|
21
|
+
decodeArrayType,
|
|
22
|
+
toApiAddress,
|
|
23
|
+
toApiBoolean,
|
|
24
|
+
toApiByteVec,
|
|
25
|
+
toApiNumber256,
|
|
26
|
+
PrimitiveTypes,
|
|
27
|
+
decodeTupleType
|
|
28
|
+
} from '../api'
|
|
20
29
|
import { HexString, binToHex, bs58, hexToBinUnsafe, isHexString } from '../utils'
|
|
21
30
|
import { Fields, FieldsSig, Struct } from './contract'
|
|
22
31
|
import {
|
|
@@ -208,6 +217,19 @@ export function calcFieldSize(
|
|
|
208
217
|
const base = calcFieldSize(baseType, isMutable, structs)
|
|
209
218
|
return { immFields: base.immFields * size, mutFields: base.mutFields * size }
|
|
210
219
|
}
|
|
220
|
+
if (type.startsWith('(')) {
|
|
221
|
+
const tuple = decodeTupleType(type)
|
|
222
|
+
return tuple.reduce(
|
|
223
|
+
(acc, fieldType) => {
|
|
224
|
+
const subFieldSize = calcFieldSize(fieldType, isMutable, structs)
|
|
225
|
+
return {
|
|
226
|
+
immFields: acc.immFields + subFieldSize.immFields,
|
|
227
|
+
mutFields: acc.mutFields + subFieldSize.mutFields
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
{ immFields: 0, mutFields: 0 }
|
|
231
|
+
)
|
|
232
|
+
}
|
|
211
233
|
return isMutable ? { immFields: 0, mutFields: 1 } : { immFields: 1, mutFields: 0 }
|
|
212
234
|
}
|
|
213
235
|
|
|
@@ -284,6 +306,11 @@ export function typeLength(typ: string, structs: Struct[]): number {
|
|
|
284
306
|
return size * typeLength(baseType, structs)
|
|
285
307
|
}
|
|
286
308
|
|
|
309
|
+
if (typ.startsWith('(')) {
|
|
310
|
+
const tuple = decodeTupleType(typ)
|
|
311
|
+
return tuple.reduce((acc, fieldType) => acc + typeLength(fieldType, structs), 0)
|
|
312
|
+
}
|
|
313
|
+
|
|
287
314
|
const struct = structs.find((s) => s.name === typ)
|
|
288
315
|
if (struct !== undefined) {
|
|
289
316
|
return struct.fieldTypes.reduce((acc, fieldType) => acc + typeLength(fieldType, structs), 0)
|
|
@@ -323,6 +350,15 @@ function flattenField(
|
|
|
323
350
|
return flattenField(isMutable, `${name}[${index}]`, baseType, item, structs)
|
|
324
351
|
})
|
|
325
352
|
}
|
|
353
|
+
if (Array.isArray(value) && type.startsWith('(')) {
|
|
354
|
+
const tuple = decodeTupleType(type)
|
|
355
|
+
if (value.length !== tuple.length) {
|
|
356
|
+
throw Error(`Invalid tuple length, expected ${tuple.length}, got ${value.length}`)
|
|
357
|
+
}
|
|
358
|
+
return tuple.flatMap((fieldType, index) => {
|
|
359
|
+
return flattenField(isMutable, `${name}._${index}`, fieldType, value[`${index}`], structs)
|
|
360
|
+
})
|
|
361
|
+
}
|
|
326
362
|
const struct = structs.find((s) => s.name === type)
|
|
327
363
|
if (struct !== undefined) {
|
|
328
364
|
if (typeof value !== 'object') {
|
package/src/signer/tx-builder.ts
CHANGED
|
@@ -207,13 +207,14 @@ export abstract class TransactionBuilder {
|
|
|
207
207
|
private buildExecuteScriptTxParams(params: SignExecuteScriptTxParams, publicKey: string): node.BuildExecuteScriptTx {
|
|
208
208
|
TransactionBuilder.validatePublicKey(params, publicKey, params.signerKeyType)
|
|
209
209
|
|
|
210
|
-
const { attoAlphAmount, tokens, gasPrice, ...rest } = params
|
|
210
|
+
const { attoAlphAmount, tokens, gasPrice, dustAmount, ...rest } = params
|
|
211
211
|
return {
|
|
212
212
|
fromPublicKey: publicKey,
|
|
213
213
|
fromPublicKeyType: params.signerKeyType,
|
|
214
214
|
attoAlphAmount: toApiNumber256Optional(attoAlphAmount),
|
|
215
215
|
tokens: toApiTokens(tokens),
|
|
216
216
|
gasPrice: toApiNumber256Optional(gasPrice),
|
|
217
|
+
dustAmount: toApiNumber256Optional(dustAmount),
|
|
217
218
|
...rest
|
|
218
219
|
}
|
|
219
220
|
}
|
package/src/signer/types.ts
CHANGED
|
@@ -34,8 +34,12 @@ export interface Destination {
|
|
|
34
34
|
}
|
|
35
35
|
assertType<Eq<keyof Destination, keyof node.Destination>>
|
|
36
36
|
|
|
37
|
-
export
|
|
38
|
-
export
|
|
37
|
+
export const groupedKeyTypes = ['default', 'bip340-schnorr'] as const
|
|
38
|
+
export const grouplessKeyTypes = ['gl-secp256k1', 'gl-secp256r1', 'gl-ed25519', 'gl-webauthn'] as const
|
|
39
|
+
export const keyTypes = [...groupedKeyTypes, ...grouplessKeyTypes] as const
|
|
40
|
+
|
|
41
|
+
export type GroupedKeyType = (typeof groupedKeyTypes)[number]
|
|
42
|
+
export type GrouplessKeyType = (typeof grouplessKeyTypes)[number]
|
|
39
43
|
|
|
40
44
|
export type KeyType = GroupedKeyType | GrouplessKeyType
|
|
41
45
|
|
|
@@ -54,12 +58,20 @@ export interface GrouplessAccount {
|
|
|
54
58
|
|
|
55
59
|
export type Account = GroupedAccount | GrouplessAccount
|
|
56
60
|
|
|
61
|
+
export function isGroupedKeyType(keyType: KeyType): keyType is GroupedKeyType {
|
|
62
|
+
return keyType === 'default' || keyType === 'bip340-schnorr'
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function isGrouplessKeyType(keyType: KeyType): keyType is GrouplessKeyType {
|
|
66
|
+
return keyType !== 'default' && keyType !== 'bip340-schnorr'
|
|
67
|
+
}
|
|
68
|
+
|
|
57
69
|
export function isGroupedAccount(account: Account): account is GroupedAccount {
|
|
58
|
-
return account.keyType
|
|
70
|
+
return isGroupedKeyType(account.keyType)
|
|
59
71
|
}
|
|
60
72
|
|
|
61
73
|
export function isGrouplessAccount(account: Account): account is GrouplessAccount {
|
|
62
|
-
return account.keyType
|
|
74
|
+
return isGrouplessKeyType(account.keyType)
|
|
63
75
|
}
|
|
64
76
|
|
|
65
77
|
export type SignerAddress = { signerAddress: string; signerKeyType?: KeyType }
|
|
@@ -127,6 +139,7 @@ export interface SignExecuteScriptTxParams {
|
|
|
127
139
|
gasPrice?: Number256
|
|
128
140
|
gasEstimationMultiplier?: number
|
|
129
141
|
group?: number
|
|
142
|
+
dustAmount?: Number256
|
|
130
143
|
}
|
|
131
144
|
assertType<Eq<keyof SignExecuteScriptTxParams, keyof TxBuildParams<node.BuildExecuteScriptTx>>>()
|
|
132
145
|
export interface SignExecuteScriptTxResult {
|