@aptos-labs/ts-sdk 7.3.0 → 7.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +43 -43
- package/README.md +19 -20
- package/dist/api/account/abstraction.d.ts +10 -0
- package/dist/api/account/abstraction.d.ts.map +1 -1
- package/dist/api/account/abstraction.js +19 -6
- package/dist/api/account/abstraction.js.map +1 -1
- package/dist/api/ans.d.ts +9 -0
- package/dist/api/ans.d.ts.map +1 -1
- package/dist/api/ans.js +5 -0
- package/dist/api/ans.js.map +1 -1
- package/dist/api/coin.d.ts +2 -0
- package/dist/api/coin.d.ts.map +1 -1
- package/dist/api/coin.js +1 -0
- package/dist/api/coin.js.map +1 -1
- package/dist/api/digitalAsset.d.ts +30 -0
- package/dist/api/digitalAsset.d.ts.map +1 -1
- package/dist/api/digitalAsset.js +15 -0
- package/dist/api/digitalAsset.js.map +1 -1
- package/dist/api/fungibleAsset.d.ts +4 -0
- package/dist/api/fungibleAsset.d.ts.map +1 -1
- package/dist/api/fungibleAsset.js +2 -0
- package/dist/api/fungibleAsset.js.map +1 -1
- package/dist/api/keyless.d.ts +38 -1
- package/dist/api/keyless.d.ts.map +1 -1
- package/dist/api/keyless.js +29 -1
- package/dist/api/keyless.js.map +1 -1
- package/dist/api/transaction.d.ts +41 -1
- package/dist/api/transaction.d.ts.map +1 -1
- package/dist/api/transaction.js +42 -2
- package/dist/api/transaction.js.map +1 -1
- package/dist/api/transactionSubmission/build.d.ts +7 -5
- package/dist/api/transactionSubmission/build.d.ts.map +1 -1
- package/dist/api/transactionSubmission/build.js +13 -5
- package/dist/api/transactionSubmission/build.js.map +1 -1
- package/dist/api/transactionSubmission/simulate.d.ts +7 -3
- package/dist/api/transactionSubmission/simulate.d.ts.map +1 -1
- package/dist/api/transactionSubmission/simulate.js +7 -3
- package/dist/api/transactionSubmission/simulate.js.map +1 -1
- package/dist/bcs/serializable/moveStructs.d.ts +72 -28
- package/dist/bcs/serializable/moveStructs.d.ts.map +1 -1
- package/dist/bcs/serializable/moveStructs.js +76 -28
- package/dist/bcs/serializable/moveStructs.js.map +1 -1
- package/dist/functions/keyless.d.ts +1 -1
- package/dist/functions/keyless.d.ts.map +1 -1
- package/dist/functions/keyless.js +1 -1
- package/dist/functions/keyless.js.map +1 -1
- package/dist/functions/transaction.d.ts +1 -1
- package/dist/functions/transaction.d.ts.map +1 -1
- package/dist/functions/transaction.js +1 -1
- package/dist/functions/transaction.js.map +1 -1
- package/dist/internal/abstraction.d.ts +35 -0
- package/dist/internal/abstraction.d.ts.map +1 -1
- package/dist/internal/abstraction.js +38 -3
- package/dist/internal/abstraction.js.map +1 -1
- package/dist/internal/account.d.ts +6 -0
- package/dist/internal/account.d.ts.map +1 -1
- package/dist/internal/account.js +55 -37
- package/dist/internal/account.js.map +1 -1
- package/dist/internal/ans.d.ts +11 -0
- package/dist/internal/ans.d.ts.map +1 -1
- package/dist/internal/ans.js +18 -6
- package/dist/internal/ans.js.map +1 -1
- package/dist/internal/coin.d.ts +2 -0
- package/dist/internal/coin.d.ts.map +1 -1
- package/dist/internal/coin.js +3 -1
- package/dist/internal/coin.js.map +1 -1
- package/dist/internal/digitalAsset.d.ts +30 -0
- package/dist/internal/digitalAsset.d.ts.map +1 -1
- package/dist/internal/digitalAsset.js +45 -15
- package/dist/internal/digitalAsset.js.map +1 -1
- package/dist/internal/fungibleAsset.d.ts +4 -0
- package/dist/internal/fungibleAsset.d.ts.map +1 -1
- package/dist/internal/fungibleAsset.js +6 -2
- package/dist/internal/fungibleAsset.js.map +1 -1
- package/dist/internal/keyless.d.ts +39 -1
- package/dist/internal/keyless.d.ts.map +1 -1
- package/dist/internal/keyless.js +71 -13
- package/dist/internal/keyless.js.map +1 -1
- package/dist/internal/transaction.d.ts +24 -1
- package/dist/internal/transaction.d.ts.map +1 -1
- package/dist/internal/transaction.js +125 -4
- package/dist/internal/transaction.js.map +1 -1
- package/dist/internal/transactionSubmission.d.ts +2 -0
- package/dist/internal/transactionSubmission.d.ts.map +1 -1
- package/dist/internal/transactionSubmission.js +3 -1
- package/dist/internal/transactionSubmission.js.map +1 -1
- package/dist/transactions/management/transactionWorker.d.ts +10 -6
- package/dist/transactions/management/transactionWorker.d.ts.map +1 -1
- package/dist/transactions/management/transactionWorker.js +28 -24
- package/dist/transactions/management/transactionWorker.js.map +1 -1
- package/dist/transactions/transactionBuilder/index.d.ts +1 -0
- package/dist/transactions/transactionBuilder/index.d.ts.map +1 -1
- package/dist/transactions/transactionBuilder/index.js +1 -0
- package/dist/transactions/transactionBuilder/index.js.map +1 -1
- package/dist/transactions/transactionBuilder/scriptAbi.d.ts +10 -0
- package/dist/transactions/transactionBuilder/scriptAbi.d.ts.map +1 -0
- package/dist/transactions/transactionBuilder/scriptAbi.js +863 -0
- package/dist/transactions/transactionBuilder/scriptAbi.js.map +1 -0
- package/dist/transactions/transactionBuilder/transactionBuilder.d.ts.map +1 -1
- package/dist/transactions/transactionBuilder/transactionBuilder.js +65 -1
- package/dist/transactions/transactionBuilder/transactionBuilder.js.map +1 -1
- package/dist/transactions/types.d.ts +9 -4
- package/dist/transactions/types.d.ts.map +1 -1
- package/dist/types/keyless.d.ts +2 -2
- package/dist/types/keyless.d.ts.map +1 -1
- package/dist/types/types.d.ts +2 -2
- package/dist/types/types.d.ts.map +1 -1
- package/dist/utils/const.d.ts +11 -0
- package/dist/utils/const.d.ts.map +1 -1
- package/dist/utils/const.js +11 -0
- package/dist/utils/const.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +26 -25
- package/src/api/account/abstraction.ts +23 -6
- package/src/api/ans.ts +9 -0
- package/src/api/coin.ts +2 -0
- package/src/api/digitalAsset.ts +30 -0
- package/src/api/fungibleAsset.ts +4 -0
- package/src/api/keyless.ts +39 -1
- package/src/api/transaction.ts +48 -1
- package/src/api/transactionSubmission/build.ts +16 -6
- package/src/api/transactionSubmission/simulate.ts +7 -3
- package/src/bcs/serializable/moveStructs.ts +80 -28
- package/src/functions/keyless.ts +1 -0
- package/src/functions/transaction.ts +1 -0
- package/src/internal/abstraction.ts +41 -3
- package/src/internal/account.ts +60 -38
- package/src/internal/ans.ts +24 -6
- package/src/internal/coin.ts +4 -1
- package/src/internal/digitalAsset.ts +60 -9
- package/src/internal/fungibleAsset.ts +8 -2
- package/src/internal/keyless.ts +91 -14
- package/src/internal/transaction.ts +154 -4
- package/src/internal/transactionSubmission.ts +4 -1
- package/src/transactions/management/transactionWorker.ts +35 -23
- package/src/transactions/transactionBuilder/index.ts +1 -0
- package/src/transactions/transactionBuilder/scriptAbi.ts +1145 -0
- package/src/transactions/transactionBuilder/transactionBuilder.ts +91 -6
- package/src/transactions/types.ts +10 -4
- package/src/types/keyless.ts +2 -2
- package/src/types/types.ts +2 -2
- package/src/utils/const.ts +12 -0
- package/src/version.ts +1 -1
|
@@ -0,0 +1,863 @@
|
|
|
1
|
+
// Copyright © Aptos Foundation
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { AccountAddress, Hex } from "../../core/index.js";
|
|
4
|
+
import { MoveAbility } from "../../types/index.js";
|
|
5
|
+
import { Identifier } from "../instances/identifier.js";
|
|
6
|
+
import { StructTag, TypeTagAddress, TypeTagBool, TypeTagGeneric, TypeTagI128, TypeTagI16, TypeTagI256, TypeTagI32, TypeTagI64, TypeTagI8, TypeTagReference, TypeTagSigner, TypeTagStruct, TypeTagU128, TypeTagU16, TypeTagU256, TypeTagU32, TypeTagU64, TypeTagU8, TypeTagVector, } from "../typeTag/index.js";
|
|
7
|
+
const MOVE_MAGIC = [0xa1, 0x1c, 0xeb, 0x0b];
|
|
8
|
+
const APTOS_BYTECODE_VERSION_MASK = 0x0a000000;
|
|
9
|
+
const MIN_BYTECODE_VERSION = 1;
|
|
10
|
+
const MAX_BYTECODE_VERSION = 10;
|
|
11
|
+
const TABLE_INDEX_MAX = 65535;
|
|
12
|
+
const TABLE_COUNT_MAX = 255;
|
|
13
|
+
const TYPE_PARAMETER_COUNT_MAX = 255;
|
|
14
|
+
const TYPE_PARAMETER_INDEX_MAX = 65536;
|
|
15
|
+
const SIGNATURE_SIZE_MAX = 255;
|
|
16
|
+
const SIGNATURE_TOKEN_DEPTH_MAX = 256;
|
|
17
|
+
const ABILITY_SET_MAX = 15;
|
|
18
|
+
const ACCESS_SPECIFIER_COUNT_MAX = 64;
|
|
19
|
+
const ATTRIBUTE_COUNT_MAX = 16;
|
|
20
|
+
const BYTECODE_COUNT_MAX = 65535;
|
|
21
|
+
function invalidScript(reason) {
|
|
22
|
+
throw new Error(`Invalid script bytecode: ${reason}`);
|
|
23
|
+
}
|
|
24
|
+
class ScriptBytecodeReader {
|
|
25
|
+
bytes;
|
|
26
|
+
start;
|
|
27
|
+
end;
|
|
28
|
+
cursor;
|
|
29
|
+
constructor(bytes, start = 0, end = bytes.length) {
|
|
30
|
+
this.bytes = bytes;
|
|
31
|
+
this.start = start;
|
|
32
|
+
this.end = end;
|
|
33
|
+
this.cursor = start;
|
|
34
|
+
}
|
|
35
|
+
get position() {
|
|
36
|
+
return this.cursor - this.start;
|
|
37
|
+
}
|
|
38
|
+
get remaining() {
|
|
39
|
+
return this.end - this.cursor;
|
|
40
|
+
}
|
|
41
|
+
readU8(label) {
|
|
42
|
+
if (this.remaining < 1) {
|
|
43
|
+
invalidScript(`unexpected end of input while reading ${label}`);
|
|
44
|
+
}
|
|
45
|
+
const value = this.bytes[this.cursor];
|
|
46
|
+
this.cursor += 1;
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
readU32(label) {
|
|
50
|
+
const bytes = this.readBytes(4, label);
|
|
51
|
+
return bytes[0] + bytes[1] * 256 + bytes[2] * 256 ** 2 + bytes[3] * 256 ** 3;
|
|
52
|
+
}
|
|
53
|
+
readU16(label) {
|
|
54
|
+
const bytes = this.readBytes(2, label);
|
|
55
|
+
return bytes[0] + bytes[1] * 256;
|
|
56
|
+
}
|
|
57
|
+
readUleb128(label, max) {
|
|
58
|
+
let value = 0;
|
|
59
|
+
for (let byteIndex = 0; byteIndex < 5; byteIndex += 1) {
|
|
60
|
+
const byte = this.readU8(label);
|
|
61
|
+
const group = byte % 128;
|
|
62
|
+
value += group * 128 ** byteIndex;
|
|
63
|
+
if (byte < 128) {
|
|
64
|
+
if (byteIndex > 0 && group === 0) {
|
|
65
|
+
invalidScript(`non-canonical ULEB128 encoding for ${label}`);
|
|
66
|
+
}
|
|
67
|
+
if (value > max) {
|
|
68
|
+
invalidScript(`${label} ${value} exceeds maximum ${max}`);
|
|
69
|
+
}
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
invalidScript(`ULEB128 encoding for ${label} continues after five bytes`);
|
|
74
|
+
}
|
|
75
|
+
readUleb128U64(label) {
|
|
76
|
+
for (let byteIndex = 0; byteIndex < 10; byteIndex += 1) {
|
|
77
|
+
const byte = this.readU8(label);
|
|
78
|
+
const group = byte % 128;
|
|
79
|
+
if (byteIndex === 9 && group > 1) {
|
|
80
|
+
invalidScript(`${label} exceeds maximum u64`);
|
|
81
|
+
}
|
|
82
|
+
if (byte < 128) {
|
|
83
|
+
if (byteIndex > 0 && group === 0) {
|
|
84
|
+
invalidScript(`non-canonical ULEB128 encoding for ${label}`);
|
|
85
|
+
}
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
invalidScript(`ULEB128 encoding for ${label} continues after ten bytes`);
|
|
90
|
+
}
|
|
91
|
+
readBytes(length, label) {
|
|
92
|
+
if (!Number.isSafeInteger(length) || length < 0 || length > this.remaining) {
|
|
93
|
+
invalidScript(`unexpected end of input while reading ${label}`);
|
|
94
|
+
}
|
|
95
|
+
const value = this.bytes.subarray(this.cursor, this.cursor + length);
|
|
96
|
+
this.cursor += length;
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
subReader(offset, length, label) {
|
|
100
|
+
if (!Number.isSafeInteger(offset) ||
|
|
101
|
+
!Number.isSafeInteger(length) ||
|
|
102
|
+
offset < 0 ||
|
|
103
|
+
length < 0 ||
|
|
104
|
+
offset > this.remaining ||
|
|
105
|
+
length > this.remaining - offset) {
|
|
106
|
+
invalidScript(`${label} is outside the available byte range`);
|
|
107
|
+
}
|
|
108
|
+
const subStart = this.cursor + offset;
|
|
109
|
+
return new ScriptBytecodeReader(this.bytes, subStart, subStart + length);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function parseTableType(value) {
|
|
113
|
+
switch (value) {
|
|
114
|
+
case 1 /* TableType.ModuleHandles */:
|
|
115
|
+
case 2 /* TableType.StructHandles */:
|
|
116
|
+
case 3 /* TableType.FunctionHandles */:
|
|
117
|
+
case 4 /* TableType.FunctionInstantiations */:
|
|
118
|
+
case 5 /* TableType.Signatures */:
|
|
119
|
+
case 6 /* TableType.ConstantPool */:
|
|
120
|
+
case 7 /* TableType.Identifiers */:
|
|
121
|
+
case 8 /* TableType.AddressIdentifiers */:
|
|
122
|
+
case 16 /* TableType.Metadata */:
|
|
123
|
+
return value;
|
|
124
|
+
case 10 /* TableType.StructDefinitions */:
|
|
125
|
+
case 11 /* TableType.StructDefinitionInstantiations */:
|
|
126
|
+
case 12 /* TableType.FunctionDefinitions */:
|
|
127
|
+
case 13 /* TableType.FieldHandles */:
|
|
128
|
+
case 14 /* TableType.FieldInstantiations */:
|
|
129
|
+
case 15 /* TableType.FriendDeclarations */:
|
|
130
|
+
case 17 /* TableType.VariantFieldHandles */:
|
|
131
|
+
case 18 /* TableType.VariantFieldInstantiations */:
|
|
132
|
+
case 19 /* TableType.StructVariantHandles */:
|
|
133
|
+
case 20 /* TableType.StructVariantInstantiations */:
|
|
134
|
+
return invalidScript(`table type ${value} is not valid in a script`);
|
|
135
|
+
default:
|
|
136
|
+
return invalidScript(`unknown table type ${value}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function parseTableHeaders(reader) {
|
|
140
|
+
const tableCount = reader.readUleb128("table count", TABLE_COUNT_MAX);
|
|
141
|
+
const headers = [];
|
|
142
|
+
const kinds = new Set();
|
|
143
|
+
for (let index = 0; index < tableCount; index += 1) {
|
|
144
|
+
const kind = parseTableType(reader.readU8(`table ${index} kind`));
|
|
145
|
+
if (kinds.has(kind)) {
|
|
146
|
+
invalidScript(`duplicate table type ${kind}`);
|
|
147
|
+
}
|
|
148
|
+
kinds.add(kind);
|
|
149
|
+
headers.push({
|
|
150
|
+
kind,
|
|
151
|
+
offset: reader.readUleb128(`table ${index} offset`, 0xffffffff),
|
|
152
|
+
byteLength: reader.readUleb128(`table ${index} byte length`, 0xffffffff),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
headers.sort((left, right) => left.offset - right.offset);
|
|
156
|
+
let contentLength = 0;
|
|
157
|
+
for (const header of headers) {
|
|
158
|
+
if (header.offset !== contentLength || header.byteLength === 0) {
|
|
159
|
+
invalidScript("table ranges must be contiguous, non-empty, and begin at offset zero");
|
|
160
|
+
}
|
|
161
|
+
contentLength += header.byteLength;
|
|
162
|
+
if (!Number.isSafeInteger(contentLength) || contentLength > reader.remaining) {
|
|
163
|
+
invalidScript("table ranges exceed the available bytecode");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return { headers, contentLength };
|
|
167
|
+
}
|
|
168
|
+
function tableReader(tableContents, headers, kind) {
|
|
169
|
+
const header = headers.find((candidate) => candidate.kind === kind);
|
|
170
|
+
return header === undefined
|
|
171
|
+
? undefined
|
|
172
|
+
: tableContents.subReader(header.offset, header.byteLength, `table type ${kind}`);
|
|
173
|
+
}
|
|
174
|
+
function parseEntries(reader, parse) {
|
|
175
|
+
if (reader === undefined) {
|
|
176
|
+
return [];
|
|
177
|
+
}
|
|
178
|
+
const entries = [];
|
|
179
|
+
while (reader.remaining > 0) {
|
|
180
|
+
entries.push(parse(reader));
|
|
181
|
+
}
|
|
182
|
+
return entries;
|
|
183
|
+
}
|
|
184
|
+
function isMoveIdentifierCharacter(character) {
|
|
185
|
+
const code = character.charCodeAt(0);
|
|
186
|
+
return (character === "_" ||
|
|
187
|
+
character === "$" ||
|
|
188
|
+
(code >= 48 && code <= 57) ||
|
|
189
|
+
(code >= 65 && code <= 90) ||
|
|
190
|
+
(code >= 97 && code <= 122));
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Mirrors Move's bytecode-level identifier rules, including the legacy script self name and
|
|
194
|
+
* compiler-generated `<SELF>_N` names. `$` is reserved for compiler/runtime names and is only
|
|
195
|
+
* encoded by Aptos bytecode version 9 or newer.
|
|
196
|
+
*/
|
|
197
|
+
function isValidMoveIdentifier(identifier, version) {
|
|
198
|
+
if (identifier === " ")
|
|
199
|
+
return true;
|
|
200
|
+
if (identifier.startsWith("<SELF>_")) {
|
|
201
|
+
const suffix = identifier.slice(7);
|
|
202
|
+
return suffix.length > 0 && Array.from(suffix).every((character) => character >= "0" && character <= "9");
|
|
203
|
+
}
|
|
204
|
+
if (identifier.length === 0 || (version < 9 && identifier.includes("$")))
|
|
205
|
+
return false;
|
|
206
|
+
const characters = Array.from(identifier);
|
|
207
|
+
const first = characters[0];
|
|
208
|
+
const firstCode = first.charCodeAt(0);
|
|
209
|
+
const startsWithLetter = (firstCode >= 65 && firstCode <= 90) || (firstCode >= 97 && firstCode <= 122);
|
|
210
|
+
if (!startsWithLetter && first !== "_" && first !== "$")
|
|
211
|
+
return false;
|
|
212
|
+
if ((first === "_" || first === "$") && characters.length === 1)
|
|
213
|
+
return false;
|
|
214
|
+
return characters.slice(1).every(isMoveIdentifierCharacter);
|
|
215
|
+
}
|
|
216
|
+
function parseIdentifiers(reader, version) {
|
|
217
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
218
|
+
return parseEntries(reader, (entry) => {
|
|
219
|
+
const length = entry.readUleb128("identifier length", TABLE_INDEX_MAX);
|
|
220
|
+
const bytes = entry.readBytes(length, "identifier");
|
|
221
|
+
if (bytes.some((byte) => byte > 0x7f)) {
|
|
222
|
+
invalidScript("identifier bytes must be ASCII");
|
|
223
|
+
}
|
|
224
|
+
let identifier;
|
|
225
|
+
try {
|
|
226
|
+
identifier = decoder.decode(bytes);
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
invalidScript("identifier is not valid UTF-8");
|
|
230
|
+
}
|
|
231
|
+
if (!isValidMoveIdentifier(identifier, version)) {
|
|
232
|
+
if (version < 9 && identifier.includes("$")) {
|
|
233
|
+
invalidScript(`$ in identifiers is not supported in bytecode version ${version}`);
|
|
234
|
+
}
|
|
235
|
+
invalidScript(`invalid identifier '${identifier}'`);
|
|
236
|
+
}
|
|
237
|
+
return identifier;
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
function parseAddresses(reader) {
|
|
241
|
+
return parseEntries(reader, (entry) => entry.readBytes(AccountAddress.LENGTH, "address identifier"));
|
|
242
|
+
}
|
|
243
|
+
function parseModuleHandles(reader) {
|
|
244
|
+
return parseEntries(reader, (entry) => ({
|
|
245
|
+
address: entry.readUleb128("module handle address index", TABLE_INDEX_MAX),
|
|
246
|
+
name: entry.readUleb128("module handle name index", TABLE_INDEX_MAX),
|
|
247
|
+
}));
|
|
248
|
+
}
|
|
249
|
+
function readVersionedAbilitySet(reader, version, position) {
|
|
250
|
+
if (version >= 2) {
|
|
251
|
+
return reader.readUleb128("ability set", ABILITY_SET_MAX);
|
|
252
|
+
}
|
|
253
|
+
const legacyValue = reader.readU8("legacy ability");
|
|
254
|
+
if (position === "structHandle") {
|
|
255
|
+
if (legacyValue === 1)
|
|
256
|
+
return 4 | 8;
|
|
257
|
+
if (legacyValue === 2)
|
|
258
|
+
return 1 | 2 | 4;
|
|
259
|
+
invalidScript(`unknown legacy struct ability ${legacyValue}`);
|
|
260
|
+
}
|
|
261
|
+
let abilities;
|
|
262
|
+
switch (legacyValue) {
|
|
263
|
+
case 1:
|
|
264
|
+
abilities = 0;
|
|
265
|
+
break;
|
|
266
|
+
case 2:
|
|
267
|
+
abilities = 1 | 2;
|
|
268
|
+
break;
|
|
269
|
+
case 3:
|
|
270
|
+
abilities = 8;
|
|
271
|
+
break;
|
|
272
|
+
default:
|
|
273
|
+
invalidScript(`unknown legacy type parameter ability ${legacyValue}`);
|
|
274
|
+
}
|
|
275
|
+
return position === "functionTypeParameter" ? abilities | 4 : abilities;
|
|
276
|
+
}
|
|
277
|
+
function parseStructHandles(reader, version) {
|
|
278
|
+
return parseEntries(reader, (entry) => {
|
|
279
|
+
const module = entry.readUleb128("struct handle module index", TABLE_INDEX_MAX);
|
|
280
|
+
const name = entry.readUleb128("struct handle name index", TABLE_INDEX_MAX);
|
|
281
|
+
readVersionedAbilitySet(entry, version, "structHandle");
|
|
282
|
+
const typeParameterCount = entry.readUleb128("struct type parameter count", TYPE_PARAMETER_COUNT_MAX);
|
|
283
|
+
for (let index = 0; index < typeParameterCount; index += 1) {
|
|
284
|
+
readVersionedAbilitySet(entry, version, "structTypeParameter");
|
|
285
|
+
if (version >= 3) {
|
|
286
|
+
entry.readUleb128(`struct type parameter ${index} phantom flag`, 1);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return { module, name, typeParameterCount };
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
function parseSignatureToken(reader, version, depth = 1) {
|
|
293
|
+
if (depth > SIGNATURE_TOKEN_DEPTH_MAX) {
|
|
294
|
+
invalidScript(`signature token nesting exceeds ${SIGNATURE_TOKEN_DEPTH_MAX}`);
|
|
295
|
+
}
|
|
296
|
+
const serializedType = reader.readU8("signature token");
|
|
297
|
+
switch (serializedType) {
|
|
298
|
+
case 1 /* SerializedType.Bool */:
|
|
299
|
+
return { kind: "bool" };
|
|
300
|
+
case 2 /* SerializedType.U8 */:
|
|
301
|
+
return { kind: "u8" };
|
|
302
|
+
case 3 /* SerializedType.U64 */:
|
|
303
|
+
return { kind: "u64" };
|
|
304
|
+
case 4 /* SerializedType.U128 */:
|
|
305
|
+
return { kind: "u128" };
|
|
306
|
+
case 5 /* SerializedType.Address */:
|
|
307
|
+
return { kind: "address" };
|
|
308
|
+
case 6 /* SerializedType.Reference */:
|
|
309
|
+
case 7 /* SerializedType.MutableReference */:
|
|
310
|
+
return {
|
|
311
|
+
kind: "reference",
|
|
312
|
+
mutable: serializedType === 7 /* SerializedType.MutableReference */,
|
|
313
|
+
value: parseSignatureToken(reader, version, depth + 1),
|
|
314
|
+
};
|
|
315
|
+
case 8 /* SerializedType.Struct */:
|
|
316
|
+
return {
|
|
317
|
+
kind: "struct",
|
|
318
|
+
index: reader.readUleb128("struct handle index", TABLE_INDEX_MAX),
|
|
319
|
+
typeArguments: [],
|
|
320
|
+
};
|
|
321
|
+
case 9 /* SerializedType.TypeParameter */:
|
|
322
|
+
return {
|
|
323
|
+
kind: "typeParameter",
|
|
324
|
+
index: reader.readUleb128("type parameter index", TYPE_PARAMETER_INDEX_MAX),
|
|
325
|
+
};
|
|
326
|
+
case 10 /* SerializedType.Vector */:
|
|
327
|
+
return { kind: "vector", value: parseSignatureToken(reader, version, depth + 1) };
|
|
328
|
+
case 11 /* SerializedType.StructInstantiation */: {
|
|
329
|
+
const index = reader.readUleb128("struct handle index", TABLE_INDEX_MAX);
|
|
330
|
+
const count = reader.readUleb128("struct instantiation arity", TYPE_PARAMETER_COUNT_MAX);
|
|
331
|
+
if (count === 0) {
|
|
332
|
+
invalidScript("struct instantiation has zero type arguments");
|
|
333
|
+
}
|
|
334
|
+
const typeArguments = Array.from({ length: count }, () => parseSignatureToken(reader, version, depth + 1));
|
|
335
|
+
return { kind: "struct", index, typeArguments };
|
|
336
|
+
}
|
|
337
|
+
case 12 /* SerializedType.Signer */:
|
|
338
|
+
return { kind: "signer" };
|
|
339
|
+
case 13 /* SerializedType.U16 */:
|
|
340
|
+
case 14 /* SerializedType.U32 */:
|
|
341
|
+
case 15 /* SerializedType.U256 */:
|
|
342
|
+
if (version < 6) {
|
|
343
|
+
invalidScript(`integer signature token ${serializedType} is not supported in version ${version}`);
|
|
344
|
+
}
|
|
345
|
+
if (serializedType === 13 /* SerializedType.U16 */)
|
|
346
|
+
return { kind: "u16" };
|
|
347
|
+
if (serializedType === 14 /* SerializedType.U32 */)
|
|
348
|
+
return { kind: "u32" };
|
|
349
|
+
return { kind: "u256" };
|
|
350
|
+
case 16 /* SerializedType.Function */: {
|
|
351
|
+
if (version < 8) {
|
|
352
|
+
invalidScript(`function signature tokens are not supported in version ${version}`);
|
|
353
|
+
}
|
|
354
|
+
readVersionedAbilitySet(reader, version, "structTypeParameter");
|
|
355
|
+
const argumentCount = reader.readUleb128("function argument count", TYPE_PARAMETER_COUNT_MAX);
|
|
356
|
+
const resultCount = reader.readUleb128("function result count", TYPE_PARAMETER_COUNT_MAX);
|
|
357
|
+
const arguments_ = Array.from({ length: argumentCount }, () => parseSignatureToken(reader, version, depth + 1));
|
|
358
|
+
const results = Array.from({ length: resultCount }, () => parseSignatureToken(reader, version, depth + 1));
|
|
359
|
+
return { kind: "function", arguments: arguments_, results };
|
|
360
|
+
}
|
|
361
|
+
case 17 /* SerializedType.I8 */:
|
|
362
|
+
case 18 /* SerializedType.I16 */:
|
|
363
|
+
case 19 /* SerializedType.I32 */:
|
|
364
|
+
case 20 /* SerializedType.I64 */:
|
|
365
|
+
case 21 /* SerializedType.I128 */:
|
|
366
|
+
case 22 /* SerializedType.I256 */:
|
|
367
|
+
if (version < 9) {
|
|
368
|
+
invalidScript(`signed integer signature token ${serializedType} is not supported in version ${version}`);
|
|
369
|
+
}
|
|
370
|
+
switch (serializedType) {
|
|
371
|
+
case 17 /* SerializedType.I8 */:
|
|
372
|
+
return { kind: "i8" };
|
|
373
|
+
case 18 /* SerializedType.I16 */:
|
|
374
|
+
return { kind: "i16" };
|
|
375
|
+
case 19 /* SerializedType.I32 */:
|
|
376
|
+
return { kind: "i32" };
|
|
377
|
+
case 20 /* SerializedType.I64 */:
|
|
378
|
+
return { kind: "i64" };
|
|
379
|
+
case 21 /* SerializedType.I128 */:
|
|
380
|
+
return { kind: "i128" };
|
|
381
|
+
default:
|
|
382
|
+
return { kind: "i256" };
|
|
383
|
+
}
|
|
384
|
+
default:
|
|
385
|
+
invalidScript(`unknown signature token ${serializedType}`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
function parseSignatures(reader, version) {
|
|
389
|
+
return parseEntries(reader, (entry) => {
|
|
390
|
+
const count = entry.readUleb128("signature length", SIGNATURE_SIZE_MAX);
|
|
391
|
+
return Array.from({ length: count }, () => parseSignatureToken(entry, version));
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
function parseAccessSpecifiers(reader) {
|
|
395
|
+
const option = reader.readU8("access specifier option");
|
|
396
|
+
if (option === 1)
|
|
397
|
+
return [];
|
|
398
|
+
if (option !== 2) {
|
|
399
|
+
invalidScript(`unknown access specifier option ${option}`);
|
|
400
|
+
}
|
|
401
|
+
const references = [];
|
|
402
|
+
const count = reader.readUleb128("access specifier count", ACCESS_SPECIFIER_COUNT_MAX);
|
|
403
|
+
for (let index = 0; index < count; index += 1) {
|
|
404
|
+
const kind = reader.readU8(`access specifier ${index} kind`);
|
|
405
|
+
if (kind !== 1 && kind !== 2) {
|
|
406
|
+
invalidScript(`unknown access specifier kind ${kind}`);
|
|
407
|
+
}
|
|
408
|
+
const negated = reader.readU8(`access specifier ${index} negated flag`);
|
|
409
|
+
if (negated !== 1 && negated !== 2) {
|
|
410
|
+
invalidScript(`unknown access specifier boolean ${negated}`);
|
|
411
|
+
}
|
|
412
|
+
const resource = reader.readU8(`access specifier ${index} resource`);
|
|
413
|
+
switch (resource) {
|
|
414
|
+
case 1:
|
|
415
|
+
break;
|
|
416
|
+
case 2:
|
|
417
|
+
references.push({
|
|
418
|
+
kind: "address",
|
|
419
|
+
index: reader.readUleb128("access specifier address index", TABLE_INDEX_MAX),
|
|
420
|
+
});
|
|
421
|
+
break;
|
|
422
|
+
case 3:
|
|
423
|
+
references.push({
|
|
424
|
+
kind: "module",
|
|
425
|
+
index: reader.readUleb128("access specifier module index", TABLE_INDEX_MAX),
|
|
426
|
+
});
|
|
427
|
+
break;
|
|
428
|
+
case 4:
|
|
429
|
+
references.push({
|
|
430
|
+
kind: "struct",
|
|
431
|
+
index: reader.readUleb128("access specifier struct index", TABLE_INDEX_MAX),
|
|
432
|
+
});
|
|
433
|
+
break;
|
|
434
|
+
case 5:
|
|
435
|
+
references.push({
|
|
436
|
+
kind: "struct",
|
|
437
|
+
index: reader.readUleb128("access specifier struct index", TABLE_INDEX_MAX),
|
|
438
|
+
});
|
|
439
|
+
references.push({
|
|
440
|
+
kind: "signature",
|
|
441
|
+
index: reader.readUleb128("access specifier signature index", TABLE_INDEX_MAX),
|
|
442
|
+
});
|
|
443
|
+
break;
|
|
444
|
+
default:
|
|
445
|
+
invalidScript(`unknown access specifier resource ${resource}`);
|
|
446
|
+
}
|
|
447
|
+
const address = reader.readU8(`access specifier ${index} address`);
|
|
448
|
+
switch (address) {
|
|
449
|
+
case 1:
|
|
450
|
+
break;
|
|
451
|
+
case 2:
|
|
452
|
+
references.push({
|
|
453
|
+
kind: "address",
|
|
454
|
+
index: reader.readUleb128("access specifier literal address index", TABLE_INDEX_MAX),
|
|
455
|
+
});
|
|
456
|
+
break;
|
|
457
|
+
case 3: {
|
|
458
|
+
reader.readUleb128("access specifier parameter index", 255);
|
|
459
|
+
const functionOption = reader.readU8("access specifier function option");
|
|
460
|
+
if (functionOption === 2) {
|
|
461
|
+
references.push({
|
|
462
|
+
kind: "functionInstantiation",
|
|
463
|
+
index: reader.readUleb128("access specifier function instantiation index", TABLE_INDEX_MAX),
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
else if (functionOption !== 1) {
|
|
467
|
+
invalidScript(`unknown access specifier function option ${functionOption}`);
|
|
468
|
+
}
|
|
469
|
+
break;
|
|
470
|
+
}
|
|
471
|
+
default:
|
|
472
|
+
invalidScript(`unknown access specifier address ${address}`);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return references;
|
|
476
|
+
}
|
|
477
|
+
function parseFunctionAttributes(reader, version) {
|
|
478
|
+
if (version < 8)
|
|
479
|
+
return;
|
|
480
|
+
const count = reader.readUleb128("function attribute count", ATTRIBUTE_COUNT_MAX);
|
|
481
|
+
for (let index = 0; index < count; index += 1) {
|
|
482
|
+
const attribute = reader.readU8(`function attribute ${index}`);
|
|
483
|
+
if (attribute < 1 || attribute > 9) {
|
|
484
|
+
invalidScript(`unknown function attribute ${attribute}`);
|
|
485
|
+
}
|
|
486
|
+
if (attribute >= 3 && version < 10) {
|
|
487
|
+
invalidScript(`function attribute ${attribute} is not supported in version ${version}`);
|
|
488
|
+
}
|
|
489
|
+
if (attribute === 4 || (attribute >= 6 && attribute <= 9)) {
|
|
490
|
+
reader.readU16(`function attribute ${index} operand`);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
function parseFunctionHandles(reader, version) {
|
|
495
|
+
return parseEntries(reader, (entry) => {
|
|
496
|
+
const module = entry.readUleb128("function handle module index", TABLE_INDEX_MAX);
|
|
497
|
+
const name = entry.readUleb128("function handle name index", TABLE_INDEX_MAX);
|
|
498
|
+
const parameters = entry.readUleb128("function handle parameter signature index", TABLE_INDEX_MAX);
|
|
499
|
+
const returns = entry.readUleb128("function handle return signature index", TABLE_INDEX_MAX);
|
|
500
|
+
const typeParameterCount = entry.readUleb128("function type parameter count", TYPE_PARAMETER_COUNT_MAX);
|
|
501
|
+
for (let index = 0; index < typeParameterCount; index += 1) {
|
|
502
|
+
readVersionedAbilitySet(entry, version, "functionTypeParameter");
|
|
503
|
+
}
|
|
504
|
+
const accessReferences = version >= 7 ? parseAccessSpecifiers(entry) : [];
|
|
505
|
+
parseFunctionAttributes(entry, version);
|
|
506
|
+
return { module, name, parameters, returns, typeParameterCount, accessReferences };
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
function parseFunctionInstantiations(reader) {
|
|
510
|
+
return parseEntries(reader, (entry) => ({
|
|
511
|
+
handle: entry.readUleb128("function instantiation handle index", TABLE_INDEX_MAX),
|
|
512
|
+
typeParameters: entry.readUleb128("function instantiation signature index", TABLE_INDEX_MAX),
|
|
513
|
+
}));
|
|
514
|
+
}
|
|
515
|
+
function parseConstants(reader, version) {
|
|
516
|
+
return parseEntries(reader, (entry) => {
|
|
517
|
+
const type = parseSignatureToken(entry, version);
|
|
518
|
+
const byteLength = entry.readUleb128("constant byte length", TABLE_INDEX_MAX);
|
|
519
|
+
entry.readBytes(byteLength, "constant bytes");
|
|
520
|
+
return type;
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
function parseMetadata(reader, version) {
|
|
524
|
+
if (reader !== undefined && version < 5) {
|
|
525
|
+
invalidScript(`metadata tables are not supported in bytecode version ${version}`);
|
|
526
|
+
}
|
|
527
|
+
parseEntries(reader, (entry) => {
|
|
528
|
+
const keyLength = entry.readUleb128("metadata key length", 1023);
|
|
529
|
+
entry.readBytes(keyLength, "metadata key");
|
|
530
|
+
const valueLength = entry.readUleb128("metadata value length", TABLE_INDEX_MAX);
|
|
531
|
+
entry.readBytes(valueLength, "metadata value");
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
function decodeAbilities(bits) {
|
|
535
|
+
const abilities = [];
|
|
536
|
+
if ((bits & 1) !== 0)
|
|
537
|
+
abilities.push(MoveAbility.COPY);
|
|
538
|
+
if ((bits & 2) !== 0)
|
|
539
|
+
abilities.push(MoveAbility.DROP);
|
|
540
|
+
if ((bits & 4) !== 0)
|
|
541
|
+
abilities.push(MoveAbility.STORE);
|
|
542
|
+
if ((bits & 8) !== 0)
|
|
543
|
+
abilities.push(MoveAbility.KEY);
|
|
544
|
+
return abilities;
|
|
545
|
+
}
|
|
546
|
+
function indexed(values, index, label) {
|
|
547
|
+
const value = values[index];
|
|
548
|
+
if (value === undefined) {
|
|
549
|
+
invalidScript(`${label} index ${index} does not exist`);
|
|
550
|
+
}
|
|
551
|
+
return value;
|
|
552
|
+
}
|
|
553
|
+
function validateSignatureToken(token, structHandles, moduleHandles, identifiers, addresses, typeParameterCount) {
|
|
554
|
+
switch (token.kind) {
|
|
555
|
+
case "vector":
|
|
556
|
+
case "reference":
|
|
557
|
+
validateSignatureToken(token.value, structHandles, moduleHandles, identifiers, addresses, typeParameterCount);
|
|
558
|
+
return;
|
|
559
|
+
case "struct": {
|
|
560
|
+
const structHandle = indexed(structHandles, token.index, "struct handle");
|
|
561
|
+
if (token.typeArguments.length !== structHandle.typeParameterCount) {
|
|
562
|
+
invalidScript(`struct handle index ${token.index} expects ${structHandle.typeParameterCount} type arguments, received ${token.typeArguments.length}`);
|
|
563
|
+
}
|
|
564
|
+
const moduleHandle = indexed(moduleHandles, structHandle.module, "module handle");
|
|
565
|
+
indexed(addresses, moduleHandle.address, "address");
|
|
566
|
+
indexed(identifiers, moduleHandle.name, "identifier");
|
|
567
|
+
indexed(identifiers, structHandle.name, "identifier");
|
|
568
|
+
for (const argument of token.typeArguments) {
|
|
569
|
+
validateSignatureToken(argument, structHandles, moduleHandles, identifiers, addresses, typeParameterCount);
|
|
570
|
+
}
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
case "typeParameter":
|
|
574
|
+
if (typeParameterCount !== undefined && token.index >= typeParameterCount) {
|
|
575
|
+
invalidScript(`type parameter index ${token.index} does not exist`);
|
|
576
|
+
}
|
|
577
|
+
return;
|
|
578
|
+
case "function":
|
|
579
|
+
for (const argument of token.arguments) {
|
|
580
|
+
validateSignatureToken(argument, structHandles, moduleHandles, identifiers, addresses, typeParameterCount);
|
|
581
|
+
}
|
|
582
|
+
for (const result of token.results) {
|
|
583
|
+
validateSignatureToken(result, structHandles, moduleHandles, identifiers, addresses, typeParameterCount);
|
|
584
|
+
}
|
|
585
|
+
return;
|
|
586
|
+
default:
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
function validateSignature(signature, structHandles, moduleHandles, identifiers, addresses, typeParameterCount) {
|
|
591
|
+
for (const token of signature) {
|
|
592
|
+
validateSignatureToken(token, structHandles, moduleHandles, identifiers, addresses, typeParameterCount);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
function validateAccessReferences(references, addresses, moduleHandles, structHandles, signatures, functionInstantiations) {
|
|
596
|
+
for (const reference of references) {
|
|
597
|
+
switch (reference.kind) {
|
|
598
|
+
case "address":
|
|
599
|
+
indexed(addresses, reference.index, "access specifier address");
|
|
600
|
+
break;
|
|
601
|
+
case "module":
|
|
602
|
+
indexed(moduleHandles, reference.index, "access specifier module handle");
|
|
603
|
+
break;
|
|
604
|
+
case "struct":
|
|
605
|
+
indexed(structHandles, reference.index, "access specifier struct handle");
|
|
606
|
+
break;
|
|
607
|
+
case "signature":
|
|
608
|
+
indexed(signatures, reference.index, "access specifier signature");
|
|
609
|
+
break;
|
|
610
|
+
case "functionInstantiation":
|
|
611
|
+
indexed(functionInstantiations, reference.index, "access specifier function instantiation");
|
|
612
|
+
break;
|
|
613
|
+
default:
|
|
614
|
+
invalidScript("unknown access specifier reference");
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
function requireOpcodeVersion(opcode, version) {
|
|
619
|
+
let minimum = 1;
|
|
620
|
+
if (opcode >= 0x40 && opcode <= 0x47)
|
|
621
|
+
minimum = 4;
|
|
622
|
+
else if (opcode >= 0x48 && opcode <= 0x4d)
|
|
623
|
+
minimum = 6;
|
|
624
|
+
else if (opcode >= 0x4e && opcode <= 0x57)
|
|
625
|
+
minimum = 7;
|
|
626
|
+
else if (opcode >= 0x58 && opcode <= 0x5a)
|
|
627
|
+
minimum = 8;
|
|
628
|
+
else if (opcode >= 0x5b && opcode <= 0x67)
|
|
629
|
+
minimum = 9;
|
|
630
|
+
else if (opcode === 0x68)
|
|
631
|
+
minimum = 10;
|
|
632
|
+
if (version < minimum) {
|
|
633
|
+
invalidScript(`opcode ${opcode} is not supported in bytecode version ${version}`);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Structurally consumes one instruction from bytecode versions 1-10.
|
|
638
|
+
*
|
|
639
|
+
* This is deliberately not a semantic bytecode verifier: it recognizes every instruction encoding
|
|
640
|
+
* and validates signature operands needed for ABI-safe parsing, but leaves stack, branch, local,
|
|
641
|
+
* and module-only table semantics to the Move verifier.
|
|
642
|
+
*/
|
|
643
|
+
function parseInstruction(reader, version, signatures, instructionIndex) {
|
|
644
|
+
const opcode = reader.readU8(`instruction ${instructionIndex} opcode`);
|
|
645
|
+
if (opcode < 1 || opcode > 0x68) {
|
|
646
|
+
invalidScript(`unknown opcode ${opcode}`);
|
|
647
|
+
}
|
|
648
|
+
requireOpcodeVersion(opcode, version);
|
|
649
|
+
if (opcode === 0x31 || opcode === 0x5b) {
|
|
650
|
+
reader.readBytes(1, `instruction ${instructionIndex} operand`);
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
if (opcode === 0x48 || opcode === 0x5c) {
|
|
654
|
+
reader.readBytes(2, `instruction ${instructionIndex} operand`);
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
if (opcode === 0x49 || opcode === 0x5d) {
|
|
658
|
+
reader.readBytes(4, `instruction ${instructionIndex} operand`);
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
if (opcode === 0x06 || opcode === 0x5e) {
|
|
662
|
+
reader.readBytes(8, `instruction ${instructionIndex} operand`);
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
if (opcode === 0x32 || opcode === 0x5f) {
|
|
666
|
+
reader.readBytes(16, `instruction ${instructionIndex} operand`);
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
if (opcode === 0x4a || opcode === 0x60) {
|
|
670
|
+
reader.readBytes(32, `instruction ${instructionIndex} operand`);
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
if (opcode === 0x40 || opcode === 0x46) {
|
|
674
|
+
const signature = reader.readUleb128(`instruction ${instructionIndex} signature index`, TABLE_INDEX_MAX);
|
|
675
|
+
indexed(signatures, signature, "instruction signature");
|
|
676
|
+
reader.readBytes(8, `instruction ${instructionIndex} vector count`);
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
if (opcode === 0x58 || opcode === 0x59) {
|
|
680
|
+
reader.readUleb128(`instruction ${instructionIndex} function index`, TABLE_INDEX_MAX);
|
|
681
|
+
reader.readUleb128U64(`instruction ${instructionIndex} closure mask`);
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
if (opcode >= 0x0a && opcode <= 0x0e) {
|
|
685
|
+
reader.readUleb128(`instruction ${instructionIndex} local index`, 255);
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
const hasIndexOperand = (opcode >= 0x03 && opcode <= 0x05) ||
|
|
689
|
+
opcode === 0x07 ||
|
|
690
|
+
(opcode >= 0x0f && opcode <= 0x13) ||
|
|
691
|
+
(opcode >= 0x29 && opcode <= 0x2d) ||
|
|
692
|
+
(opcode >= 0x36 && opcode <= 0x3f) ||
|
|
693
|
+
(opcode >= 0x41 && opcode <= 0x45) ||
|
|
694
|
+
opcode === 0x47 ||
|
|
695
|
+
(opcode >= 0x4e && opcode <= 0x57) ||
|
|
696
|
+
opcode === 0x5a;
|
|
697
|
+
if (hasIndexOperand) {
|
|
698
|
+
const index = reader.readUleb128(`instruction ${instructionIndex} index`, TABLE_INDEX_MAX);
|
|
699
|
+
if ((opcode >= 0x41 && opcode <= 0x47) || opcode === 0x5a) {
|
|
700
|
+
indexed(signatures, index, "instruction signature");
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
function parseCodeUnit(reader, version, signatures) {
|
|
705
|
+
const locals = reader.readUleb128("code unit locals signature index", TABLE_INDEX_MAX);
|
|
706
|
+
indexed(signatures, locals, "code unit locals signature");
|
|
707
|
+
const instructionCount = reader.readUleb128("instruction count", BYTECODE_COUNT_MAX);
|
|
708
|
+
for (let index = 0; index < instructionCount; index += 1) {
|
|
709
|
+
parseInstruction(reader, version, signatures, index);
|
|
710
|
+
}
|
|
711
|
+
return locals;
|
|
712
|
+
}
|
|
713
|
+
function resolveSignatureToken(token, typeParameterCount, structHandles, moduleHandles, identifiers, addresses) {
|
|
714
|
+
switch (token.kind) {
|
|
715
|
+
case "bool":
|
|
716
|
+
return new TypeTagBool();
|
|
717
|
+
case "u8":
|
|
718
|
+
return new TypeTagU8();
|
|
719
|
+
case "u16":
|
|
720
|
+
return new TypeTagU16();
|
|
721
|
+
case "u32":
|
|
722
|
+
return new TypeTagU32();
|
|
723
|
+
case "u64":
|
|
724
|
+
return new TypeTagU64();
|
|
725
|
+
case "u128":
|
|
726
|
+
return new TypeTagU128();
|
|
727
|
+
case "u256":
|
|
728
|
+
return new TypeTagU256();
|
|
729
|
+
case "i8":
|
|
730
|
+
return new TypeTagI8();
|
|
731
|
+
case "i16":
|
|
732
|
+
return new TypeTagI16();
|
|
733
|
+
case "i32":
|
|
734
|
+
return new TypeTagI32();
|
|
735
|
+
case "i64":
|
|
736
|
+
return new TypeTagI64();
|
|
737
|
+
case "i128":
|
|
738
|
+
return new TypeTagI128();
|
|
739
|
+
case "i256":
|
|
740
|
+
return new TypeTagI256();
|
|
741
|
+
case "address":
|
|
742
|
+
return new TypeTagAddress();
|
|
743
|
+
case "signer":
|
|
744
|
+
return new TypeTagSigner();
|
|
745
|
+
case "vector":
|
|
746
|
+
return new TypeTagVector(resolveSignatureToken(token.value, typeParameterCount, structHandles, moduleHandles, identifiers, addresses));
|
|
747
|
+
case "reference":
|
|
748
|
+
return new TypeTagReference(resolveSignatureToken(token.value, typeParameterCount, structHandles, moduleHandles, identifiers, addresses));
|
|
749
|
+
case "typeParameter":
|
|
750
|
+
if (token.index >= typeParameterCount) {
|
|
751
|
+
invalidScript(`type parameter index ${token.index} does not exist`);
|
|
752
|
+
}
|
|
753
|
+
return new TypeTagGeneric(token.index);
|
|
754
|
+
case "struct": {
|
|
755
|
+
const structHandle = indexed(structHandles, token.index, "struct handle");
|
|
756
|
+
if (token.typeArguments.length !== structHandle.typeParameterCount) {
|
|
757
|
+
invalidScript(`struct handle index ${token.index} expects ${structHandle.typeParameterCount} type arguments, received ${token.typeArguments.length}`);
|
|
758
|
+
}
|
|
759
|
+
const moduleHandle = indexed(moduleHandles, structHandle.module, "module handle");
|
|
760
|
+
const address = indexed(addresses, moduleHandle.address, "address");
|
|
761
|
+
const moduleName = indexed(identifiers, moduleHandle.name, "identifier");
|
|
762
|
+
const structName = indexed(identifiers, structHandle.name, "identifier");
|
|
763
|
+
const typeArguments = token.typeArguments.map((argument) => resolveSignatureToken(argument, typeParameterCount, structHandles, moduleHandles, identifiers, addresses));
|
|
764
|
+
return new TypeTagStruct(new StructTag(new AccountAddress(address), new Identifier(moduleName), new Identifier(structName), typeArguments));
|
|
765
|
+
}
|
|
766
|
+
case "function":
|
|
767
|
+
return invalidScript("function signature tokens cannot be represented as TypeTag values");
|
|
768
|
+
default:
|
|
769
|
+
return invalidScript("unknown signature token");
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
function isSignerToken(token) {
|
|
773
|
+
return token.kind === "signer" || (token.kind === "reference" && token.value.kind === "signer");
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Extracts a transaction script's type parameters and parameter types from compiled Move bytecode.
|
|
777
|
+
*
|
|
778
|
+
* @param bytecode - Compiled Move script bytecode.
|
|
779
|
+
* @returns The script ABI needed to prepare caller-supplied arguments.
|
|
780
|
+
*/
|
|
781
|
+
export function parseScriptAbi(bytecode) {
|
|
782
|
+
let bytes;
|
|
783
|
+
try {
|
|
784
|
+
bytes = Hex.hexInputToUint8Array(bytecode);
|
|
785
|
+
}
|
|
786
|
+
catch (error) {
|
|
787
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
788
|
+
invalidScript(`invalid hex input: ${reason}`);
|
|
789
|
+
}
|
|
790
|
+
const reader = new ScriptBytecodeReader(bytes);
|
|
791
|
+
const magic = reader.readBytes(MOVE_MAGIC.length, "magic");
|
|
792
|
+
if (!MOVE_MAGIC.every((value, index) => magic[index] === value)) {
|
|
793
|
+
invalidScript("incorrect magic bytes");
|
|
794
|
+
}
|
|
795
|
+
const encodedVersion = reader.readU32("bytecode version");
|
|
796
|
+
const version = encodedVersion & ~APTOS_BYTECODE_VERSION_MASK;
|
|
797
|
+
if (version < MIN_BYTECODE_VERSION || version > MAX_BYTECODE_VERSION) {
|
|
798
|
+
invalidScript(`bytecode version ${version} is not supported`);
|
|
799
|
+
}
|
|
800
|
+
const { headers, contentLength } = parseTableHeaders(reader);
|
|
801
|
+
const tableContents = reader.subReader(0, contentLength, "table contents");
|
|
802
|
+
reader.readBytes(contentLength, "table contents");
|
|
803
|
+
const identifiers = parseIdentifiers(tableReader(tableContents, headers, 7 /* TableType.Identifiers */), version);
|
|
804
|
+
const addresses = parseAddresses(tableReader(tableContents, headers, 8 /* TableType.AddressIdentifiers */));
|
|
805
|
+
const moduleHandles = parseModuleHandles(tableReader(tableContents, headers, 1 /* TableType.ModuleHandles */));
|
|
806
|
+
const structHandles = parseStructHandles(tableReader(tableContents, headers, 2 /* TableType.StructHandles */), version);
|
|
807
|
+
const signatures = parseSignatures(tableReader(tableContents, headers, 5 /* TableType.Signatures */), version);
|
|
808
|
+
const functionHandles = parseFunctionHandles(tableReader(tableContents, headers, 3 /* TableType.FunctionHandles */), version);
|
|
809
|
+
const functionInstantiations = parseFunctionInstantiations(tableReader(tableContents, headers, 4 /* TableType.FunctionInstantiations */));
|
|
810
|
+
const constantTypes = parseConstants(tableReader(tableContents, headers, 6 /* TableType.ConstantPool */), version);
|
|
811
|
+
parseMetadata(tableReader(tableContents, headers, 16 /* TableType.Metadata */), version);
|
|
812
|
+
for (const moduleHandle of moduleHandles) {
|
|
813
|
+
indexed(addresses, moduleHandle.address, "module handle address");
|
|
814
|
+
indexed(identifiers, moduleHandle.name, "module handle identifier");
|
|
815
|
+
}
|
|
816
|
+
for (const structHandle of structHandles) {
|
|
817
|
+
indexed(moduleHandles, structHandle.module, "struct handle module");
|
|
818
|
+
indexed(identifiers, structHandle.name, "struct handle identifier");
|
|
819
|
+
}
|
|
820
|
+
for (const signature of signatures) {
|
|
821
|
+
validateSignature(signature, structHandles, moduleHandles, identifiers, addresses);
|
|
822
|
+
}
|
|
823
|
+
for (const type of constantTypes) {
|
|
824
|
+
validateSignatureToken(type, structHandles, moduleHandles, identifiers, addresses);
|
|
825
|
+
}
|
|
826
|
+
for (const functionHandle of functionHandles) {
|
|
827
|
+
indexed(moduleHandles, functionHandle.module, "function handle module");
|
|
828
|
+
indexed(identifiers, functionHandle.name, "function handle identifier");
|
|
829
|
+
validateSignature(indexed(signatures, functionHandle.parameters, "function handle parameter signature"), structHandles, moduleHandles, identifiers, addresses, functionHandle.typeParameterCount);
|
|
830
|
+
validateSignature(indexed(signatures, functionHandle.returns, "function handle return signature"), structHandles, moduleHandles, identifiers, addresses, functionHandle.typeParameterCount);
|
|
831
|
+
validateAccessReferences(functionHandle.accessReferences, addresses, moduleHandles, structHandles, signatures, functionInstantiations);
|
|
832
|
+
}
|
|
833
|
+
for (const instantiation of functionInstantiations) {
|
|
834
|
+
indexed(functionHandles, instantiation.handle, "function instantiation handle");
|
|
835
|
+
indexed(signatures, instantiation.typeParameters, "function instantiation signature");
|
|
836
|
+
}
|
|
837
|
+
const typeParameterCount = reader.readUleb128("script type parameter count", TYPE_PARAMETER_COUNT_MAX);
|
|
838
|
+
const typeParameters = Array.from({ length: typeParameterCount }, () => ({
|
|
839
|
+
constraints: decodeAbilities(readVersionedAbilitySet(reader, version, "functionTypeParameter")),
|
|
840
|
+
}));
|
|
841
|
+
const parameterSignatureIndex = reader.readUleb128("parameter signature index", TABLE_INDEX_MAX);
|
|
842
|
+
const parameterTokens = indexed(signatures, parameterSignatureIndex, "parameter signature");
|
|
843
|
+
const accessReferences = version >= 8 ? parseAccessSpecifiers(reader) : [];
|
|
844
|
+
const localsSignatureIndex = parseCodeUnit(reader, version, signatures);
|
|
845
|
+
if (reader.remaining !== 0) {
|
|
846
|
+
invalidScript(`${reader.remaining} trailing byte(s) after the code unit`);
|
|
847
|
+
}
|
|
848
|
+
validateAccessReferences(accessReferences, addresses, moduleHandles, structHandles, signatures, functionInstantiations);
|
|
849
|
+
validateSignature(parameterTokens, structHandles, moduleHandles, identifiers, addresses, typeParameterCount);
|
|
850
|
+
validateSignature(indexed(signatures, localsSignatureIndex, "code unit locals signature"), structHandles, moduleHandles, identifiers, addresses, typeParameterCount);
|
|
851
|
+
for (const instantiation of functionInstantiations) {
|
|
852
|
+
validateSignature(indexed(signatures, instantiation.typeParameters, "function instantiation signature"), structHandles, moduleHandles, identifiers, addresses, typeParameterCount);
|
|
853
|
+
}
|
|
854
|
+
let signers = 0;
|
|
855
|
+
while (signers < parameterTokens.length && isSignerToken(parameterTokens[signers])) {
|
|
856
|
+
signers += 1;
|
|
857
|
+
}
|
|
858
|
+
const parameters = parameterTokens
|
|
859
|
+
.slice(signers)
|
|
860
|
+
.map((token) => resolveSignatureToken(token, typeParameterCount, structHandles, moduleHandles, identifiers, addresses));
|
|
861
|
+
return { typeParameters, parameters, signers };
|
|
862
|
+
}
|
|
863
|
+
//# sourceMappingURL=scriptAbi.js.map
|