solidity-scale-codec 0.3.3 → 1.0.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +36 -2
  2. package/README.md +1 -1
  3. package/package.json +2 -2
  4. package/src/Utils/BytesUtils.sol +26 -0
  5. package/src/Utils/UnsignedUtils.sol +52 -0
  6. package/src/Xcm/VersionedXcm/VersionedXcm.sol +4 -1
  7. package/src/Xcm/VersionedXcm/VersionedXcmCodec.sol +11 -0
  8. package/src/Xcm/v3/MaybeErrorCode/MaybeErrorCode.sol +8 -7
  9. package/src/Xcm/v3/MaybeErrorCode/MaybeErrorCodeCodec.sol +18 -19
  10. package/src/Xcm/v5/AssetFilter/AssetFilter.sol +8 -8
  11. package/src/Xcm/v5/AssetFilter/AssetFilterCodec.sol +47 -34
  12. package/src/Xcm/v5/AssetInstance/AssetInstance.sol +13 -12
  13. package/src/Xcm/v5/AssetInstance/AssetInstanceCodec.sol +53 -56
  14. package/src/Xcm/v5/AssetTransferFilter/AssetTransferFilter.sol +12 -12
  15. package/src/Xcm/v5/AssetTransferFilter/AssetTransferFilterCodec.sol +48 -20
  16. package/src/Xcm/v5/Assets/Assets.sol +16 -0
  17. package/src/Xcm/v5/Assets/AssetsCodec.sol +3 -3
  18. package/src/Xcm/v5/BodyId/BodyId.sol +24 -24
  19. package/src/Xcm/v5/BodyId/BodyIdCodec.sol +41 -48
  20. package/src/Xcm/v5/BodyPart/BodyPart.sol +44 -28
  21. package/src/Xcm/v5/BodyPart/BodyPartCodec.sol +70 -37
  22. package/src/Xcm/v5/Constants.sol +2 -2
  23. package/src/Xcm/v5/Fungibility/Fungibility.sol +6 -6
  24. package/src/Xcm/v5/Fungibility/FungibilityCodec.sol +40 -36
  25. package/src/Xcm/v5/Hint/Hint.sol +5 -5
  26. package/src/Xcm/v5/Hint/HintCodec.sol +24 -20
  27. package/src/Xcm/v5/Instruction/Instruction.sol +81 -55
  28. package/src/Xcm/v5/Instruction/InstructionCodec.sol +1047 -73
  29. package/src/Xcm/v5/Junction/Junction.sol +55 -69
  30. package/src/Xcm/v5/Junction/JunctionCodec.sol +72 -135
  31. package/src/Xcm/v5/Junctions/Junctions.sol +34 -0
  32. package/src/Xcm/v5/Junctions/JunctionsCodec.sol +0 -18
  33. package/src/Xcm/v5/Location/Location.sol +8 -0
  34. package/src/Xcm/v5/NetworkId/NetworkId.sol +15 -16
  35. package/src/Xcm/v5/NetworkId/NetworkIdCodec.sol +57 -34
  36. package/src/Xcm/v5/OriginKind/OriginKindCodec.sol +1 -1
  37. package/src/Xcm/v5/Response/Response.sol +49 -40
  38. package/src/Xcm/v5/Response/ResponseCodec.sol +64 -54
  39. package/src/Xcm/v5/Weight/WeightCodec.sol +3 -2
  40. package/src/Xcm/v5/WeightLimit/WeightLimit.sol +6 -6
  41. package/src/Xcm/v5/WeightLimit/WeightLimitCodec.sol +32 -23
  42. package/src/Xcm/v5/WildAsset/WildAsset.sol +17 -25
  43. package/src/Xcm/v5/WildAsset/WildAssetCodec.sol +35 -38
  44. package/src/Xcm/v5/WildFungibility/WildFungibilityCodec.sol +6 -6
  45. package/src/Xcm/v5/Xcm/XcmBuilder.sol +689 -0
  46. package/src/Xcm/v5/XcmError/XcmError.sol +7 -7
  47. package/src/Xcm/v5/XcmError/XcmErrorCodec.sol +25 -22
  48. package/DEFINITIONS.md +0 -132
package/CHANGELOG.md CHANGED
@@ -7,15 +7,49 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  [Unreleased]
9
9
 
