ox 1.2.0 → 1.3.1

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.
Files changed (187) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/core/AbiFunction.d.ts +1 -1
  3. package/dist/core/AbiFunction.d.ts.map +1 -1
  4. package/dist/core/AbiFunction.js +6 -2
  5. package/dist/core/AbiFunction.js.map +1 -1
  6. package/dist/core/AbiParameters.d.ts +1 -1
  7. package/dist/core/AbiParameters.d.ts.map +1 -1
  8. package/dist/core/AbiParameters.js +1 -13
  9. package/dist/core/AbiParameters.js.map +1 -1
  10. package/dist/core/AesGcm.d.ts +36 -1
  11. package/dist/core/AesGcm.d.ts.map +1 -1
  12. package/dist/core/AesGcm.js +44 -0
  13. package/dist/core/AesGcm.js.map +1 -1
  14. package/dist/core/Ed25519.d.ts +46 -1
  15. package/dist/core/Ed25519.d.ts.map +1 -1
  16. package/dist/core/Ed25519.js +43 -0
  17. package/dist/core/Ed25519.js.map +1 -1
  18. package/dist/core/Engine.d.ts +1 -1
  19. package/dist/core/Engine.d.ts.map +1 -1
  20. package/dist/core/Engine.js.map +1 -1
  21. package/dist/core/Hash.d.ts +164 -1
  22. package/dist/core/Hash.d.ts.map +1 -1
  23. package/dist/core/Hash.js +172 -0
  24. package/dist/core/Hash.js.map +1 -1
  25. package/dist/core/Hex.d.ts.map +1 -1
  26. package/dist/core/Hex.js +1 -4
  27. package/dist/core/Hex.js.map +1 -1
  28. package/dist/core/Rlp.d.ts +32 -0
  29. package/dist/core/Rlp.d.ts.map +1 -1
  30. package/dist/core/Rlp.js +146 -0
  31. package/dist/core/Rlp.js.map +1 -1
  32. package/dist/core/Secp256k1.d.ts +46 -1
  33. package/dist/core/Secp256k1.d.ts.map +1 -1
  34. package/dist/core/Secp256k1.js +48 -0
  35. package/dist/core/Secp256k1.js.map +1 -1
  36. package/dist/core/WebAuthn.d.ts +224 -0
  37. package/dist/core/WebAuthn.d.ts.map +1 -0
  38. package/dist/core/WebAuthn.js +343 -0
  39. package/dist/core/WebAuthn.js.map +1 -0
  40. package/dist/core/WebAuthnP256.d.ts +46 -50
  41. package/dist/core/WebAuthnP256.d.ts.map +1 -1
  42. package/dist/core/WebAuthnP256.js +44 -50
  43. package/dist/core/WebAuthnP256.js.map +1 -1
  44. package/dist/core/internal/abiParameters.d.ts +7 -87
  45. package/dist/core/internal/abiParameters.d.ts.map +1 -1
  46. package/dist/core/internal/abiParameters.js +339 -194
  47. package/dist/core/internal/abiParameters.js.map +1 -1
  48. package/dist/core/internal/engine.d.ts +35 -2
  49. package/dist/core/internal/engine.d.ts.map +1 -1
  50. package/dist/core/internal/engine.js +12 -1
  51. package/dist/core/internal/engine.js.map +1 -1
  52. package/dist/core/internal/hash.d.ts +10 -0
  53. package/dist/core/internal/hash.d.ts.map +1 -1
  54. package/dist/core/internal/hash.js +26 -1
  55. package/dist/core/internal/hash.js.map +1 -1
  56. package/dist/index.d.ts +23 -14
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +23 -14
  59. package/dist/index.js.map +1 -1
  60. package/dist/node/Engine.d.ts +1 -1
  61. package/dist/node/Engine.d.ts.map +1 -1
  62. package/dist/node/Engine.js.map +1 -1
  63. package/dist/node/Hash.d.ts +6 -4
  64. package/dist/node/Hash.d.ts.map +1 -1
  65. package/dist/node/Hash.js +35 -3
  66. package/dist/node/Hash.js.map +1 -1
  67. package/dist/tempo/AuthorizationTempo.d.ts +6 -6
  68. package/dist/tempo/AuthorizationTempo.js +6 -6
  69. package/dist/tempo/KeyAuthorization.d.ts +3 -8
  70. package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
  71. package/dist/tempo/KeyAuthorization.js +3 -8
  72. package/dist/tempo/KeyAuthorization.js.map +1 -1
  73. package/dist/tempo/SignatureEnvelope.d.ts +8 -8
  74. package/dist/tempo/SignatureEnvelope.js +8 -8
  75. package/dist/wasm/Engine.d.ts +1 -1
  76. package/dist/wasm/Engine.d.ts.map +1 -1
  77. package/dist/wasm/Engine.js.map +1 -1
  78. package/dist/wasm/Hash.d.ts +1 -1
  79. package/dist/wasm/Hash.d.ts.map +1 -1
  80. package/dist/wasm/Hash.js +5 -0
  81. package/dist/wasm/Hash.js.map +1 -1
  82. package/dist/wasm/internal/blake3.d.ts +10 -1
  83. package/dist/wasm/internal/blake3.d.ts.map +1 -1
  84. package/dist/wasm/internal/blake3.js +12 -1
  85. package/dist/wasm/internal/blake3.js.map +1 -1
  86. package/dist/wasm/internal/blake3.wasm.d.ts +3 -1
  87. package/dist/wasm/internal/blake3.wasm.d.ts.map +1 -1
  88. package/dist/wasm/internal/blake3.wasm.js +3 -1
  89. package/dist/wasm/internal/blake3.wasm.js.map +1 -1
  90. package/dist/wasm/internal/hash.d.ts +9 -0
  91. package/dist/wasm/internal/hash.d.ts.map +1 -1
  92. package/dist/wasm/internal/hash.js +13 -1
  93. package/dist/wasm/internal/hash.js.map +1 -1
  94. package/dist/wasm/internal/hashState.d.ts +25 -0
  95. package/dist/wasm/internal/hashState.d.ts.map +1 -0
  96. package/dist/wasm/internal/hashState.js +105 -0
  97. package/dist/wasm/internal/hashState.js.map +1 -0
  98. package/dist/wasm/internal/hashes.d.ts +12 -1
  99. package/dist/wasm/internal/hashes.d.ts.map +1 -1
  100. package/dist/wasm/internal/hashes.js +18 -1
  101. package/dist/wasm/internal/hashes.js.map +1 -1
  102. package/dist/wasm/internal/hashes.wasm.d.ts +11 -3
  103. package/dist/wasm/internal/hashes.wasm.d.ts.map +1 -1
  104. package/dist/wasm/internal/hashes.wasm.js +11 -3
  105. package/dist/wasm/internal/hashes.wasm.js.map +1 -1
  106. package/dist/webauthn/Authentication.d.ts +2 -0
  107. package/dist/webauthn/Authentication.d.ts.map +1 -1
  108. package/dist/webauthn/Authentication.js +2 -1
  109. package/dist/webauthn/Authentication.js.map +1 -1
  110. package/dist/webauthn/Registration.d.ts.map +1 -1
  111. package/dist/webauthn/Registration.js +2 -1
  112. package/dist/webauthn/Registration.js.map +1 -1
  113. package/dist/webauthn/Types.d.ts +27 -6
  114. package/dist/webauthn/Types.d.ts.map +1 -1
  115. package/dist/webauthn/internal/utils.d.ts.map +1 -1
  116. package/dist/webauthn/internal/utils.js +35 -9
  117. package/dist/webauthn/internal/utils.js.map +1 -1
  118. package/dist/zod/TypedData.d.ts +2 -2
  119. package/package.json +13 -1
  120. package/src/benchmarks/Ox.bench.ts +6 -0
  121. package/src/benchmarks/OxNode.bench.ts +8 -0
  122. package/src/benchmarks/OxV0.bench.ts +4 -0
  123. package/src/benchmarks/OxWasm.bench.ts +22 -0
  124. package/src/core/AbiFunction.ts +5 -5
  125. package/src/core/AbiParameters.ts +8 -20
  126. package/src/core/AesGcm.ts +86 -1
  127. package/src/core/Ed25519.ts +87 -1
  128. package/src/core/Engine.ts +1 -0
  129. package/src/core/Hash.ts +262 -1
  130. package/src/core/Hex.ts +1 -4
  131. package/src/core/Rlp.ts +172 -5
  132. package/src/core/Secp256k1.ts +92 -1
  133. package/src/core/WebAuthn.ts +579 -0
  134. package/src/core/WebAuthnP256.ts +47 -50
  135. package/src/core/_test/AbiFunction.test.ts +9 -0
  136. package/src/core/_test/AbiParameters.differential.fuzz.ts +156 -0
  137. package/src/core/_test/AbiParameters.encode.test.ts +22 -0
  138. package/src/core/_test/AbiParameters.fuzz.ts +4 -0
  139. package/src/core/_test/AesGcm.test.ts +76 -0
  140. package/src/core/_test/Ed25519.test-d.ts +13 -1
  141. package/src/core/_test/Ed25519.test.ts +120 -1
  142. package/src/core/_test/Engine.test-d.ts +9 -0
  143. package/src/core/_test/Engine.test.ts +1 -1
  144. package/src/core/_test/Hash.test-d.ts +23 -0
  145. package/src/core/_test/Hash.test.ts +179 -1
  146. package/src/core/_test/Hex.test.ts +2 -0
  147. package/src/core/_test/Rlp.test-d.ts +18 -0
  148. package/src/core/_test/Rlp.test.ts +109 -0
  149. package/src/core/_test/Secp256k1.test-d.ts +14 -0
  150. package/src/core/_test/Secp256k1.test.ts +91 -1
  151. package/src/core/_test/WebAuthn.test-d.ts +142 -0
  152. package/src/core/_test/WebAuthn.test.ts +766 -0
  153. package/src/core/_test/index.test.ts +1 -0
  154. package/src/core/internal/abiParameters.ts +466 -326
  155. package/src/core/internal/engine.ts +47 -2
  156. package/src/core/internal/hash.ts +53 -1
  157. package/src/index.ts +24 -14
  158. package/src/node/Engine.ts +1 -0
  159. package/src/node/Hash.ts +43 -6
  160. package/src/node/_test/Engine.test-d.ts +1 -0
  161. package/src/node/_test/Engine.test.ts +2 -0
  162. package/src/node/_test/Hash.test-d.ts +10 -0
  163. package/src/node/_test/Hash.test.ts +46 -0
  164. package/src/tempo/AuthorizationTempo.ts +6 -6
  165. package/src/tempo/KeyAuthorization.ts +3 -8
  166. package/src/tempo/SignatureEnvelope.ts +8 -8
  167. package/src/version.ts +1 -1
  168. package/src/wasm/Engine.ts +1 -0
  169. package/src/wasm/Hash.ts +10 -0
  170. package/src/wasm/_test/Engine.test-d.ts +1 -0
  171. package/src/wasm/_test/Engine.test.ts +5 -0
  172. package/src/wasm/_test/Hash.browser.test.ts +28 -0
  173. package/src/wasm/_test/Hash.test-d.ts +16 -0
  174. package/src/wasm/_test/Hash.test.ts +250 -1
  175. package/src/wasm/internal/blake3.ts +23 -2
  176. package/src/wasm/internal/blake3.wasm.ts +4 -1
  177. package/src/wasm/internal/hash.ts +27 -1
  178. package/src/wasm/internal/hashState.ts +154 -0
  179. package/src/wasm/internal/hashes.ts +56 -15
  180. package/src/wasm/internal/hashes.wasm.ts +15 -3
  181. package/src/webauthn/Authentication.ts +4 -0
  182. package/src/webauthn/Registration.ts +2 -0
  183. package/src/webauthn/Types.ts +32 -2
  184. package/src/webauthn/_test/Authentication.test.ts +123 -1
  185. package/src/webauthn/_test/Registration.test.ts +26 -6
  186. package/src/webauthn/_test/WebAuthn.browser.test.ts +28 -0
  187. package/src/webauthn/internal/utils.ts +41 -8
