ox 1.2.0 → 1.3.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/CHANGELOG.md +34 -0
- package/dist/core/AbiFunction.d.ts +1 -1
- package/dist/core/AbiFunction.d.ts.map +1 -1
- package/dist/core/AbiFunction.js +6 -2
- package/dist/core/AbiFunction.js.map +1 -1
- package/dist/core/AbiParameters.d.ts +1 -1
- package/dist/core/AbiParameters.d.ts.map +1 -1
- package/dist/core/AbiParameters.js +1 -13
- package/dist/core/AbiParameters.js.map +1 -1
- package/dist/core/AesGcm.d.ts +36 -1
- package/dist/core/AesGcm.d.ts.map +1 -1
- package/dist/core/AesGcm.js +44 -0
- package/dist/core/AesGcm.js.map +1 -1
- package/dist/core/Ed25519.d.ts +46 -1
- package/dist/core/Ed25519.d.ts.map +1 -1
- package/dist/core/Ed25519.js +43 -0
- package/dist/core/Ed25519.js.map +1 -1
- package/dist/core/Engine.d.ts +1 -1
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Hash.d.ts +164 -1
- package/dist/core/Hash.d.ts.map +1 -1
- package/dist/core/Hash.js +172 -0
- package/dist/core/Hash.js.map +1 -1
- package/dist/core/Hex.d.ts.map +1 -1
- package/dist/core/Hex.js +1 -4
- package/dist/core/Hex.js.map +1 -1
- package/dist/core/Rlp.d.ts +32 -0
- package/dist/core/Rlp.d.ts.map +1 -1
- package/dist/core/Rlp.js +146 -0
- package/dist/core/Rlp.js.map +1 -1
- package/dist/core/Secp256k1.d.ts +46 -1
- package/dist/core/Secp256k1.d.ts.map +1 -1
- package/dist/core/Secp256k1.js +48 -0
- package/dist/core/Secp256k1.js.map +1 -1
- package/dist/core/WebAuthn.d.ts +224 -0
- package/dist/core/WebAuthn.d.ts.map +1 -0
- package/dist/core/WebAuthn.js +343 -0
- package/dist/core/WebAuthn.js.map +1 -0
- package/dist/core/WebAuthnP256.d.ts +46 -50
- package/dist/core/WebAuthnP256.d.ts.map +1 -1
- package/dist/core/WebAuthnP256.js +44 -50
- package/dist/core/WebAuthnP256.js.map +1 -1
- package/dist/core/internal/abiParameters.d.ts +7 -87
- package/dist/core/internal/abiParameters.d.ts.map +1 -1
- package/dist/core/internal/abiParameters.js +339 -194
- package/dist/core/internal/abiParameters.js.map +1 -1
- package/dist/core/internal/engine.d.ts +35 -2
- package/dist/core/internal/engine.d.ts.map +1 -1
- package/dist/core/internal/engine.js +12 -1
- package/dist/core/internal/engine.js.map +1 -1
- package/dist/core/internal/hash.d.ts +10 -0
- package/dist/core/internal/hash.d.ts.map +1 -1
- package/dist/core/internal/hash.js +26 -1
- package/dist/core/internal/hash.js.map +1 -1
- package/dist/index.d.ts +23 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -14
- package/dist/index.js.map +1 -1
- package/dist/node/Engine.d.ts +1 -1
- package/dist/node/Engine.d.ts.map +1 -1
- package/dist/node/Engine.js.map +1 -1
- package/dist/node/Hash.d.ts +6 -4
- package/dist/node/Hash.d.ts.map +1 -1
- package/dist/node/Hash.js +35 -3
- package/dist/node/Hash.js.map +1 -1
- package/dist/tempo/AuthorizationTempo.d.ts +6 -6
- package/dist/tempo/AuthorizationTempo.js +6 -6
- package/dist/tempo/KeyAuthorization.d.ts +3 -8
- package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
- package/dist/tempo/KeyAuthorization.js +3 -8
- package/dist/tempo/KeyAuthorization.js.map +1 -1
- package/dist/tempo/SignatureEnvelope.d.ts +8 -8
- package/dist/tempo/SignatureEnvelope.js +8 -8
- package/dist/wasm/Engine.d.ts +1 -1
- package/dist/wasm/Engine.d.ts.map +1 -1
- package/dist/wasm/Engine.js.map +1 -1
- package/dist/wasm/Hash.d.ts +1 -1
- package/dist/wasm/Hash.d.ts.map +1 -1
- package/dist/wasm/Hash.js +5 -0
- package/dist/wasm/Hash.js.map +1 -1
- package/dist/wasm/internal/blake3.d.ts +10 -1
- package/dist/wasm/internal/blake3.d.ts.map +1 -1
- package/dist/wasm/internal/blake3.js +12 -1
- package/dist/wasm/internal/blake3.js.map +1 -1
- package/dist/wasm/internal/blake3.wasm.d.ts +3 -1
- package/dist/wasm/internal/blake3.wasm.d.ts.map +1 -1
- package/dist/wasm/internal/blake3.wasm.js +3 -1
- package/dist/wasm/internal/blake3.wasm.js.map +1 -1
- package/dist/wasm/internal/hash.d.ts +9 -0
- package/dist/wasm/internal/hash.d.ts.map +1 -1
- package/dist/wasm/internal/hash.js +13 -1
- package/dist/wasm/internal/hash.js.map +1 -1
- package/dist/wasm/internal/hashState.d.ts +25 -0
- package/dist/wasm/internal/hashState.d.ts.map +1 -0
- package/dist/wasm/internal/hashState.js +105 -0
- package/dist/wasm/internal/hashState.js.map +1 -0
- package/dist/wasm/internal/hashes.d.ts +12 -1
- package/dist/wasm/internal/hashes.d.ts.map +1 -1
- package/dist/wasm/internal/hashes.js +18 -1
- package/dist/wasm/internal/hashes.js.map +1 -1
- package/dist/wasm/internal/hashes.wasm.d.ts +11 -3
- package/dist/wasm/internal/hashes.wasm.d.ts.map +1 -1
- package/dist/wasm/internal/hashes.wasm.js +11 -3
- package/dist/wasm/internal/hashes.wasm.js.map +1 -1
- package/dist/webauthn/Authentication.d.ts +2 -0
- package/dist/webauthn/Authentication.d.ts.map +1 -1
- package/dist/webauthn/Authentication.js +2 -1
- package/dist/webauthn/Authentication.js.map +1 -1
- package/dist/webauthn/Registration.d.ts.map +1 -1
- package/dist/webauthn/Registration.js +2 -1
- package/dist/webauthn/Registration.js.map +1 -1
- package/dist/webauthn/Types.d.ts +27 -6
- package/dist/webauthn/Types.d.ts.map +1 -1
- package/dist/webauthn/internal/utils.d.ts.map +1 -1
- package/dist/webauthn/internal/utils.js +35 -9
- package/dist/webauthn/internal/utils.js.map +1 -1
- package/dist/zod/TypedData.d.ts +2 -2
- package/package.json +9 -1
- package/src/benchmarks/Ox.bench.ts +6 -0
- package/src/benchmarks/OxNode.bench.ts +8 -0
- package/src/benchmarks/OxV0.bench.ts +4 -0
- package/src/benchmarks/OxWasm.bench.ts +22 -0
- package/src/core/AbiFunction.ts +5 -5
- package/src/core/AbiParameters.ts +8 -20
- package/src/core/AesGcm.ts +86 -1
- package/src/core/Ed25519.ts +87 -1
- package/src/core/Engine.ts +1 -0
- package/src/core/Hash.ts +262 -1
- package/src/core/Hex.ts +1 -4
- package/src/core/Rlp.ts +172 -5
- package/src/core/Secp256k1.ts +92 -1
- package/src/core/WebAuthn.ts +579 -0
- package/src/core/WebAuthnP256.ts +47 -50
- package/src/core/_test/AbiFunction.test.ts +9 -0
- package/src/core/_test/AbiParameters.differential.fuzz.ts +156 -0
- package/src/core/_test/AbiParameters.encode.test.ts +22 -0
- package/src/core/_test/AbiParameters.fuzz.ts +4 -0
- package/src/core/_test/AesGcm.test.ts +76 -0
- package/src/core/_test/Ed25519.test-d.ts +13 -1
- package/src/core/_test/Ed25519.test.ts +120 -1
- package/src/core/_test/Engine.test-d.ts +9 -0
- package/src/core/_test/Engine.test.ts +1 -1
- package/src/core/_test/Hash.test-d.ts +23 -0
- package/src/core/_test/Hash.test.ts +179 -1
- package/src/core/_test/Hex.test.ts +2 -0
- package/src/core/_test/Rlp.test-d.ts +18 -0
- package/src/core/_test/Rlp.test.ts +109 -0
- package/src/core/_test/Secp256k1.test-d.ts +14 -0
- package/src/core/_test/Secp256k1.test.ts +91 -1
- package/src/core/_test/WebAuthn.test-d.ts +142 -0
- package/src/core/_test/WebAuthn.test.ts +766 -0
- package/src/core/_test/index.test.ts +1 -0
- package/src/core/internal/abiParameters.ts +466 -326
- package/src/core/internal/engine.ts +47 -2
- package/src/core/internal/hash.ts +53 -1
- package/src/index.ts +24 -14
- package/src/node/Engine.ts +1 -0
- package/src/node/Hash.ts +43 -6
- package/src/node/_test/Engine.test-d.ts +1 -0
- package/src/node/_test/Engine.test.ts +2 -0
- package/src/node/_test/Hash.test-d.ts +10 -0
- package/src/node/_test/Hash.test.ts +46 -0
- package/src/tempo/AuthorizationTempo.ts +6 -6
- package/src/tempo/KeyAuthorization.ts +3 -8
- package/src/tempo/SignatureEnvelope.ts +8 -8
- package/src/version.ts +1 -1
- package/src/wasm/Engine.ts +1 -0
- package/src/wasm/Hash.ts +10 -0
- package/src/wasm/_test/Engine.test-d.ts +1 -0
- package/src/wasm/_test/Engine.test.ts +5 -0
- package/src/wasm/_test/Hash.browser.test.ts +28 -0
- package/src/wasm/_test/Hash.test-d.ts +16 -0
- package/src/wasm/_test/Hash.test.ts +250 -1
- package/src/wasm/internal/blake3.ts +23 -2
- package/src/wasm/internal/blake3.wasm.ts +4 -1
- package/src/wasm/internal/hash.ts +27 -1
- package/src/wasm/internal/hashState.ts +154 -0
- package/src/wasm/internal/hashes.ts +56 -15
- package/src/wasm/internal/hashes.wasm.ts +15 -3
- package/src/webauthn/Authentication.ts +4 -0
- package/src/webauthn/Registration.ts +2 -0
- package/src/webauthn/Types.ts +32 -2
- package/src/webauthn/_test/Authentication.test.ts +123 -1
- package/src/webauthn/_test/Registration.test.ts +26 -6
- package/src/webauthn/_test/WebAuthn.browser.test.ts +28 -0
- package/src/webauthn/internal/utils.ts +41 -8
|
@@ -9,7 +9,8 @@ import * as Address from '../Address.js'
|
|
|
9
9
|
import * as Bytes from '../Bytes.js'
|
|
10
10
|
import * as Errors from '../Errors.js'
|
|
11
11
|
import * as Hex from '../Hex.js'
|
|
12
|
-
import { integerRegex } from '../Solidity.js'
|
|
12
|
+
import { bytesRegex, integerRegex } from '../Solidity.js'
|
|
13
|
+
import { encoder } from './codec/utf8.js'
|
|
13
14
|
import type * as Cursor from './cursor.js'
|
|
14
15
|
import type { Compute, IsNarrowable, UnionToIntersection } from './types.js'
|
|
15
16
|
|
|
@@ -19,8 +20,61 @@ export type ParameterToPrimitiveType<
|
|
|
19
20
|
abiParameterKind extends AbiParameterKind = AbiParameterKind,
|
|
20
21
|
> = AbiParameterToPrimitiveType<abiParameter, abiParameterKind>
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
type CompiledParameterBase = {
|
|
24
|
+
dynamic: boolean
|
|
25
|
+
name: string | undefined
|
|
26
|
+
staticSize: number
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type CompiledArray = CompiledParameterBase & {
|
|
30
|
+
child: CompiledParameter
|
|
31
|
+
kind: 'array'
|
|
32
|
+
length: number | null
|
|
33
|
+
type: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type CompiledBytes = CompiledParameterBase & {
|
|
37
|
+
kind: 'bytes'
|
|
38
|
+
size: number | null
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type CompiledInteger = CompiledParameterBase & {
|
|
42
|
+
kind: 'integer'
|
|
43
|
+
max: bigint
|
|
44
|
+
min: bigint
|
|
45
|
+
signed: boolean
|
|
46
|
+
size: number
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
type CompiledTuple = CompiledParameterBase & {
|
|
50
|
+
children: readonly CompiledParameter[]
|
|
51
|
+
kind: 'tuple'
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
type CompiledParameter =
|
|
55
|
+
| CompiledArray
|
|
56
|
+
| CompiledBytes
|
|
57
|
+
| CompiledInteger
|
|
58
|
+
| CompiledTuple
|
|
59
|
+
| (CompiledParameterBase & {
|
|
60
|
+
kind: 'address' | 'boolean' | 'invalid' | 'string'
|
|
61
|
+
type?: string | undefined
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
type MeasureContext = {
|
|
65
|
+
checksumAddress: boolean
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
type HexPatch = {
|
|
69
|
+
offset: number
|
|
70
|
+
value: string
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
type WriteContext = {
|
|
74
|
+
bytes: Bytes.Bytes
|
|
75
|
+
patches: HexPatch[]
|
|
76
|
+
view: DataView
|
|
77
|
+
}
|
|
24
78
|
|
|
25
79
|
/** @internal */
|
|
26
80
|
export type ToObject<
|
|
@@ -423,385 +477,471 @@ export declare namespace decodeString {
|
|
|
423
477
|
}
|
|
424
478
|
|
|
425
479
|
/** @internal */
|
|
426
|
-
export function
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
480
|
+
export function encodeParameters(
|
|
481
|
+
parameters: readonly AbiParameters.Parameter[],
|
|
482
|
+
values: readonly unknown[],
|
|
483
|
+
options: encodeParameters.Options = {},
|
|
484
|
+
): Hex.Hex {
|
|
485
|
+
const { checksumAddress = false, prefix } = options
|
|
486
|
+
|
|
487
|
+
if (parameters.length !== values.length)
|
|
488
|
+
throw new AbiParameters.LengthMismatchError({
|
|
489
|
+
expectedLength: parameters.length,
|
|
490
|
+
givenLength: values.length,
|
|
491
|
+
})
|
|
492
|
+
|
|
493
|
+
// Compile the wire shape before walking values so recursive writes only
|
|
494
|
+
// handle offsets and data.
|
|
495
|
+
const compiled = compileParameters(parameters)
|
|
496
|
+
const context: MeasureContext = {
|
|
497
|
+
checksumAddress,
|
|
498
|
+
}
|
|
499
|
+
const size = measureParameters(compiled, values, context)
|
|
500
|
+
|
|
501
|
+
const prefixSize = prefix ? Hex.size(prefix) : 0
|
|
502
|
+
const bytes = new Uint8Array(prefixSize + size)
|
|
503
|
+
const writer: WriteContext = {
|
|
504
|
+
bytes,
|
|
505
|
+
patches: [],
|
|
506
|
+
view: new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength),
|
|
448
507
|
}
|
|
449
|
-
|
|
508
|
+
|
|
509
|
+
if (prefix) writeHex(writer, 0, prefix)
|
|
510
|
+
writeParameters(writer, prefixSize, compiled, values)
|
|
511
|
+
|
|
512
|
+
let data = Hex.fromBytes(bytes)
|
|
513
|
+
for (let i = 0; i < writer.patches.length; i++) {
|
|
514
|
+
const patch = writer.patches[i]!
|
|
515
|
+
const start = 2 + patch.offset * 2
|
|
516
|
+
data =
|
|
517
|
+
`${data.slice(0, start)}${patch.value}${data.slice(start + patch.value.length)}` as Hex.Hex
|
|
518
|
+
}
|
|
519
|
+
return data
|
|
450
520
|
}
|
|
451
521
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
522
|
+
export declare namespace encodeParameters {
|
|
523
|
+
type Options = {
|
|
524
|
+
checksumAddress?: boolean | undefined
|
|
525
|
+
prefix?: Hex.Hex | undefined
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
type ErrorType =
|
|
529
|
+
| AbiParameters.LengthMismatchError
|
|
530
|
+
| AbiParameters.InvalidArrayError
|
|
531
|
+
| AbiParameters.ArrayLengthMismatchError
|
|
532
|
+
| AbiParameters.BytesSizeMismatchError
|
|
533
|
+
| AbiParameters.InvalidTypeError
|
|
534
|
+
| Address.assert.ErrorType
|
|
535
|
+
| Hex.IntegerOutOfRangeError
|
|
536
|
+
| Hex.fromBytes.ErrorType
|
|
537
|
+
| Errors.GlobalErrorType
|
|
455
538
|
}
|
|
456
539
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
540
|
+
function compileParameters(
|
|
541
|
+
parameters: readonly AbiParameters.Parameter[],
|
|
542
|
+
): readonly CompiledParameter[] {
|
|
543
|
+
const compiled: CompiledParameter[] = []
|
|
544
|
+
for (let i = 0; i < parameters.length; i++)
|
|
545
|
+
compiled.push(compileParameter(parameters[i]!))
|
|
546
|
+
return compiled
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function compileParameter(
|
|
550
|
+
parameter: AbiParameters.Parameter,
|
|
551
|
+
): CompiledParameter {
|
|
552
|
+
const name = parameter.name
|
|
553
|
+
const array = getArrayComponents(parameter.type)
|
|
554
|
+
if (array) {
|
|
555
|
+
const [length, type] = array
|
|
556
|
+
const child = compileParameter({ ...parameter, type })
|
|
557
|
+
const dynamic = length === null || child.dynamic
|
|
558
|
+
return {
|
|
559
|
+
child,
|
|
560
|
+
dynamic,
|
|
561
|
+
kind: 'array',
|
|
478
562
|
length,
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
})
|
|
563
|
+
name,
|
|
564
|
+
staticSize: dynamic ? 32 : child.staticSize * length,
|
|
565
|
+
type: parameter.type,
|
|
566
|
+
}
|
|
484
567
|
}
|
|
568
|
+
|
|
485
569
|
if (parameter.type === 'tuple') {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
570
|
+
const children = compileParameters(
|
|
571
|
+
(parameter as TupleAbiParameter).components,
|
|
572
|
+
)
|
|
573
|
+
let dynamic = false
|
|
574
|
+
let staticSize = 0
|
|
575
|
+
for (let i = 0; i < children.length; i++) {
|
|
576
|
+
const child = children[i]!
|
|
577
|
+
if (child.dynamic) dynamic = true
|
|
578
|
+
staticSize += child.staticSize
|
|
579
|
+
}
|
|
580
|
+
return {
|
|
581
|
+
children,
|
|
582
|
+
dynamic,
|
|
583
|
+
kind: 'tuple',
|
|
584
|
+
name,
|
|
585
|
+
staticSize: dynamic ? 32 : staticSize,
|
|
586
|
+
}
|
|
498
587
|
}
|
|
588
|
+
|
|
589
|
+
if (parameter.type === 'address')
|
|
590
|
+
return {
|
|
591
|
+
dynamic: false,
|
|
592
|
+
kind: 'address',
|
|
593
|
+
name,
|
|
594
|
+
staticSize: 32,
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if (parameter.type === 'bool')
|
|
598
|
+
return {
|
|
599
|
+
dynamic: false,
|
|
600
|
+
kind: 'boolean',
|
|
601
|
+
name,
|
|
602
|
+
staticSize: 32,
|
|
603
|
+
}
|
|
604
|
+
|
|
499
605
|
if (parameter.type.startsWith('uint') || parameter.type.startsWith('int')) {
|
|
500
606
|
const signed = parameter.type.startsWith('int')
|
|
501
607
|
const [, , size = '256'] = integerRegex.exec(parameter.type) ?? []
|
|
502
|
-
|
|
608
|
+
const size_ = Number(size)
|
|
609
|
+
const max = 2n ** (BigInt(size_) - (signed ? 1n : 0n)) - 1n
|
|
610
|
+
return {
|
|
611
|
+
dynamic: false,
|
|
612
|
+
kind: 'integer',
|
|
613
|
+
max,
|
|
614
|
+
min: signed ? -max - 1n : 0n,
|
|
615
|
+
name,
|
|
503
616
|
signed,
|
|
504
|
-
size:
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
if (parameter.type.startsWith('bytes')) {
|
|
508
|
-
return encodeBytes(value as unknown as Hex.Hex, { type: parameter.type })
|
|
509
|
-
}
|
|
510
|
-
if (parameter.type === 'string') {
|
|
511
|
-
return encodeString(value as unknown as string)
|
|
617
|
+
size: size_,
|
|
618
|
+
staticSize: 32,
|
|
619
|
+
}
|
|
512
620
|
}
|
|
513
|
-
throw new AbiParameters.InvalidTypeError(parameter.type)
|
|
514
|
-
}
|
|
515
621
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
| Errors.GlobalErrorType
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
/** @internal */
|
|
530
|
-
export function encode(preparedParameters: PreparedParameter[]): Hex.Hex {
|
|
531
|
-
// 1. Compute the size of the static part of the parameters.
|
|
532
|
-
let staticSize = 0
|
|
533
|
-
for (let i = 0; i < preparedParameters.length; i++) {
|
|
534
|
-
const { dynamic, encoded } = preparedParameters[i]!
|
|
535
|
-
if (dynamic) staticSize += 32
|
|
536
|
-
else staticSize += Hex.size(encoded)
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
// 2. Split the parameters into static and dynamic parts.
|
|
540
|
-
const staticParameters: Hex.Hex[] = []
|
|
541
|
-
const dynamicParameters: Hex.Hex[] = []
|
|
542
|
-
let dynamicSize = 0
|
|
543
|
-
for (let i = 0; i < preparedParameters.length; i++) {
|
|
544
|
-
const { dynamic, encoded } = preparedParameters[i]!
|
|
545
|
-
if (dynamic) {
|
|
546
|
-
staticParameters.push(
|
|
547
|
-
Hex.fromNumber(staticSize + dynamicSize, { size: 32 }),
|
|
548
|
-
)
|
|
549
|
-
dynamicParameters.push(encoded)
|
|
550
|
-
dynamicSize += Hex.size(encoded)
|
|
551
|
-
} else {
|
|
552
|
-
staticParameters.push(encoded)
|
|
622
|
+
if (parameter.type.startsWith('bytes')) {
|
|
623
|
+
if (!bytesRegex.test(parameter.type))
|
|
624
|
+
throw new AbiParameters.InvalidTypeError(parameter.type)
|
|
625
|
+
const [, size] = parameter.type.split('bytes')
|
|
626
|
+
return {
|
|
627
|
+
dynamic: !size,
|
|
628
|
+
kind: 'bytes',
|
|
629
|
+
name,
|
|
630
|
+
size: size ? Number.parseInt(size, 10) : null,
|
|
631
|
+
staticSize: 32,
|
|
553
632
|
}
|
|
554
633
|
}
|
|
555
634
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
| Hex.concat.ErrorType
|
|
564
|
-
| Hex.fromNumber.ErrorType
|
|
565
|
-
| Hex.size.ErrorType
|
|
566
|
-
| Errors.GlobalErrorType
|
|
567
|
-
}
|
|
635
|
+
if (parameter.type === 'string')
|
|
636
|
+
return {
|
|
637
|
+
dynamic: true,
|
|
638
|
+
kind: 'string',
|
|
639
|
+
name,
|
|
640
|
+
staticSize: 32,
|
|
641
|
+
}
|
|
568
642
|
|
|
569
|
-
/** @internal */
|
|
570
|
-
export function encodeAddress(
|
|
571
|
-
value: Hex.Hex,
|
|
572
|
-
options: { checksum: boolean },
|
|
573
|
-
): PreparedParameter {
|
|
574
|
-
const { checksum } = options
|
|
575
|
-
Address.assert(value, { strict: checksum })
|
|
576
643
|
return {
|
|
577
644
|
dynamic: false,
|
|
578
|
-
|
|
645
|
+
kind: 'invalid',
|
|
646
|
+
name,
|
|
647
|
+
staticSize: 0,
|
|
648
|
+
type: parameter.type,
|
|
579
649
|
}
|
|
580
650
|
}
|
|
581
651
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
652
|
+
function measureParameters(
|
|
653
|
+
parameters: readonly CompiledParameter[],
|
|
654
|
+
values: readonly unknown[] | object,
|
|
655
|
+
context: MeasureContext,
|
|
656
|
+
): number {
|
|
657
|
+
let size = getHeadSize(parameters)
|
|
658
|
+
for (let i = 0; i < parameters.length; i++) {
|
|
659
|
+
const parameter = parameters[i]!
|
|
660
|
+
const parameterSize = measureParameter(
|
|
661
|
+
parameter,
|
|
662
|
+
getParameterValue(parameter, values, i),
|
|
663
|
+
context,
|
|
664
|
+
)
|
|
665
|
+
if (parameter.dynamic) size += parameterSize
|
|
666
|
+
}
|
|
667
|
+
return size
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
function measureParameter(
|
|
671
|
+
parameter: CompiledParameter,
|
|
672
|
+
value: unknown,
|
|
673
|
+
context: MeasureContext,
|
|
674
|
+
): number {
|
|
675
|
+
if (parameter.kind === 'array') {
|
|
676
|
+
if (!Array.isArray(value)) throw new AbiParameters.InvalidArrayError(value)
|
|
677
|
+
if (parameter.length !== null && value.length !== parameter.length)
|
|
678
|
+
throw new AbiParameters.ArrayLengthMismatchError({
|
|
679
|
+
expectedLength: parameter.length,
|
|
680
|
+
givenLength: value.length,
|
|
681
|
+
type: parameter.type,
|
|
682
|
+
})
|
|
589
683
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
const { checksumAddress, length, parameter } = options
|
|
684
|
+
let size = parameter.length === null ? 32 : 0
|
|
685
|
+
size +=
|
|
686
|
+
value.length * (parameter.child.dynamic ? 32 : parameter.child.staticSize)
|
|
687
|
+
for (let i = 0; i < value.length; i++) {
|
|
688
|
+
const childSize = measureParameter(parameter.child, value[i], context)
|
|
689
|
+
if (parameter.child.dynamic) size += childSize
|
|
690
|
+
}
|
|
691
|
+
return size
|
|
692
|
+
}
|
|
600
693
|
|
|
601
|
-
|
|
694
|
+
if (parameter.kind === 'tuple')
|
|
695
|
+
return measureParameters(parameter.children, value as object, context)
|
|
602
696
|
|
|
603
|
-
if (
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
expectedLength: length!,
|
|
607
|
-
givenLength: value.length,
|
|
608
|
-
type: `${parameter.type}[${length}]`,
|
|
697
|
+
if (parameter.kind === 'address') {
|
|
698
|
+
Address.assert(value as Address.Address, {
|
|
699
|
+
strict: context.checksumAddress,
|
|
609
700
|
})
|
|
701
|
+
return 32
|
|
702
|
+
}
|
|
610
703
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
checksumAddress,
|
|
618
|
-
parameter,
|
|
619
|
-
value: value[i],
|
|
620
|
-
})
|
|
621
|
-
if (preparedParam.dynamic) dynamicChild = true
|
|
622
|
-
preparedParameters.push(preparedParam)
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
if (dynamic || dynamicChild) {
|
|
626
|
-
const data = encode(preparedParameters)
|
|
627
|
-
if (dynamic) {
|
|
628
|
-
const length = Hex.fromNumber(preparedParameters.length, { size: 32 })
|
|
629
|
-
return {
|
|
630
|
-
dynamic: true,
|
|
631
|
-
encoded:
|
|
632
|
-
preparedParameters.length > 0 ? Hex.concat(length, data) : length,
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
if (dynamicChild) return { dynamic: true, encoded: data }
|
|
704
|
+
if (parameter.kind === 'boolean') {
|
|
705
|
+
if (typeof value !== 'boolean')
|
|
706
|
+
throw new Errors.BaseError(
|
|
707
|
+
`Invalid boolean value: "${value}" (type: ${typeof value}). Expected: \`true\` or \`false\`.`,
|
|
708
|
+
)
|
|
709
|
+
return 32
|
|
636
710
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
711
|
+
|
|
712
|
+
if (parameter.kind === 'integer') {
|
|
713
|
+
const value_ = value as number
|
|
714
|
+
if (value_ > parameter.max || value_ < parameter.min)
|
|
715
|
+
throw new Hex.IntegerOutOfRangeError({
|
|
716
|
+
max: parameter.max.toString(),
|
|
717
|
+
min: parameter.min.toString(),
|
|
718
|
+
signed: parameter.signed,
|
|
719
|
+
size: parameter.size / 8,
|
|
720
|
+
value: value_.toString(),
|
|
721
|
+
})
|
|
722
|
+
BigInt(value_)
|
|
723
|
+
return 32
|
|
640
724
|
}
|
|
641
|
-
}
|
|
642
725
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
726
|
+
if (parameter.kind === 'bytes') {
|
|
727
|
+
const value_ = value as Hex.Hex
|
|
728
|
+
const size = Hex.size(value_)
|
|
729
|
+
if (parameter.size !== null && size !== parameter.size)
|
|
730
|
+
throw new AbiParameters.BytesSizeMismatchError({
|
|
731
|
+
expectedSize: parameter.size,
|
|
732
|
+
value: value_,
|
|
733
|
+
})
|
|
734
|
+
if (parameter.size !== null) return 32
|
|
735
|
+
return 32 + Math.ceil(size / 32) * 32
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
if (parameter.kind === 'string') {
|
|
739
|
+
const size = getUtf8Size(normalizeString(value))
|
|
740
|
+
return 32 + Math.ceil(size / 32) * 32
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
throw new AbiParameters.InvalidTypeError(parameter.type!)
|
|
651
744
|
}
|
|
652
745
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
const [, parametersize] = type.split('bytes')
|
|
659
|
-
const bytesSize = Hex.size(value)
|
|
660
|
-
if (!parametersize) {
|
|
661
|
-
let value_ = value
|
|
662
|
-
// If the size is not divisible by 32 bytes, pad the end
|
|
663
|
-
// with empty bytes to the ceiling 32 bytes.
|
|
664
|
-
if (bytesSize % 32 !== 0)
|
|
665
|
-
value_ = Hex.padRight(value_, Math.ceil((value.length - 2) / 2 / 32) * 32)
|
|
666
|
-
return {
|
|
667
|
-
dynamic: true,
|
|
668
|
-
encoded: Hex.concat(
|
|
669
|
-
Hex.padLeft(Hex.fromNumber(bytesSize, { size: 32 })),
|
|
670
|
-
value_,
|
|
671
|
-
),
|
|
672
|
-
}
|
|
746
|
+
function getHeadSize(parameters: readonly CompiledParameter[]): number {
|
|
747
|
+
let size = 0
|
|
748
|
+
for (let i = 0; i < parameters.length; i++) {
|
|
749
|
+
const parameter = parameters[i]!
|
|
750
|
+
size += parameter.dynamic ? 32 : parameter.staticSize
|
|
673
751
|
}
|
|
674
|
-
|
|
675
|
-
throw new AbiParameters.BytesSizeMismatchError({
|
|
676
|
-
expectedSize: Number.parseInt(parametersize, 10),
|
|
677
|
-
value,
|
|
678
|
-
})
|
|
679
|
-
return { dynamic: false, encoded: Hex.padRight(value) }
|
|
752
|
+
return size
|
|
680
753
|
}
|
|
681
754
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
| Errors.GlobalErrorType
|
|
755
|
+
function getParameterValue(
|
|
756
|
+
parameter: CompiledParameter,
|
|
757
|
+
values: readonly unknown[] | object,
|
|
758
|
+
index: number,
|
|
759
|
+
) {
|
|
760
|
+
if (Array.isArray(values)) return values[index]
|
|
761
|
+
return (values as Record<string, unknown>)[parameter.name!]
|
|
690
762
|
}
|
|
691
763
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
)
|
|
698
|
-
|
|
764
|
+
function getUtf8Size(value: string): number {
|
|
765
|
+
let size = 0
|
|
766
|
+
for (let i = 0; i < value.length; i++) {
|
|
767
|
+
const code = value.charCodeAt(i)
|
|
768
|
+
if (code < 0x80) size++
|
|
769
|
+
else if (code < 0x800) size += 2
|
|
770
|
+
else if (
|
|
771
|
+
code >= 0xd800 &&
|
|
772
|
+
code <= 0xdbff &&
|
|
773
|
+
value.charCodeAt(i + 1) >= 0xdc00 &&
|
|
774
|
+
value.charCodeAt(i + 1) <= 0xdfff
|
|
775
|
+
) {
|
|
776
|
+
size += 4
|
|
777
|
+
i++
|
|
778
|
+
} else size += 3
|
|
779
|
+
}
|
|
780
|
+
return size
|
|
699
781
|
}
|
|
700
782
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
| Hex.padLeft.ErrorType
|
|
705
|
-
| Hex.fromBoolean.ErrorType
|
|
706
|
-
| Errors.GlobalErrorType
|
|
783
|
+
function normalizeString(value: unknown): string {
|
|
784
|
+
if (value === undefined) return ''
|
|
785
|
+
return `${value}`
|
|
707
786
|
}
|
|
708
787
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
)
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
if (value
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
788
|
+
function isWritableHex(value: Hex.Hex): boolean {
|
|
789
|
+
if (
|
|
790
|
+
typeof value !== 'string' ||
|
|
791
|
+
value.charCodeAt(0) !== 48 ||
|
|
792
|
+
value.charCodeAt(1) !== 120
|
|
793
|
+
)
|
|
794
|
+
return false
|
|
795
|
+
for (let i = 2; i < value.length; i++)
|
|
796
|
+
if (toNibble(value.charCodeAt(i)) === -1) return false
|
|
797
|
+
return true
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
function writeParameters(
|
|
801
|
+
context: WriteContext,
|
|
802
|
+
offset: number,
|
|
803
|
+
parameters: readonly CompiledParameter[],
|
|
804
|
+
values: readonly unknown[] | object,
|
|
805
|
+
): number {
|
|
806
|
+
let head = offset
|
|
807
|
+
let tail = offset + getHeadSize(parameters)
|
|
808
|
+
for (let i = 0; i < parameters.length; i++) {
|
|
809
|
+
const parameter = parameters[i]!
|
|
810
|
+
const value = getParameterValue(parameter, values, i)
|
|
811
|
+
if (parameter.dynamic) {
|
|
812
|
+
writeWord(context, head, tail - offset)
|
|
813
|
+
head += 32
|
|
814
|
+
tail = writeParameter(context, tail, parameter, value)
|
|
815
|
+
} else head = writeParameter(context, head, parameter, value)
|
|
725
816
|
}
|
|
726
|
-
return
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
817
|
+
return Math.max(head, tail)
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
function writeParameter(
|
|
821
|
+
context: WriteContext,
|
|
822
|
+
offset: number,
|
|
823
|
+
parameter: CompiledParameter,
|
|
824
|
+
value: unknown,
|
|
825
|
+
): number {
|
|
826
|
+
if (parameter.kind === 'array') {
|
|
827
|
+
const values = value as readonly unknown[]
|
|
828
|
+
let head = offset
|
|
829
|
+
if (parameter.length === null) {
|
|
830
|
+
writeWord(context, head, values.length)
|
|
831
|
+
head += 32
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
let tail =
|
|
835
|
+
head +
|
|
836
|
+
values.length *
|
|
837
|
+
(parameter.child.dynamic ? 32 : parameter.child.staticSize)
|
|
838
|
+
for (let i = 0; i < values.length; i++) {
|
|
839
|
+
if (parameter.child.dynamic) {
|
|
840
|
+
writeWord(
|
|
841
|
+
context,
|
|
842
|
+
head,
|
|
843
|
+
tail - (parameter.length === null ? offset + 32 : offset),
|
|
844
|
+
)
|
|
845
|
+
head += 32
|
|
846
|
+
tail = writeParameter(context, tail, parameter.child, values[i])
|
|
847
|
+
} else head = writeParameter(context, head, parameter.child, values[i])
|
|
848
|
+
}
|
|
849
|
+
return Math.max(head, tail)
|
|
732
850
|
}
|
|
733
|
-
}
|
|
734
851
|
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
type ErrorType = Hex.fromNumber.ErrorType | Errors.GlobalErrorType
|
|
738
|
-
}
|
|
852
|
+
if (parameter.kind === 'tuple')
|
|
853
|
+
return writeParameters(context, offset, parameter.children, value as object)
|
|
739
854
|
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
const partsLength = Math.ceil(Hex.size(hexValue) / 32)
|
|
744
|
-
const parts: Hex.Hex[] = []
|
|
745
|
-
for (let i = 0; i < partsLength; i++) {
|
|
746
|
-
parts.push(Hex.padRight(Hex.slice(hexValue, i * 32, (i + 1) * 32)))
|
|
855
|
+
if (parameter.kind === 'address') {
|
|
856
|
+
writeHex(context, offset + 12, value as Hex.Hex)
|
|
857
|
+
return offset + 32
|
|
747
858
|
}
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
...parts,
|
|
753
|
-
),
|
|
859
|
+
|
|
860
|
+
if (parameter.kind === 'boolean') {
|
|
861
|
+
context.bytes[offset + 31] = value ? 1 : 0
|
|
862
|
+
return offset + 32
|
|
754
863
|
}
|
|
755
|
-
}
|
|
756
864
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
865
|
+
if (parameter.kind === 'integer') {
|
|
866
|
+
writeWord(context, offset, value as number)
|
|
867
|
+
return offset + 32
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
if (parameter.kind === 'bytes') {
|
|
871
|
+
const value_ = value as Hex.Hex
|
|
872
|
+
if (parameter.size === null) {
|
|
873
|
+
const size = Hex.size(value_)
|
|
874
|
+
writeWord(context, offset, size)
|
|
875
|
+
writeHex(context, offset + 32, value_)
|
|
876
|
+
return offset + 32 + Math.ceil(size / 32) * 32
|
|
877
|
+
}
|
|
878
|
+
writeHex(context, offset, value_)
|
|
879
|
+
return offset + 32
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
if (parameter.kind === 'string') {
|
|
883
|
+
const value_ = normalizeString(value)
|
|
884
|
+
const size = getUtf8Size(value_)
|
|
885
|
+
writeWord(context, offset, size)
|
|
886
|
+
const { written } = encoder.encodeInto(
|
|
887
|
+
value_,
|
|
888
|
+
context.bytes.subarray(offset + 32, offset + 32 + size),
|
|
889
|
+
)
|
|
890
|
+
if (written !== size) throw new Error('Failed to encode string.')
|
|
891
|
+
return offset + 32 + Math.ceil(size / 32) * 32
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
return offset
|
|
765
895
|
}
|
|
766
896
|
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
parameter: parameter
|
|
777
|
-
},
|
|
778
|
-
): PreparedParameter {
|
|
779
|
-
const { checksumAddress, parameter } = options
|
|
780
|
-
|
|
781
|
-
let dynamic = false
|
|
782
|
-
const preparedParameters: PreparedParameter[] = []
|
|
783
|
-
for (let i = 0; i < parameter.components.length; i++) {
|
|
784
|
-
const param_ = parameter.components[i]!
|
|
785
|
-
const index = Array.isArray(value) ? i : param_.name
|
|
786
|
-
const preparedParam = prepareParameter({
|
|
787
|
-
checksumAddress,
|
|
788
|
-
parameter: param_,
|
|
789
|
-
value: (value as any)[index!] as readonly unknown[],
|
|
790
|
-
})
|
|
791
|
-
preparedParameters.push(preparedParam)
|
|
792
|
-
if (preparedParam.dynamic) dynamic = true
|
|
897
|
+
function writeHex(
|
|
898
|
+
context: WriteContext,
|
|
899
|
+
offset: number,
|
|
900
|
+
value: Hex.Hex,
|
|
901
|
+
): number {
|
|
902
|
+
if (!isWritableHex(value)) {
|
|
903
|
+
const patch = value.slice(2)
|
|
904
|
+
context.patches.push({ offset, value: patch })
|
|
905
|
+
return offset + Math.ceil(patch.length / 2)
|
|
793
906
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
907
|
+
|
|
908
|
+
let i = 2
|
|
909
|
+
for (; i + 1 < value.length; i += 2)
|
|
910
|
+
context.bytes[offset++] =
|
|
911
|
+
(toNibble(value.charCodeAt(i)) << 4) | toNibble(value.charCodeAt(i + 1))
|
|
912
|
+
if (i < value.length)
|
|
913
|
+
context.bytes[offset++] = toNibble(value.charCodeAt(i)) << 4
|
|
914
|
+
return offset
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
function writeWord(
|
|
918
|
+
context: WriteContext,
|
|
919
|
+
offset: number,
|
|
920
|
+
value: bigint | number,
|
|
921
|
+
) {
|
|
922
|
+
let value_ = BigInt(value)
|
|
923
|
+
if (value_ < 0n) value_ = BigInt.asUintN(256, value_)
|
|
924
|
+
|
|
925
|
+
// DataView avoids 32 BigInt shifts for the common word-sized case.
|
|
926
|
+
if (value_ <= 0xffff_ffff_ffff_ffffn) {
|
|
927
|
+
context.view.setBigUint64(offset + 24, value_)
|
|
928
|
+
return
|
|
799
929
|
}
|
|
930
|
+
|
|
931
|
+
const hex = value_.toString(16)
|
|
932
|
+
let cursor = offset + 32 - Math.ceil(hex.length / 2)
|
|
933
|
+
let i = hex.length % 2
|
|
934
|
+
if (i === 1) context.bytes[cursor++] = toNibble(hex.charCodeAt(0))
|
|
935
|
+
for (; i < hex.length; i += 2)
|
|
936
|
+
context.bytes[cursor++] =
|
|
937
|
+
(toNibble(hex.charCodeAt(i)) << 4) | toNibble(hex.charCodeAt(i + 1))
|
|
800
938
|
}
|
|
801
939
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
940
|
+
function toNibble(code: number): number {
|
|
941
|
+
if (code >= 48 && code <= 57) return code - 48
|
|
942
|
+
if (code >= 65 && code <= 70) return code - 55
|
|
943
|
+
if (code >= 97 && code <= 102) return code - 87
|
|
944
|
+
return -1
|
|
805
945
|
}
|
|
806
946
|
|
|
807
947
|
/** @internal */
|