10
+ ## Version 1.0.0
11
+
12
+ ### Added
13
+
14
+ - `BytesUtils.sol`, a new utility library for byte manipulation, including functions for copying byte arrays. - [#3](https://github.com/LucasGrasso/solidity-scale-codec/pull/3)
15
+ - `UnsignedUtils.sol`, a new utility library for safely converting `uint256` values to smaller unsigned integer types (`uint8`, `uint16`, `uint32`, `uint64`, `uint128`) with overflow checks. - [#3](https://github.com/LucasGrasso/solidity-scale-codec/pull/3)
16
+ - `XcmBuilder.sol`, a new utility library for constructing XCM messages in a more ergonomic way, with functions for building various XCM instructions. - [#3](https://github.com/LucasGrasso/solidity-scale-codec/pull/3)
17
+ - Added `parent()` helper function in `Location.sol` to create a `Location` struct representing the parent location (one level up in the hierarchy). - [#93618bf](https://github.com/LucasGrasso/solidity-scale-codec/commit/93618bf)
18
+ - Added `fromAsset(Asset)` and `fromAssets(Asset[])` helper functions in `Assets.sol` to construct `Assets` values ergonomically from a single asset or an array. - [#dd79e86](https://github.com/LucasGrasso/solidity-scale-codec/commit/dd79e86)
19
+
20
+ ### Changed
21
+
22
+ - For every enum equivalent, rename `Type` suffix to `Variant` for better clarity and consistency. - [#3](https://github.com/LucasGrasso/solidity-scale-codec/pull/3)
23
+ - Type Checking with `UnsignedUtils` in all codecs to ensure safe downcasting of `uint256` to smaller unsigned integer types, preventing potential overflow issues and improving robustness. - [#3](https://github.com/LucasGrasso/solidity-scale-codec/pull/3)
24
+ - DRY with `BytesUtils.copy` in all codecs to replace manual byte copying loops, improving code readability, maintainability, and gas efficiency. - [#3](https://github.com/LucasGrasso/solidity-scale-codec/pull/3)
25
+ - Removed unnecessary length checks at the beginning of decoding functions since `encodedSizeAt` and `BytesUtils.copy` will handle those checks and revert if data is insufficient, simplifying the code and centralizing error handling. - [#3](https://github.com/LucasGrasso/solidity-scale-codec/pull/3)
26
+ - Moved helper `Junction` functions to outside of the codec. - [#b91bdfa](https://github.com/LucasGrasso/solidity-scale-codec/commit/b91bdfa24472fe931ee5dd6625ae2b4796d23248)
27
+
28
+ ### Fixed
29
+
30
+ - Inconsistencies in Xcm Codec libraries:
31
+ - `decode`, `decodeAt` functions not returning `bytesRead` in some codecs. - [#3](https://github.com/LucasGrasso/solidity-scale-codec/pull/3)
32
+ - Now returning `{Variant}Params` structs in `as{Variant}` decoding functions for consistency and better ergonomics. - [#3](https://github.com/LucasGrasso/solidity-scale-codec/pull/3)
33
+ - Inconsistencies in Xcm Instruction factory functions:
34
+ - Some factory functions were taking individual parameters instead of `{Variant}Params` structs, leading to less consistent and ergonomic API. - [#3](https://github.com/LucasGrasso/solidity-scale-codec/pull/3)
35
+ - Now checking Variant bounds when calling `decodeAt` at all enum equivalents. - [#3](https://github.com/LucasGrasso/solidity-scale-codec/pull/3)
36
+ - Optional encoding in `Junction` factory functions was not correctly implemented, leading to incorrect encoding when `hasNetwork` was false. - [#93618bf](https://github.com/LucasGrasso/solidity-scale-codec/commit/93618bf)
37
+
38
+ ## Version 0.3.4
39
+
40
+ ### Changed
41
+
42
+ - Move Definitions to website docs - [#f57c914](https://github.com/LucasGrasso/solidity-scale-codec/commit/7e88534930cdb8ac47b5f16a02f2203c588a7e7f)
43
+
10
44
  ## Version 0.3.3
11
45
 
12
- ## Changed
46
+ ### Changed
13
47
 
14
48
  - Homepage for the docsite - [#fcbac35](https://github.com/LucasGrasso/solidity-scale-codec/commit/757cddcce6d9f7a82f9535471c86f0cffa878956)
15
49
 
16
50
  ## Version 0.3.2
17
51
 
18
- ## Changed
52
+ ### Changed
19
53
 
20
54
  - Better Changelog - [#288b3e9](https://github.com/LucasGrasso/solidity-scale-codec/commit/288b3e966ff1d030b7e50dcc40d0610cd30b201c)
21
55
 
package/README.md CHANGED
@@ -22,7 +22,7 @@ This library provides a Highly-Modular implementation of SCALE in solidity.
22
22
  | `Compact` | A "compact" or general integer encoding is sufficient for encoding large integers (up to 2\*\*536) and is more efficient at encoding most values than the fixed-width version. (Though for single-byte values, the fixed-width integer is never worse.) | `0` | `0x00` |
23
23
  | `Arrays` | A collection of same-typed values is encoded, prefixed with a compact encoding of the number of items, followed by each item's encoding concatenated in turn. Currently `[uintN]`,`[intN]`, `[bool]` are supported. | `[1,0]` | `0x080100` |
24
24
 
25
- See the [Definitions](DEFINITIONS.md) for more details on the encoding of different types.
25
+ See the [Definitions](https://lucasgrasso.github.io/solidity-scale-codec/Definitions.html) for more details on the encoding of different types.
26
26
 
27
27
  ## Usage
28
28
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "solidity-scale-codec",
3
- "version": "0.3.3",
3
+ "version": "1.0.0",
4
4
  "description": "Solidity implementation of scale-codec.",
5
5
  "keywords": [
6
6
  "solidity",
@@ -47,7 +47,7 @@
47
47
  "hardhat": "^3.0.15",
48
48
  "prettier": "^3.8.1",
49
49
  "prettier-plugin-solidity": "^2.2.1",
50
- "solidity-doc-generator": "^1.1.1",
50
+ "solidity-doc-generator": "^1.2.1",
51
51
  "typescript": "~5.8.0",
52
52
  "viem": "^2.40.3",
53
53
  "vitepress": "^1.6.4",
@@ -0,0 +1,26 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.28;
3
+
4
+ /// @notice Utility functions for working with byte arrays, such as copying segments of bytes.
5
+ library BytesUtils {
6
+ error InvalidBounds();
7
+
8
+ /// @notice Copies a segment of bytes from a source byte array.
9
+ /// @param src The source byte array from which to copy.
10
+ /// @param from The starting index in the source array from which to begin copying.
11
+ /// @param count The number of bytes to copy from the source array.
12
+ function copy(
13
+ bytes memory src,
14
+ uint256 from,
15
+ uint256 count
16
+ ) internal pure returns (bytes memory) {
17
+ if (src.length < from + count) {
18
+ revert InvalidBounds();
19
+ }
20
+ bytes memory result = new bytes(count);
21
+ for (uint256 i = 0; i < count; i++) {
22
+ result[i] = src[from + i];
23
+ }
24
+ return result;
25
+ }
26
+ }
@@ -0,0 +1,52 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.28;
3
+
4
+ /// @notice Utility functions for safely downcasting `uint256` values to smaller unsigned integer types.
5
+ library UnsignedUtils {
6
+ error NumberTooLarge(uint256 value, uint256 max);
7
+
8
+ function toU8(uint256 value) internal pure returns (uint8) {
9
+ if (value > type(uint8).max) {
10
+ revert NumberTooLarge(value, type(uint8).max);
11
+ }
12
+ unchecked {
13
+ return uint8(value);
14
+ }
15
+ }
16
+
17
+ function toU16(uint256 value) internal pure returns (uint16) {
18
+ if (value > type(uint16).max) {
19
+ revert NumberTooLarge(value, type(uint16).max);
20
+ }
21
+ unchecked {
22
+ return uint16(value);
23
+ }
24
+ }
25
+
26
+ function toU32(uint256 value) internal pure returns (uint32) {
27
+ if (value > type(uint32).max) {
28
+ revert NumberTooLarge(value, type(uint32).max);
29
+ }
30
+ unchecked {
31
+ return uint32(value);
32
+ }
33
+ }
34
+
35
+ function toU64(uint256 value) internal pure returns (uint64) {
36
+ if (value > type(uint64).max) {
37
+ revert NumberTooLarge(value, type(uint64).max);
38
+ }
39
+ unchecked {
40
+ return uint64(value);
41
+ }
42
+ }
43
+
44
+ function toU128(uint256 value) internal pure returns (uint128) {
45
+ if (value > type(uint128).max) {
46
+ revert NumberTooLarge(value, type(uint128).max);
47
+ }
48
+ unchecked {
49
+ return uint128(value);
50
+ }
51
+ }
52
+ }
@@ -6,8 +6,11 @@ import {XcmCodec as XcmV5Codec} from "../v5/Xcm/XcmCodec.sol";
6
6
 
7
7
  /// @notice The XCM versions supported by this package.
8
8
  enum XcmVersion {
9
- _unsupported_V2,
9
+ _reserved0,
10
+ _reserved1,
11
+ _reserved2,
10
12
  _unsupported_V3,
13
+ _unsupported_V4,
11
14
  V5
12
15
  }
13
16
 
@@ -67,4 +67,15 @@ library VersionedXcmCodec {
67
67
  revert UnsupportedXcmVersion(version);
68
68
  }
69
69
  }
70
+
71
+ /// @notice Converts a `VersionedXcm` to an `XcmV5` struct, if it is of version `V5`.
72
+ /// @param versionedXcm The `VersionedXcm` to convert.
73
+ /// @return xcm The decoded `XcmV5` struct contained in the `VersionedXcm`.
74
+ function asV5(
75
+ VersionedXcm memory versionedXcm
76
+ ) internal pure returns (XcmV5 memory xcm) {
77
+ if (versionedXcm.version != XcmVersion.V5)
78
+ revert UnsupportedXcmVersion(versionedXcm.version);
79
+ (xcm, ) = XcmV5Codec.decode(versionedXcm.xcm);
80
+ }
70
81
  }
@@ -5,7 +5,7 @@ import {U8Arr} from "../../../Scale/Array.sol";
5
5
  import {MAX_DISPATCH_ERROR_LEN} from "../Constants.sol";
6
6
 
7
7
  /// @notice Discriminant for the `MaybeErrorCode` enum.
8
- enum MaybeErrorCodeType {
8
+ enum MaybeErrorCodeVariant {
9
9
  /// @custom:variant No error occurred.
10
10
  Success,
11
11
  /// @custom:variant An error occurred, containing the dispatch error bytes.
@@ -16,9 +16,9 @@ enum MaybeErrorCodeType {
16
16
 
17
17
  /// @notice The result of a `Transact` dispatch, either success or an error code.
18
18
  struct MaybeErrorCode {
19
- /// @custom:property The type of the result. See `MaybeErrorCodeType` enum for possible values.
20
- MaybeErrorCodeType meType;
21
- /// @custom:property The SCALE-encoded dispatch error bytes. Only meaningful when `meType` is `Error` or `TruncatedError`. Max length is MAX_DISPATCH_ERROR_LEN (128 bytes).
19
+ /// @custom:property The type of the result. See `MaybeErrorCodeVariant` enum for possible values.
20
+ MaybeErrorCodeVariant variant;
21
+ /// @custom:property The SCALE-encoded dispatch error bytes. Only meaningful when `variant` is `Error` or `TruncatedError`. Max length is MAX_DISPATCH_ERROR_LEN (128 bytes).
22
22
  bytes payload;
23
23
  }
24
24
 
@@ -39,7 +39,8 @@ struct TruncatedErrorParams {
39
39
  /// @notice Creates a `Success` MaybeErrorCode.
40
40
  /// @return A `MaybeErrorCode` struct representing success.
41
41
  function success() pure returns (MaybeErrorCode memory) {
42
- return MaybeErrorCode({meType: MaybeErrorCodeType.Success, payload: ""});
42
+ return
43
+ MaybeErrorCode({variant: MaybeErrorCodeVariant.Success, payload: ""});
43
44
  }
44
45
 
45
46
  /// @notice Creates an `Error` MaybeErrorCode with the given dispatch error bytes.
@@ -50,7 +51,7 @@ function error(ErrorParams memory params) pure returns (MaybeErrorCode memory) {
50
51
  revert MaybeErrorCodeTooLong(params.errorBytes.length);
51
52
  return
52
53
  MaybeErrorCode({
53
- meType: MaybeErrorCodeType.Error,
54
+ variant: MaybeErrorCodeVariant.Error,
54
55
  payload: U8Arr.encode(params.errorBytes)
55
56
  });
56
57
  }
@@ -65,7 +66,7 @@ function truncatedError(
65
66
  revert MaybeErrorCodeTooLong(params.errorBytes.length);
66
67
  return
67
68
  MaybeErrorCode({
68
- meType: MaybeErrorCodeType.TruncatedError,
69
+ variant: MaybeErrorCodeVariant.TruncatedError,
69
70
  payload: U8Arr.encode(params.errorBytes)
70
71
  });
71
72
  }
@@ -2,7 +2,8 @@
2
2
  pragma solidity ^0.8.28;
3
3
 
4
4
  import {U8Arr} from "../../../Scale/Array.sol";
5
- import {MaybeErrorCode, MaybeErrorCodeType} from "./MaybeErrorCode.sol";
5
+ import {MaybeErrorCode, MaybeErrorCodeVariant} from "./MaybeErrorCode.sol";
6
+ import {BytesUtils} from "../../../Utils/BytesUtils.sol";
6
7
 
7
8
  /// @title SCALE Codec for XCM v3 `MaybeErrorCode`
8
9
  /// @notice SCALE-compliant encoder/decoder for the `MaybeErrorCode` type.
@@ -10,7 +11,7 @@ import {MaybeErrorCode, MaybeErrorCodeType} from "./MaybeErrorCode.sol";
10
11
  /// @dev XCM v3 reference: https://paritytech.github.io/polkadot-sdk/master/staging_xcm/v3/index.html
11
12
  library MaybeErrorCodeCodec {
12
13
  error InvalidMaybeErrorCodeLength();
13
- error InvalidMaybeErrorCodeType(uint8 meType);
14
+ error InvalidMaybeErrorCodeVariant(uint8 variant);
14
15
 
15
16
  /// @notice Encodes a `MaybeErrorCode` struct into SCALE bytes.
16
17
  /// @param me The `MaybeErrorCode` struct to encode.
@@ -18,7 +19,7 @@ library MaybeErrorCodeCodec {
18
19
  function encode(
19
20
  MaybeErrorCode memory me
20
21
  ) internal pure returns (bytes memory) {
21
- return abi.encodePacked(uint8(me.meType), me.payload);
22
+ return abi.encodePacked(uint8(me.variant), me.payload);
22
23
  }
23
24
 
24
25
  /// @notice Returns the number of bytes that a `MaybeErrorCode` would occupy when SCALE-encoded.
@@ -30,16 +31,16 @@ library MaybeErrorCodeCodec {
30
31
  uint256 offset
31
32
  ) internal pure returns (uint256) {
32
33
  if (data.length < offset + 1) revert InvalidMaybeErrorCodeLength();
33
- uint8 meType = uint8(data[offset]);
34
- if (meType == uint8(MaybeErrorCodeType.Success)) {
34
+ uint8 variant = uint8(data[offset]);
35
+ if (variant == uint8(MaybeErrorCodeVariant.Success)) {
35
36
  return 1;
36
37
  } else if (
37
- meType == uint8(MaybeErrorCodeType.Error) ||
38
- meType == uint8(MaybeErrorCodeType.TruncatedError)
38
+ variant == uint8(MaybeErrorCodeVariant.Error) ||
39
+ variant == uint8(MaybeErrorCodeVariant.TruncatedError)
39
40
  ) {
40
41
  return 1 + U8Arr.encodedSizeAt(data, offset + 1);
41
42
  } else {
42
- revert InvalidMaybeErrorCodeType(meType);
43
+ revert InvalidMaybeErrorCodeVariant(variant);
43
44
  }
44
45
  }
45
46
 
@@ -63,17 +64,15 @@ library MaybeErrorCodeCodec {
63
64
  uint256 offset
64
65
  ) internal pure returns (MaybeErrorCode memory me, uint256 bytesRead) {
65
66
  if (data.length < offset + 1) revert InvalidMaybeErrorCodeLength();
66
- uint8 meType = uint8(data[offset]);
67
- if (meType > uint8(MaybeErrorCodeType.TruncatedError))
68
- revert InvalidMaybeErrorCodeType(meType);
67
+ uint8 variant = uint8(data[offset]);
68
+ if (variant > uint8(type(MaybeErrorCodeVariant).max)) {
69
+ revert InvalidMaybeErrorCodeVariant(variant);
70
+ }
69
71
  uint256 size = encodedSizeAt(data, offset);
70
72
  uint256 payloadLength = size - 1;
71
- bytes memory payload = new bytes(payloadLength);
72
- for (uint256 i = 0; i < payloadLength; ++i) {
73
- payload[i] = data[offset + 1 + i];
74
- }
73
+ bytes memory payload = BytesUtils.copy(data, offset + 1, payloadLength);
75
74
  me = MaybeErrorCode({
76
- meType: MaybeErrorCodeType(meType),
75
+ variant: MaybeErrorCodeVariant(variant),
77
76
  payload: payload
78
77
  });
79
78
  bytesRead = size;
@@ -86,9 +85,9 @@ library MaybeErrorCodeCodec {
86
85
  MaybeErrorCode memory me
87
86
  ) internal pure returns (uint8[] memory errorBytes) {
88
87
  if (
89
- me.meType != MaybeErrorCodeType.Error &&
90
- me.meType != MaybeErrorCodeType.TruncatedError
91
- ) revert InvalidMaybeErrorCodeType(uint8(me.meType));
88
+ me.variant != MaybeErrorCodeVariant.Error &&
89
+ me.variant != MaybeErrorCodeVariant.TruncatedError
90
+ ) revert InvalidMaybeErrorCodeVariant(uint8(me.variant));
92
91
  (errorBytes, ) = U8Arr.decode(me.payload);
93
92
  }
94
93
  }
@@ -7,7 +7,7 @@ import {WildAsset} from "../WildAsset/WildAsset.sol";
7
7
  import {WildAssetCodec} from "../WildAsset/WildAssetCodec.sol";
8
8
 
9
9
  /// @notice Discriminant for the type of asset filter being specified in an `AssetFilter`.
10
- enum AssetFilterType {
10
+ enum AssetFilterVariant {
11
11
  /// @custom:variant Specify the filter as being everything contained by the given `Assets` inner.
12
12
  Definite,
13
13
  /// @custom:variant Specify the filter as the given `WildAsset` wildcard.
@@ -16,9 +16,9 @@ enum AssetFilterType {
16
16
 
17
17
  /// @notice `Asset` collection, defined either by a number of `Assets` or a single wildcard.
18
18
  struct AssetFilter {
19
- /// @custom:property The type of asset filter, determining how to interpret the payload. See `AssetFilterType` enum for possible values.
20
- AssetFilterType afType;
21
- /// @custom:property The encoded payload containing the asset filter data, whose structure depends on the `afType`.
19
+ /// @custom:property The type of asset filter, determining how to interpret the payload. See `AssetFilterVariant` enum for possible values.
20
+ AssetFilterVariant variant;
21
+ /// @custom:property The encoded payload containing the asset filter data, whose structure depends on the `variant`.
22
22
  bytes payload;
23
23
  }
24
24
 
@@ -31,7 +31,7 @@ struct DefiniteParams {
31
31
  /// @notice Parameters for the `Wild` variant.
32
32
  struct WildParams {
33
33
  /// @custom:property The wildcard asset selector.
34
- WildAsset wA;
34
+ WildAsset wildAsset;
35
35
  }
36
36
 
37
37
  // ============ Factory Functions ============
@@ -44,7 +44,7 @@ function definite(
44
44
  ) pure returns (AssetFilter memory) {
45
45
  return
46
46
  AssetFilter({
47
- afType: AssetFilterType.Definite,
47
+ variant: AssetFilterVariant.Definite,
48
48
  payload: AssetsCodec.encode(params.assets)
49
49
  });
50
50
  }
@@ -55,7 +55,7 @@ function definite(
55
55
  function wild(WildParams memory params) pure returns (AssetFilter memory) {
56
56
  return
57
57
  AssetFilter({
58
- afType: AssetFilterType.Wild,
59
- payload: WildAssetCodec.encode(params.wA)
58
+ variant: AssetFilterVariant.Wild,
59
+ payload: WildAssetCodec.encode(params.wildAsset)
60
60
  });
61
61
  }
@@ -5,7 +5,13 @@ import {Assets} from "../Assets/Assets.sol";
5
5
  import {AssetsCodec} from "../Assets/AssetsCodec.sol";
6
6
  import {WildAsset} from "../WildAsset/WildAsset.sol";
7
7
  import {WildAssetCodec} from "../WildAsset/WildAssetCodec.sol";
8
- import {AssetFilter, AssetFilterType} from "./AssetFilter.sol";
8
+ import {
9
+ AssetFilter,
10
+ AssetFilterVariant,
11
+ DefiniteParams,
12
+ WildParams
13
+ } from "./AssetFilter.sol";
14
+ import {BytesUtils} from "../../../Utils/BytesUtils.sol";
9
15
 
10
16
  /// @title SCALE Codec for XCM v5 `AssetFilter`
11
17
  /// @notice SCALE-compliant encoder/decoder for the `AssetFilter` type.
@@ -13,8 +19,7 @@ import {AssetFilter, AssetFilterType} from "./AssetFilter.sol";
13
19
  /// @dev XCM v5 reference: https://paritytech.github.io/polkadot-sdk/master/staging_xcm/v5/index.html
14
20
  library AssetFilterCodec {
15
21
  error InvalidAssetFilterLength();
16
- error InvalidAssetFilterType(uint8 afType);
17
- error InvalidAssetFilterPayload();
22
+ error InvalidAssetFilterVariant(uint8 variant);
18
23
 
19
24
  /// @notice Encodes an `AssetFilter` struct into a SCALE-compliant byte array.
20
25
  /// @param assetFilter The `AssetFilter` struct to encode.
@@ -22,7 +27,8 @@ library AssetFilterCodec {
22
27
  function encode(
23
28
  AssetFilter memory assetFilter
24
29
  ) internal pure returns (bytes memory) {
25
- return abi.encodePacked(uint8(assetFilter.afType), assetFilter.payload);
30
+ return
31
+ abi.encodePacked(uint8(assetFilter.variant), assetFilter.payload);
26
32
  }
27
33
 
28
34
  /// @notice Returns the number of bytes that a `AssetFilter` struct would occupy when SCALE-encoded.
@@ -36,22 +42,27 @@ library AssetFilterCodec {
36
42
  if (data.length < offset + 1) {
37
43
  revert InvalidAssetFilterLength();
38
44
  }
39
- uint8 afType = uint8(data[offset]);
40
- if (afType == uint8(AssetFilterType.Definite)) {
45
+ uint8 variant = uint8(data[offset]);
46
+ if (variant == uint8(AssetFilterVariant.Definite)) {
41
47
  return 1 + AssetsCodec.encodedSizeAt(data, offset + 1);
42
- } else if (afType == uint8(AssetFilterType.Wild)) {
48
+ } else if (variant == uint8(AssetFilterVariant.Wild)) {
43
49
  return 1 + WildAssetCodec.encodedSizeAt(data, offset + 1);
44
50
  } else {
45
- revert InvalidAssetFilterType(afType);
51
+ revert InvalidAssetFilterVariant(variant);
46
52
  }
47
53
  }
48
54
 
49
55
  /// @notice Decodes an `AssetFilter` struct from a SCALE-encoded byte array starting at the beginning of the data.
50
56
  /// @param data The byte sequence containing the encoded `AssetFilter`.
51
57
  /// @return assetFilter The decoded `AssetFilter` struct.
58
+ /// @return bytesRead The total number of bytes read from `data` to decode the `AssetFilter`.
52
59
  function decode(
53
60
  bytes memory data
54
- ) internal pure returns (AssetFilter memory) {
61
+ )
62
+ internal
63
+ pure
64
+ returns (AssetFilter memory assetFilter, uint256 bytesRead)
65
+ {
55
66
  return decodeAt(data, 0);
56
67
  }
57
68
 
@@ -59,47 +70,49 @@ library AssetFilterCodec {
59
70
  /// @param data The byte sequence containing the encoded `AssetFilter`.
60
71
  /// @param offset The starting index in `data` from which to decode the `AssetFilter`.
61
72
  /// @return assetFilter The decoded `AssetFilter` struct.
73
+ /// @return bytesRead The total number of bytes read from `data` to decode the `AssetFilter`.
62
74
  function decodeAt(
63
75
  bytes memory data,
64
76
  uint256 offset
65
- ) internal pure returns (AssetFilter memory assetFilter) {
66
- if (data.length < offset + 1) {
67
- revert InvalidAssetFilterLength();
68
- }
69
- uint8 afType = uint8(data[offset]);
70
- uint256 payloadLength = encodedSizeAt(data, offset) - 1; // Subtract 1 byte for the afType
71
- if (data.length < offset + 1 + payloadLength) {
72
- revert InvalidAssetFilterLength();
73
- }
74
- bytes memory payload = new bytes(payloadLength);
75
- for (uint256 i = 0; i < payloadLength; i++) {
76
- payload[i] = data[offset + 1 + i];
77
- }
78
- assetFilter.afType = AssetFilterType(afType);
77
+ )
78
+ internal
79
+ pure
80
+ returns (AssetFilter memory assetFilter, uint256 bytesRead)
81
+ {
82
+ uint256 payloadLength = encodedSizeAt(data, offset) - 1; // Subtract 1 byte for the variant
83
+ uint8 variant = uint8(data[offset]);
84
+ bytes memory payload = BytesUtils.copy(data, offset + 1, payloadLength);
85
+ assetFilter.variant = AssetFilterVariant(variant);
79
86
  assetFilter.payload = payload;
87
+ bytesRead = 1 + payloadLength;
80
88
  }
81
89
 
82
90
  /// @notice Extracs the inner `Assets` collection. Reverts if the `AssetFilter` is not of the `Definite` variant.
83
91
  /// @param assetFilter The `AssetFilter` struct to decode, which must have the `Definite` variant.
84
- /// @return assets The `Assets` collection contained within the `AssetFilter` if it is of the `Definite` variant.
92
+ /// @return params A `DefiniteParams` struct containing the decoded `Assets` collection.
85
93
  function asDefinite(
86
94
  AssetFilter memory assetFilter
87
- ) internal pure returns (Assets memory assets) {
88
- if (assetFilter.afType != AssetFilterType.Definite) {
89
- revert InvalidAssetFilterPayload();
90
- }
91
- (assets, ) = AssetsCodec.decode(assetFilter.payload);
95
+ ) internal pure returns (DefiniteParams memory params) {
96
+ _assertVariant(assetFilter, AssetFilterVariant.Definite);
97
+ (params.assets, ) = AssetsCodec.decode(assetFilter.payload);
92
98
  }
93
99
 
94
100
  /// @notice Extracts the inner `WildAsset` wildcard. Reverts if the `AssetFilter` is not of the `Wild` variant.
95
101
  /// @param assetFilter The `AssetFilter` struct to decode, which must have the `Wild` variant.
96
- /// @return wA The `WildAsset` wildcard contained within the `AssetFilter` if it is of the `Wild` variant.
102
+ /// @return params A `WildParams` struct containing the decoded `WildAsset` wildcard.
97
103
  function asWild(
98
104
  AssetFilter memory assetFilter
99
- ) internal pure returns (WildAsset memory wA) {
100
- if (assetFilter.afType != AssetFilterType.Wild) {
101
- revert InvalidAssetFilterPayload();
105
+ ) internal pure returns (WildParams memory params) {
106
+ _assertVariant(assetFilter, AssetFilterVariant.Wild);
107
+ (params.wildAsset, ) = WildAssetCodec.decode(assetFilter.payload);
108
+ }
109
+
110
+ function _assertVariant(
111
+ AssetFilter memory assetFilter,
112
+ AssetFilterVariant expected
113
+ ) private pure {
114
+ if (assetFilter.variant != expected) {
115
+ revert InvalidAssetFilterVariant(uint8(assetFilter.variant));
102
116
  }
103
- (wA, ) = WildAssetCodec.decode(assetFilter.payload);
104
117
  }
105
118
  }
@@ -13,7 +13,7 @@ using Bytes16 for bytes16;
13
13
  using Bytes32 for bytes32;
14
14
 
15
15
  /// @dev Discriminant for the different types of AssetInstances in XCM v5.
16
- enum AssetInstanceType {
16
+ enum AssetInstanceVariant {
17
17
  /// @custom:variant Used if the non-fungible asset class has only one instance.
18
18
  Undefined,
19
19
  /// @custom:variant A compact index up to 2^128 - 1.
@@ -30,16 +30,16 @@ enum AssetInstanceType {
30
30
 
31
31
  /// @notice A general identifier for an instance of a non-fungible asset class.
32
32
  struct AssetInstance {
33
- /// @custom:property The type of asset instance, determining how to interpret the payload. See `AssetInstanceType` enum for possible values.
34
- AssetInstanceType iType;
35
- /// @custom:property The encoded payload containing the asset instance data, whose structure depends on the `iType`.
33
+ /// @custom:property The type of asset instance, determining how to interpret the payload. See `AssetInstanceVariant` enum for possible values.
34
+ AssetInstanceVariant variant;
35
+ /// @custom:property The encoded payload containing the asset instance data, whose structure depends on the `variant`.
36
36
  bytes payload;
37
37
  }
38
38
 
39
39
  /// @notice Parameters for the `Index` variant.
40
40
  struct IndexParams {
41
41
  /// @custom:property The compact index value.
42
- uint128 idx;
42
+ uint128 index;
43
43
  }
44
44
 
45
45
  /// @notice Parameters for the `Array4` variant.
@@ -73,7 +73,7 @@ struct Array32Params {
73
73
  function undefined() pure returns (AssetInstance memory) {
74
74
  return
75
75
  AssetInstance({
76
- iType: AssetInstanceType.Undefined,
76
+ variant: AssetInstanceVariant.Undefined,
77
77
  payload: new bytes(0)
78
78
  });
79
79
  }
@@ -82,8 +82,9 @@ function undefined() pure returns (AssetInstance memory) {
82
82
  /// @param params Parameters for the index variant.
83
83
  /// @return An `AssetInstance` struct with type `Index` and the provided index value encoded in the payload.
84
84
  function index(IndexParams memory params) pure returns (AssetInstance memory) {
85
- bytes memory payload = Compact.encode(params.idx);
86
- return AssetInstance({iType: AssetInstanceType.Index, payload: payload});
85
+ bytes memory payload = Compact.encode(params.index);
86
+ return
87
+ AssetInstance({variant: AssetInstanceVariant.Index, payload: payload});
87
88
  }
88
89
 
89
90
  /// @notice Creates an `Array4` asset instance with the given 4-byte data.
@@ -94,7 +95,7 @@ function array4(
94
95
  ) pure returns (AssetInstance memory) {
95
96
  return
96
97
  AssetInstance({
97
- iType: AssetInstanceType.Array4,
98
+ variant: AssetInstanceVariant.Array4,
98
99
  payload: params.data.encode()
99
100
  });
100
101
  }
@@ -107,7 +108,7 @@ function array8(
107
108
  ) pure returns (AssetInstance memory) {
108
109
  return
109
110
  AssetInstance({
110
- iType: AssetInstanceType.Array8,
111
+ variant: AssetInstanceVariant.Array8,
111
112
  payload: params.data.encode()
112
113
  });
113
114
  }
@@ -120,7 +121,7 @@ function array16(
120
121
  ) pure returns (AssetInstance memory) {
121
122
  return
122
123
  AssetInstance({
123
- iType: AssetInstanceType.Array16,
124
+ variant: AssetInstanceVariant.Array16,
124
125
  payload: params.data.encode()
125
126
  });
126
127
  }
@@ -133,7 +134,7 @@ function array32(
133
134
  ) pure returns (AssetInstance memory) {
134
135
  return
135
136
  AssetInstance({
136
- iType: AssetInstanceType.Array32,
137
+ variant: AssetInstanceVariant.Array32,
137
138
  payload: params.data.encode()
138
139
  });
139
140
  }