@@ -3,7 +3,8 @@ import * as Address from '../Address.js';
3
3
  import * as Bytes from '../Bytes.js';
4
4
  import * as Errors from '../Errors.js';
5
5
  import * as Hex from '../Hex.js';
6
- import { integerRegex } from '../Solidity.js';
6
+ import { bytesRegex, integerRegex } from '../Solidity.js';
7
+ import { encoder } from './codec/utf8.js';
7
8
  /** @internal */
8
9
  export function decodeParameter(cursor, param, options) {
9
10
  const { checksumAddress, staticPosition } = options;
@@ -236,229 +237,373 @@ export function decodeString(cursor, { staticPosition }) {
236
237
  return [value, 32];
237
238
  }
238
239
  /** @internal */
239
- export function prepareParameters({ checksumAddress, parameters, values, }) {
240
- const preparedParameters = [];
241
- for (let i = 0; i < parameters.length; i++) {
242
- preparedParameters.push(prepareParameter({
243
- checksumAddress,
244
- parameter: parameters[i],
245
- value: values[i],
246
- }));
240
+ export function encodeParameters(parameters, values, options = {}) {
241
+ const { checksumAddress = false, prefix } = options;
242
+ if (parameters.length !== values.length)
243
+ throw new AbiParameters.LengthMismatchError({
244
+ expectedLength: parameters.length,
245
+ givenLength: values.length,
246
+ });
247
+ // Compile the wire shape before walking values so recursive writes only
248
+ // handle offsets and data.
249
+ const compiled = compileParameters(parameters);
250
+ const context = {
251
+ checksumAddress,
252
+ };
253
+ const size = measureParameters(compiled, values, context);
254
+ const prefixSize = prefix ? Hex.size(prefix) : 0;
255
+ const bytes = new Uint8Array(prefixSize + size);
256
+ const writer = {
257
+ bytes,
258
+ patches: [],
259
+ view: new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength),
260
+ };
261
+ if (prefix)
262
+ writeHex(writer, 0, prefix);
263
+ writeParameters(writer, prefixSize, compiled, values);
264
+ let data = Hex.fromBytes(bytes);
265
+ for (let i = 0; i < writer.patches.length; i++) {
266
+ const patch = writer.patches[i];
267
+ const start = 2 + patch.offset * 2;
268
+ data =
269
+ `${data.slice(0, start)}${patch.value}${data.slice(start + patch.value.length)}`;
247
270
  }
248
- return preparedParameters;
271
+ return data;
249
272
  }
250
- /** @internal */
251
- export function prepareParameter({ checksumAddress = false, parameter: parameter_, value, }) {
252
- const parameter = parameter_;
253
- const arrayComponents = getArrayComponents(parameter.type);
254
- if (arrayComponents) {
255
- const [length, type] = arrayComponents;
256
- return encodeArray(value, {
257
- checksumAddress,
273
+ function compileParameters(parameters) {
274
+ const compiled = [];
275
+ for (let i = 0; i < parameters.length; i++)
276
+ compiled.push(compileParameter(parameters[i]));
277
+ return compiled;
278
+ }
279
+ function compileParameter(parameter) {
280
+ const name = parameter.name;
281
+ const array = getArrayComponents(parameter.type);
282
+ if (array) {
283
+ const [length, type] = array;
284
+ const child = compileParameter({ ...parameter, type });
285
+ const dynamic = length === null || child.dynamic;
286
+ return {
287
+ child,
288
+ dynamic,
289
+ kind: 'array',
258
290
  length,
259
- parameter: {
260
- ...parameter,
261
- type,
262
- },
263
- });
291
+ name,
292
+ staticSize: dynamic ? 32 : child.staticSize * length,
293
+ type: parameter.type,
294
+ };
264
295
  }
265
296
  if (parameter.type === 'tuple') {
266
- return encodeTuple(value, {
267
- checksumAddress,
268
- parameter: parameter,
269
- });
270
- }
271
- if (parameter.type === 'address') {
272
- return encodeAddress(value, {
273
- checksum: checksumAddress,
274
- });
275
- }
276
- if (parameter.type === 'bool') {
277
- return encodeBoolean(value);
297
+ const children = compileParameters(parameter.components);
298
+ let dynamic = false;
299
+ let staticSize = 0;
300
+ for (let i = 0; i < children.length; i++) {
301
+ const child = children[i];
302
+ if (child.dynamic)
303
+ dynamic = true;
304
+ staticSize += child.staticSize;
305
+ }
306
+ return {
307
+ children,
308
+ dynamic,
309
+ kind: 'tuple',
310
+ name,
311
+ staticSize: dynamic ? 32 : staticSize,
312
+ };
278
313
  }
314
+ if (parameter.type === 'address')
315
+ return {
316
+ dynamic: false,
317
+ kind: 'address',
318
+ name,
319
+ staticSize: 32,
320
+ };
321
+ if (parameter.type === 'bool')
322
+ return {
323
+ dynamic: false,
324
+ kind: 'boolean',
325
+ name,
326
+ staticSize: 32,
327
+ };
279
328
  if (parameter.type.startsWith('uint') || parameter.type.startsWith('int')) {
280
329
  const signed = parameter.type.startsWith('int');
281
330
  const [, , size = '256'] = integerRegex.exec(parameter.type) ?? [];
282
- return encodeNumber(value, {
331
+ const size_ = Number(size);
332
+ const max = 2n ** (BigInt(size_) - (signed ? 1n : 0n)) - 1n;
333
+ return {
334
+ dynamic: false,
335
+ kind: 'integer',
336
+ max,
337
+ min: signed ? -max - 1n : 0n,
338
+ name,
283
339
  signed,
284
- size: Number(size),
285
- });
340
+ size: size_,
341
+ staticSize: 32,
342
+ };
286
343
  }
287
344
  if (parameter.type.startsWith('bytes')) {
288
- return encodeBytes(value, { type: parameter.type });
289
- }
290
- if (parameter.type === 'string') {
291
- return encodeString(value);
345
+ if (!bytesRegex.test(parameter.type))
346
+ throw new AbiParameters.InvalidTypeError(parameter.type);
347
+ const [, size] = parameter.type.split('bytes');
348
+ return {
349
+ dynamic: !size,
350
+ kind: 'bytes',
351
+ name,
352
+ size: size ? Number.parseInt(size, 10) : null,
353
+ staticSize: 32,
354
+ };
292
355
  }
293
- throw new AbiParameters.InvalidTypeError(parameter.type);
356
+ if (parameter.type === 'string')
357
+ return {
358
+ dynamic: true,
359
+ kind: 'string',
360
+ name,
361
+ staticSize: 32,
362
+ };
363
+ return {
364
+ dynamic: false,
365
+ kind: 'invalid',
366
+ name,
367
+ staticSize: 0,
368
+ type: parameter.type,
369
+ };
294
370
  }
295
- /** @internal */
296
- export function encode(preparedParameters) {
297
- // 1. Compute the size of the static part of the parameters.
298
- let staticSize = 0;
299
- for (let i = 0; i < preparedParameters.length; i++) {
300
- const { dynamic, encoded } = preparedParameters[i];
301
- if (dynamic)
302
- staticSize += 32;
303
- else
304
- staticSize += Hex.size(encoded);
371
+ function measureParameters(parameters, values, context) {
372
+ let size = getHeadSize(parameters);
373
+ for (let i = 0; i < parameters.length; i++) {
374
+ const parameter = parameters[i];
375
+ const parameterSize = measureParameter(parameter, getParameterValue(parameter, values, i), context);
376
+ if (parameter.dynamic)
377
+ size += parameterSize;
305
378
  }
306
- // 2. Split the parameters into static and dynamic parts.
307
- const staticParameters = [];
308
- const dynamicParameters = [];
309
- let dynamicSize = 0;
310
- for (let i = 0; i < preparedParameters.length; i++) {
311
- const { dynamic, encoded } = preparedParameters[i];
312
- if (dynamic) {
313
- staticParameters.push(Hex.fromNumber(staticSize + dynamicSize, { size: 32 }));
314
- dynamicParameters.push(encoded);
315
- dynamicSize += Hex.size(encoded);
316
- }
317
- else {
318
- staticParameters.push(encoded);
379
+ return size;
380
+ }
381
+ function measureParameter(parameter, value, context) {
382
+ if (parameter.kind === 'array') {
383
+ if (!Array.isArray(value))
384
+ throw new AbiParameters.InvalidArrayError(value);
385
+ if (parameter.length !== null && value.length !== parameter.length)
386
+ throw new AbiParameters.ArrayLengthMismatchError({
387
+ expectedLength: parameter.length,
388
+ givenLength: value.length,
389
+ type: parameter.type,
390
+ });
391
+ let size = parameter.length === null ? 32 : 0;
392
+ size +=
393
+ value.length * (parameter.child.dynamic ? 32 : parameter.child.staticSize);
394
+ for (let i = 0; i < value.length; i++) {
395
+ const childSize = measureParameter(parameter.child, value[i], context);
396
+ if (parameter.child.dynamic)
397
+ size += childSize;
319
398
  }
399
+ return size;
320
400
  }
321
- // 3. Concatenate static and dynamic parts.
322
- return Hex.concat(...staticParameters, ...dynamicParameters);
401
+ if (parameter.kind === 'tuple')
402
+ return measureParameters(parameter.children, value, context);
403
+ if (parameter.kind === 'address') {
404
+ Address.assert(value, {
405
+ strict: context.checksumAddress,
406
+ });
407
+ return 32;
408
+ }
409
+ if (parameter.kind === 'boolean') {
410
+ if (typeof value !== 'boolean')
411
+ throw new Errors.BaseError(`Invalid boolean value: "${value}" (type: ${typeof value}). Expected: \`true\` or \`false\`.`);
412
+ return 32;
413
+ }
414
+ if (parameter.kind === 'integer') {
415
+ const value_ = value;
416
+ if (value_ > parameter.max || value_ < parameter.min)
417
+ throw new Hex.IntegerOutOfRangeError({
418
+ max: parameter.max.toString(),
419
+ min: parameter.min.toString(),
420
+ signed: parameter.signed,
421
+ size: parameter.size / 8,
422
+ value: value_.toString(),
423
+ });
424
+ BigInt(value_);
425
+ return 32;
426
+ }
427
+ if (parameter.kind === 'bytes') {
428
+ const value_ = value;
429
+ const size = Hex.size(value_);
430
+ if (parameter.size !== null && size !== parameter.size)
431
+ throw new AbiParameters.BytesSizeMismatchError({
432
+ expectedSize: parameter.size,
433
+ value: value_,
434
+ });
435
+ if (parameter.size !== null)
436
+ return 32;
437
+ return 32 + Math.ceil(size / 32) * 32;
438
+ }
439
+ if (parameter.kind === 'string') {
440
+ const size = getUtf8Size(normalizeString(value));
441
+ return 32 + Math.ceil(size / 32) * 32;
442
+ }
443
+ throw new AbiParameters.InvalidTypeError(parameter.type);
323
444
  }
324
- /** @internal */
325
- export function encodeAddress(value, options) {
326
- const { checksum } = options;
327
- Address.assert(value, { strict: checksum });
328
- return {
329
- dynamic: false,
330
- encoded: Hex.padLeft(value.toLowerCase()),
331
- };
445
+ function getHeadSize(parameters) {
446
+ let size = 0;
447
+ for (let i = 0; i < parameters.length; i++) {
448
+ const parameter = parameters[i];
449
+ size += parameter.dynamic ? 32 : parameter.staticSize;
450
+ }
451
+ return size;
332
452
  }
333
- /** @internal */
334
- export function encodeArray(value, options) {
335
- const { checksumAddress, length, parameter } = options;
336
- const dynamic = length === null;
337
- if (!Array.isArray(value))
338
- throw new AbiParameters.InvalidArrayError(value);
339
- if (!dynamic && value.length !== length)
340
- throw new AbiParameters.ArrayLengthMismatchError({
341
- expectedLength: length,
342
- givenLength: value.length,
343
- type: `${parameter.type}[${length}]`,
344
- });
345
- // Zero-length fixed arrays of dynamic types (e.g. `string[0]`) are dynamic
346
- // per the ABI spec, even though they have no elements to inspect.
347
- let dynamicChild = value.length === 0 && hasDynamicChild(parameter);
348
- const preparedParameters = [];
453
+ function getParameterValue(parameter, values, index) {
454
+ if (Array.isArray(values))
455
+ return values[index];
456
+ return values[parameter.name];
457
+ }
458
+ function getUtf8Size(value) {
459
+ let size = 0;
349
460
  for (let i = 0; i < value.length; i++) {
350
- const preparedParam = prepareParameter({
351
- checksumAddress,
352
- parameter,
353
- value: value[i],
354
- });
355
- if (preparedParam.dynamic)
356
- dynamicChild = true;
357
- preparedParameters.push(preparedParam);
358
- }
359
- if (dynamic || dynamicChild) {
360
- const data = encode(preparedParameters);
361
- if (dynamic) {
362
- const length = Hex.fromNumber(preparedParameters.length, { size: 32 });
363
- return {
364
- dynamic: true,
365
- encoded: preparedParameters.length > 0 ? Hex.concat(length, data) : length,
366
- };
461
+ const code = value.charCodeAt(i);
462
+ if (code < 0x80)
463
+ size++;
464
+ else if (code < 0x800)
465
+ size += 2;
466
+ else if (code >= 0xd800 &&
467
+ code <= 0xdbff &&
468
+ value.charCodeAt(i + 1) >= 0xdc00 &&
469
+ value.charCodeAt(i + 1) <= 0xdfff) {
470
+ size += 4;
471
+ i++;
367
472
  }
368
- if (dynamicChild)
369
- return { dynamic: true, encoded: data };
473
+ else
474
+ size += 3;
370
475
  }
371
- return {
372
- dynamic: false,
373
- encoded: Hex.concat(...preparedParameters.map(({ encoded }) => encoded)),
374
- };
476
+ return size;
375
477
  }
376
- /** @internal */
377
- export function encodeBytes(value, { type }) {
378
- const [, parametersize] = type.split('bytes');
379
- const bytesSize = Hex.size(value);
380
- if (!parametersize) {
381
- let value_ = value;
382
- // If the size is not divisible by 32 bytes, pad the end
383
- // with empty bytes to the ceiling 32 bytes.
384
- if (bytesSize % 32 !== 0)
385
- value_ = Hex.padRight(value_, Math.ceil((value.length - 2) / 2 / 32) * 32);
386
- return {
387
- dynamic: true,
388
- encoded: Hex.concat(Hex.padLeft(Hex.fromNumber(bytesSize, { size: 32 })), value_),
389
- };
390
- }
391
- if (bytesSize !== Number.parseInt(parametersize, 10))
392
- throw new AbiParameters.BytesSizeMismatchError({
393
- expectedSize: Number.parseInt(parametersize, 10),
394
- value,
395
- });
396
- return { dynamic: false, encoded: Hex.padRight(value) };
478
+ function normalizeString(value) {
479
+ if (value === undefined)
480
+ return '';
481
+ return `${value}`;
397
482
  }
398
- /** @internal */
399
- export function encodeBoolean(value) {
400
- if (typeof value !== 'boolean')
401
- throw new Errors.BaseError(`Invalid boolean value: "${value}" (type: ${typeof value}). Expected: \`true\` or \`false\`.`);
402
- return { dynamic: false, encoded: Hex.padLeft(Hex.fromBoolean(value)) };
483
+ function isWritableHex(value) {
484
+ if (typeof value !== 'string' ||
485
+ value.charCodeAt(0) !== 48 ||
486
+ value.charCodeAt(1) !== 120)
487
+ return false;
488
+ for (let i = 2; i < value.length; i++)
489
+ if (toNibble(value.charCodeAt(i)) === -1)
490
+ return false;
491
+ return true;
403
492
  }
404
- /** @internal */
405
- export function encodeNumber(value, { signed, size }) {
406
- if (typeof size === 'number') {
407
- const max = 2n ** (BigInt(size) - (signed ? 1n : 0n)) - 1n;
408
- const min = signed ? -max - 1n : 0n;
409
- if (value > max || value < min)
410
- throw new Hex.IntegerOutOfRangeError({
411
- max: max.toString(),
412
- min: min.toString(),
413
- signed,
414
- size: size / 8,
415
- value: value.toString(),
416
- });
493
+ function writeParameters(context, offset, parameters, values) {
494
+ let head = offset;
495
+ let tail = offset + getHeadSize(parameters);
496
+ for (let i = 0; i < parameters.length; i++) {
497
+ const parameter = parameters[i];
498
+ const value = getParameterValue(parameter, values, i);
499
+ if (parameter.dynamic) {
500
+ writeWord(context, head, tail - offset);
501
+ head += 32;
502
+ tail = writeParameter(context, tail, parameter, value);
503
+ }
504
+ else
505
+ head = writeParameter(context, head, parameter, value);
417
506
  }
418
- return {
419
- dynamic: false,
420
- encoded: Hex.fromNumber(value, {
421
- size: 32,
422
- signed,
423
- }),
424
- };
507
+ return Math.max(head, tail);
425
508
  }
426
- /** @internal */
427
- export function encodeString(value) {
428
- const hexValue = Hex.fromString(value);
429
- const partsLength = Math.ceil(Hex.size(hexValue) / 32);
430
- const parts = [];
431
- for (let i = 0; i < partsLength; i++) {
432
- parts.push(Hex.padRight(Hex.slice(hexValue, i * 32, (i + 1) * 32)));
509
+ function writeParameter(context, offset, parameter, value) {
510
+ if (parameter.kind === 'array') {
511
+ const values = value;
512
+ let head = offset;
513
+ if (parameter.length === null) {
514
+ writeWord(context, head, values.length);
515
+ head += 32;
516
+ }
517
+ let tail = head +
518
+ values.length *
519
+ (parameter.child.dynamic ? 32 : parameter.child.staticSize);
520
+ for (let i = 0; i < values.length; i++) {
521
+ if (parameter.child.dynamic) {
522
+ writeWord(context, head, tail - (parameter.length === null ? offset + 32 : offset));
523
+ head += 32;
524
+ tail = writeParameter(context, tail, parameter.child, values[i]);
525
+ }
526
+ else
527
+ head = writeParameter(context, head, parameter.child, values[i]);
528
+ }
529
+ return Math.max(head, tail);
433
530
  }
434
- return {
435
- dynamic: true,
436
- encoded: Hex.concat(Hex.padRight(Hex.fromNumber(Hex.size(hexValue), { size: 32 })), ...parts),
437
- };
531
+ if (parameter.kind === 'tuple')
532
+ return writeParameters(context, offset, parameter.children, value);
533
+ if (parameter.kind === 'address') {
534
+ writeHex(context, offset + 12, value);
535
+ return offset + 32;
536
+ }
537
+ if (parameter.kind === 'boolean') {
538
+ context.bytes[offset + 31] = value ? 1 : 0;
539
+ return offset + 32;
540
+ }
541
+ if (parameter.kind === 'integer') {
542
+ writeWord(context, offset, value);
543
+ return offset + 32;
544
+ }
545
+ if (parameter.kind === 'bytes') {
546
+ const value_ = value;
547
+ if (parameter.size === null) {
548
+ const size = Hex.size(value_);
549
+ writeWord(context, offset, size);
550
+ writeHex(context, offset + 32, value_);
551
+ return offset + 32 + Math.ceil(size / 32) * 32;
552
+ }
553
+ writeHex(context, offset, value_);
554
+ return offset + 32;
555
+ }
556
+ if (parameter.kind === 'string') {
557
+ const value_ = normalizeString(value);
558
+ const size = getUtf8Size(value_);
559
+ writeWord(context, offset, size);
560
+ const { written } = encoder.encodeInto(value_, context.bytes.subarray(offset + 32, offset + 32 + size));
561
+ if (written !== size)
562
+ throw new Error('Failed to encode string.');
563
+ return offset + 32 + Math.ceil(size / 32) * 32;
564
+ }
565
+ return offset;
438
566
  }
439
- /** @internal */
440
- export function encodeTuple(value, options) {
441
- const { checksumAddress, parameter } = options;
442
- let dynamic = false;
443
- const preparedParameters = [];
444
- for (let i = 0; i < parameter.components.length; i++) {
445
- const param_ = parameter.components[i];
446
- const index = Array.isArray(value) ? i : param_.name;
447
- const preparedParam = prepareParameter({
448
- checksumAddress,
449
- parameter: param_,
450
- value: value[index],
451
- });
452
- preparedParameters.push(preparedParam);
453
- if (preparedParam.dynamic)
454
- dynamic = true;
567
+ function writeHex(context, offset, value) {
568
+ if (!isWritableHex(value)) {
569
+ const patch = value.slice(2);
570
+ context.patches.push({ offset, value: patch });
571
+ return offset + Math.ceil(patch.length / 2);
455
572
  }
456
- return {
457
- dynamic,
458
- encoded: dynamic
459
- ? encode(preparedParameters)
460
- : Hex.concat(...preparedParameters.map(({ encoded }) => encoded)),
461
- };
573
+ let i = 2;
574
+ for (; i + 1 < value.length; i += 2)
575
+ context.bytes[offset++] =
576
+ (toNibble(value.charCodeAt(i)) << 4) | toNibble(value.charCodeAt(i + 1));
577
+ if (i < value.length)
578
+ context.bytes[offset++] = toNibble(value.charCodeAt(i)) << 4;
579
+ return offset;
580
+ }
581
+ function writeWord(context, offset, value) {
582
+ let value_ = BigInt(value);
583
+ if (value_ < 0n)
584
+ value_ = BigInt.asUintN(256, value_);
585
+ // DataView avoids 32 BigInt shifts for the common word-sized case.
586
+ if (value_ <= 0xffffffffffffffffn) {
587
+ context.view.setBigUint64(offset + 24, value_);
588
+ return;
589
+ }
590
+ const hex = value_.toString(16);
591
+ let cursor = offset + 32 - Math.ceil(hex.length / 2);
592
+ let i = hex.length % 2;
593
+ if (i === 1)
594
+ context.bytes[cursor++] = toNibble(hex.charCodeAt(0));
595
+ for (; i < hex.length; i += 2)
596
+ context.bytes[cursor++] =
597
+ (toNibble(hex.charCodeAt(i)) << 4) | toNibble(hex.charCodeAt(i + 1));
598
+ }
599
+ function toNibble(code) {
600
+ if (code >= 48 && code <= 57)
601
+ return code - 48;
602
+ if (code >= 65 && code <= 70)
603
+ return code - 55;
604
+ if (code >= 97 && code <= 102)
605
+ return code - 87;
606
+ return -1;
462
607
  }
463
608
  /** @internal */
464
609
  export function getArrayComponents(type) {