@cashscript/utils 0.13.0-next.6 → 0.13.0-next.8
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/artifact.d.ts +2 -0
- package/dist/data.d.ts +1 -0
- package/dist/data.js +7 -1
- package/dist/fingerprint.d.ts +5 -0
- package/dist/fingerprint.js +50 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/script.js +2 -0
- package/package.json +2 -2
package/dist/artifact.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export interface CompilerOptions {
|
|
2
2
|
enforceFunctionParameterTypes?: boolean;
|
|
3
|
+
enforceLocktimeGuard?: boolean;
|
|
3
4
|
}
|
|
4
5
|
export interface AbiInput {
|
|
5
6
|
name: string;
|
|
@@ -46,5 +47,6 @@ export interface Artifact {
|
|
|
46
47
|
options?: CompilerOptions;
|
|
47
48
|
};
|
|
48
49
|
updatedAt: string;
|
|
50
|
+
fingerprint?: string;
|
|
49
51
|
}
|
|
50
52
|
export declare function formatArtifact(artifact: Artifact, format: 'json' | 'ts'): string;
|
package/dist/data.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare function encodeBool(bool: boolean): Uint8Array;
|
|
2
2
|
export declare function decodeBool(encodedBool: Uint8Array): boolean;
|
|
3
3
|
export declare function encodeInt(int: bigint): Uint8Array;
|
|
4
|
+
export declare function encodeIntAsFixedBytes(int: bigint, byteLength: number): Uint8Array;
|
|
4
5
|
export declare function decodeInt(encodedInt: Uint8Array, maxLength?: number): bigint;
|
|
5
6
|
export declare function encodeString(str: string): Uint8Array;
|
|
6
7
|
export declare function decodeString(encodedString: Uint8Array): string;
|
package/dist/data.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { bigIntToVmNumber, utf8ToBin, binToUtf8, vmNumberToBigInt, isVmNumberError, } from '@bitauth/libauth';
|
|
1
|
+
import { bigIntToVmNumber, utf8ToBin, binToUtf8, vmNumberToBigInt, isVmNumberError, padMinimallyEncodedVmNumber, } from '@bitauth/libauth';
|
|
2
2
|
export function encodeBool(bool) {
|
|
3
3
|
return bool ? encodeInt(1n) : encodeInt(0n);
|
|
4
4
|
}
|
|
@@ -17,6 +17,12 @@ export function decodeBool(encodedBool) {
|
|
|
17
17
|
export function encodeInt(int) {
|
|
18
18
|
return bigIntToVmNumber(int);
|
|
19
19
|
}
|
|
20
|
+
export function encodeIntAsFixedBytes(int, byteLength) {
|
|
21
|
+
const minimal = encodeInt(int);
|
|
22
|
+
if (minimal.length > byteLength)
|
|
23
|
+
throw new Error('value exceeds the requested byteLength');
|
|
24
|
+
return padMinimallyEncodedVmNumber(minimal, byteLength);
|
|
25
|
+
}
|
|
20
26
|
export function decodeInt(encodedInt, maxLength = Infinity) {
|
|
21
27
|
const options = { maximumVmNumberByteLength: maxLength };
|
|
22
28
|
const result = vmNumberToBigInt(encodedInt, options);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Op, Script } from './script.js';
|
|
2
|
+
export declare function computeBytecodePattern(bytecode: Uint8Array): Uint8Array;
|
|
3
|
+
export declare function computeBytecodeFingerprint(bytecode: Uint8Array): string;
|
|
4
|
+
export declare function computeBytecodeFingerprintWithConstructorArgs(bytecodeScript: Script, constructorArgsCount: number): string;
|
|
5
|
+
export declare function isPushOpcode(opcode: Op): boolean;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { binToHex, decodeAuthenticationInstructions, encodeDataPush, flattenBinArray, isPushOperation, } from '@bitauth/libauth';
|
|
2
|
+
import { encodeInt } from './data.js';
|
|
3
|
+
import { sha256 } from './hash.js';
|
|
4
|
+
import { generateContractBytecodeScript, Op, scriptToBytecode } from './script.js';
|
|
5
|
+
// Transform locking bytecode into the normalized "pattern" form: every run of
|
|
6
|
+
// consecutive push instructions is replaced by a single push of the run length.
|
|
7
|
+
// See: https://gitlab.com/0353F40E/smart-contract-fingerprinting/
|
|
8
|
+
export function computeBytecodePattern(bytecode) {
|
|
9
|
+
const opcodes = decodeAuthenticationInstructions(bytecode).map((instruction) => instruction.opcode);
|
|
10
|
+
const chunks = groupByPushRun(opcodes).map((run) => (isPushOpcode(run[0]) ? encodePushCount(run.length) : Uint8Array.from(run)));
|
|
11
|
+
return flattenBinArray(chunks);
|
|
12
|
+
}
|
|
13
|
+
// Split opcodes into consecutive runs that are either all pushes or all non-pushes.
|
|
14
|
+
function groupByPushRun(opcodes) {
|
|
15
|
+
return opcodes.reduce((opcodeRuns, opcode) => {
|
|
16
|
+
const lastOpcodeRun = opcodeRuns.at(-1);
|
|
17
|
+
// If ther are no runs yet, start a new run with the current opcode
|
|
18
|
+
if (!lastOpcodeRun)
|
|
19
|
+
return [[opcode]];
|
|
20
|
+
// If the last run is the same type of opcode as the current opcode, add the current opcode to the last run
|
|
21
|
+
// Else, start a new run with the current opcode
|
|
22
|
+
if (isPushOpcode(lastOpcodeRun[0]) === isPushOpcode(opcode)) {
|
|
23
|
+
lastOpcodeRun.push(opcode);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
opcodeRuns.push([opcode]);
|
|
27
|
+
}
|
|
28
|
+
return opcodeRuns;
|
|
29
|
+
}, []);
|
|
30
|
+
}
|
|
31
|
+
// Compute the SHA256 fingerprint of the normalized bytecode pattern, returned as hex.
|
|
32
|
+
export function computeBytecodeFingerprint(bytecode) {
|
|
33
|
+
return binToHex(sha256(computeBytecodePattern(bytecode)));
|
|
34
|
+
}
|
|
35
|
+
// Add placeholder constructor arguments to the bytecode script and compute the fingerprint.
|
|
36
|
+
export function computeBytecodeFingerprintWithConstructorArgs(bytecodeScript, constructorArgsCount) {
|
|
37
|
+
const placeholderConstructorArgs = new Array(constructorArgsCount).fill(0);
|
|
38
|
+
const bytecodeWithConstructorArgs = generateContractBytecodeScript(bytecodeScript, placeholderConstructorArgs);
|
|
39
|
+
return computeBytecodeFingerprint(scriptToBytecode(bytecodeWithConstructorArgs));
|
|
40
|
+
}
|
|
41
|
+
// Note: libauth's isPushOperation also matches OP_RESERVED (0x50) — the spec excludes it.
|
|
42
|
+
export function isPushOpcode(opcode) {
|
|
43
|
+
return isPushOperation(opcode) && opcode !== Op.OP_RESERVED;
|
|
44
|
+
}
|
|
45
|
+
// Encode a push count using the smallest possible push encoding.
|
|
46
|
+
// libauth's encodeDataPush minimally encodes VM Numbers in the -1..16 range as OP_N.
|
|
47
|
+
function encodePushCount(count) {
|
|
48
|
+
return encodeDataPush(encodeInt(BigInt(count)));
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=fingerprint.js.map
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/script.js
CHANGED
|
@@ -37,6 +37,8 @@ export function bytecodeToScript(bytecode) {
|
|
|
37
37
|
export function asmToBytecode(asm) {
|
|
38
38
|
// Remove any duplicate whitespace
|
|
39
39
|
asm = asm.replace(/\s+/g, ' ').trim();
|
|
40
|
+
if (asm === '')
|
|
41
|
+
return new Uint8Array();
|
|
40
42
|
// Convert the ASM tokens to AuthenticationInstructions
|
|
41
43
|
const instructions = asm.split(' ').map((token) => {
|
|
42
44
|
// Even though the OpcodesBch type allows for { [key: number]: string }, we know that the keys are always the opcodes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cashscript/utils",
|
|
3
|
-
"version": "0.13.0-next.
|
|
3
|
+
"version": "0.13.0-next.8",
|
|
4
4
|
"description": "CashScript utilities and types",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bitcoin cash",
|
|
@@ -48,5 +48,5 @@
|
|
|
48
48
|
"typescript": "^5.9.2",
|
|
49
49
|
"vitest": "^4.0.15"
|
|
50
50
|
},
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "579998062f2f9c52393568b09b580407228cb79f"
|
|
52
52
|
}
|