solidity-scale-codec 0.3.4 → 1.0.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 (47) hide show
  1. package/CHANGELOG.md +37 -3
  2. package/README.md +10 -28
  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
@@ -3,7 +3,9 @@ pragma solidity ^0.8.28;
3
3
 
4
4
  import {Bytes4} from "../../../Scale/Bytes.sol";
5
5
  import {Compact} from "../../../Scale/Compact.sol";
6
- import {BodyId, BodyIdType} from "./BodyId.sol";
6
+ import {BodyId, BodyIdVariant, MonikerParams, IndexParams} from "./BodyId.sol";
7
+ import {BytesUtils} from "../../../Utils/BytesUtils.sol";
8
+ import {UnsignedUtils} from "../../../Utils/UnsignedUtils.sol";
7
9
 
8
10
  /// @title SCALE Codec for XCM v5 `BodyId`
9
11
  /// @notice SCALE-compliant encoder/decoder for the `BodyId` type.
@@ -11,13 +13,13 @@ import {BodyId, BodyIdType} from "./BodyId.sol";
11
13
  /// @dev XCM v5 reference: https://paritytech.github.io/polkadot-sdk/master/staging_xcm/v5/index.html
12
14
  library BodyIdCodec {
13
15
  error InvalidBodyIdLength();
14
- error InvalidBodyIdType(uint8 bodyIdType);
16
+ error InvalidBodyIdVariant(uint8 variant);
15
17
 
16
18
  /// @notice Encodes a `BodyId` into bytes.
17
19
  /// @param bodyId The `BodyId` to encode.
18
20
  /// @return SCALE-encoded byte sequence representing the `BodyId`.
19
21
  function encode(BodyId memory bodyId) internal pure returns (bytes memory) {
20
- return abi.encodePacked(uint8(bodyId.bodyIdType), bodyId.payload);
22
+ return abi.encodePacked(uint8(bodyId.variant), bodyId.payload);
21
23
  }
22
24
 
23
25
  /// @notice Returns the number of bytes that a `BodyId` struct would occupy when SCALE-encoded, starting at a given offset in the data.
@@ -31,26 +33,26 @@ library BodyIdCodec {
31
33
  if (data.length < offset + 1) {
32
34
  revert InvalidBodyIdLength();
33
35
  }
34
- uint8 bodyIdTypeValue = uint8(data[offset]);
35
- BodyIdType bodyIdType = BodyIdType(bodyIdTypeValue);
36
+ uint8 variantValue = uint8(data[offset]);
37
+ BodyIdVariant variant = BodyIdVariant(variantValue);
36
38
  uint256 payloadLength;
37
39
  if (
38
- bodyIdType == BodyIdType.Unit ||
39
- bodyIdType == BodyIdType.Executive ||
40
- bodyIdType == BodyIdType.Technical ||
41
- bodyIdType == BodyIdType.Legislative ||
42
- bodyIdType == BodyIdType.Judicial ||
43
- bodyIdType == BodyIdType.Defense ||
44
- bodyIdType == BodyIdType.Administration ||
45
- bodyIdType == BodyIdType.Treasury
40
+ variant == BodyIdVariant.Unit ||
41
+ variant == BodyIdVariant.Executive ||
42
+ variant == BodyIdVariant.Technical ||
43
+ variant == BodyIdVariant.Legislative ||
44
+ variant == BodyIdVariant.Judicial ||
45
+ variant == BodyIdVariant.Defense ||
46
+ variant == BodyIdVariant.Administration ||
47
+ variant == BodyIdVariant.Treasury
46
48
  ) {
47
49
  payloadLength = 0;
48
- } else if (bodyIdType == BodyIdType.Moniker) {
50
+ } else if (variant == BodyIdVariant.Moniker) {
49
51
  payloadLength = 4;
50
- } else if (bodyIdType == BodyIdType.Index) {
52
+ } else if (variant == BodyIdVariant.Index) {
51
53
  payloadLength = 4;
52
54
  } else {
53
- revert InvalidBodyIdType(bodyIdTypeValue);
55
+ revert InvalidBodyIdVariant(variantValue);
54
56
  }
55
57
 
56
58
  if (data.length < offset + 1 + payloadLength) {
@@ -79,50 +81,41 @@ library BodyIdCodec {
79
81
  bytes memory data,
80
82
  uint256 offset
81
83
  ) internal pure returns (BodyId memory bodyId, uint256 bytesRead) {
82
- if (data.length < offset + 1) {
83
- revert InvalidBodyIdLength();
84
- }
85
- uint8 bodyIdTypeValue = uint8(data[offset]);
86
- BodyIdType bodyIdType = BodyIdType(bodyIdTypeValue);
87
- uint256 payloadLength = encodedSizeAt(data, offset) - 1; // subtract 1 byte for the bodyIdType
88
- bytes memory payload = new bytes(payloadLength);
89
-
90
- for (uint256 i = 0; i < payloadLength; i++) {
91
- payload[i] = data[offset + 1 + i];
92
- }
93
-
94
- bodyId = BodyId({bodyIdType: bodyIdType, payload: payload});
84
+ uint256 payloadLength = encodedSizeAt(data, offset) - 1; // subtract 1 byte for the variant
85
+ uint8 variantValue = uint8(data[offset]);
86
+ BodyIdVariant variant = BodyIdVariant(variantValue);
87
+ bytes memory payload = BytesUtils.copy(data, offset + 1, payloadLength);
88
+ bodyId = BodyId({variant: variant, payload: payload});
95
89
  bytesRead = 1 + payloadLength;
96
90
  }
97
91
 
98
92
  /// @notice Helper function to decode a `BodyId` and extract the moniker name if the type is `Moniker`.
99
93
  /// @param bodyId The `BodyId` to extract the moniker name from.
100
- /// @return name The 4-byte name of the moniker if the `bodyIdType` is `Moniker`.
94
+ /// @return params A `MonikerParams` struct containing the moniker name if the `variant` is `Moniker`.
101
95
  function asMoniker(
102
96
  BodyId memory bodyId
103
- ) internal pure returns (bytes4 name) {
104
- if (bodyId.bodyIdType != BodyIdType.Moniker) {
105
- revert InvalidBodyIdType(uint8(bodyId.bodyIdType));
106
- }
107
- return Bytes4.decode(bodyId.payload);
97
+ ) internal pure returns (MonikerParams memory params) {
98
+ _assertVariant(bodyId, BodyIdVariant.Moniker);
99
+ params.name = Bytes4.decode(bodyId.payload);
108
100
  }
109
101
 
110
102
  /// @notice Helper function to decode a `BodyId` and extract the index if the type is `Index`.
111
103
  /// @param bodyId The `BodyId` to extract the index from.
112
- /// @return idx The index of the body if the `bodyIdType` is `Index`.
113
- function asIndex(BodyId memory bodyId) internal pure returns (uint32 idx) {
114
- if (bodyId.bodyIdType != BodyIdType.Index) {
115
- revert InvalidBodyIdType(uint8(bodyId.bodyIdType));
116
- }
117
- if (bodyId.payload.length != 4) {
118
- revert InvalidBodyIdLength();
119
- }
104
+ /// @return params An `IndexParams` struct containing the index if the `variant` is `Index`.
105
+ function asIndex(
106
+ BodyId memory bodyId
107
+ ) internal pure returns (IndexParams memory params) {
108
+ _assertVariant(bodyId, BodyIdVariant.Index);
120
109
  (uint256 decodedIndex, ) = Compact.decode(bodyId.payload);
121
- if (decodedIndex > type(uint32).max) {
122
- revert InvalidBodyIdLength();
123
- }
124
- unchecked {
125
- idx = uint32(decodedIndex);
110
+ params.index = UnsignedUtils.toU32(decodedIndex);
111
+ }
112
+
113
+ function _assertVariant(
114
+ BodyId memory bodyId,
115
+ BodyIdVariant expected
116
+ ) internal pure {
117
+ if (bodyId.variant != expected) {
118
+ revert InvalidBodyIdVariant(uint8(bodyId.variant));
126
119
  }
127
120
  }
128
121
  }
@@ -4,7 +4,7 @@ pragma solidity ^0.8.28;
4
4
  import {Compact} from "../../../Scale/Compact.sol";
5
5
 
6
6
  /// @dev Discriminant for the different types of BodyParts in XCM v5. Each variant corresponds to a specific structure of the payload.
7
- enum BodyPartType {
7
+ enum BodyPartVariant {
8
8
  /// @custom:variant The body's declaration, under whatever means it decides.
9
9
  Voice,
10
10
  /// @custom:variant A given number of members of the body.
@@ -19,8 +19,8 @@ enum BodyPartType {
19
19
 
20
20
  /// @notice A part of a pluralistic body.
21
21
  struct BodyPart {
22
- /// @custom:property The type of BodyPart, which determines how to interpret the payload. See `BodyPartType` enum for possible values.
23
- BodyPartType bodyPartType;
22
+ /// @custom:property The type of BodyPart, which determines how to interpret the payload. See `BodyPartVariant` enum for possible values.
23
+ BodyPartVariant variant;
24
24
  /// @custom:property For Members, this will hold the count. For Fraction, AtLeastProportion, and MoreThanProportion, this will hold the encoded Proportion struct. For Voice, this will be empty.
25
25
  bytes payload;
26
26
  }
@@ -31,12 +31,36 @@ struct MembersParams {
31
31
  uint32 count;
32
32
  }
33
33
 
34
+ /// @notice Parameters for the `Fraction` variant.
35
+ struct FractionParams {
36
+ /// @custom:property The numerator of the fraction, representing the number of members in favor.
37
+ uint32 nominator;
38
+ /// @custom:property The denominator of the fraction, representing the total number of members considered.
39
+ uint32 denominator;
40
+ }
41
+
42
+ /// @notice Parameters for the `AtLeastProportion` variant.
43
+ struct AtLeastProportionParams {
44
+ /// @custom:property The numerator of the proportion, representing the minimum number of members in favor.
45
+ uint32 nominator;
46
+ /// @custom:property The denominator of the proportion, representing the total number of members considered.
47
+ uint32 denominator;
48
+ }
49
+
50
+ /// @notice Parameters for the `MoreThanProportion` variant.
51
+ struct MoreThanProportionParams {
52
+ /// @custom:property The numerator of the proportion, representing the minimum number of members in favor.
53
+ uint32 nominator;
54
+ /// @custom:property The denominator of the proportion, representing the total number of members considered.
55
+ uint32 denominator;
56
+ }
57
+
34
58
  // ============ Factory Functions ============
35
59
 
36
60
  /// @notice Creates a `BodyPart` struct representing a `Voice` body part.
37
61
  /// @return A `BodyPart` with the `Voice` variant.
38
62
  function voice() pure returns (BodyPart memory) {
39
- return BodyPart({bodyPartType: BodyPartType.Voice, payload: ""});
63
+ return BodyPart({variant: BodyPartVariant.Voice, payload: ""});
40
64
  }
41
65
 
42
66
  /// @notice Creates a `BodyPart` struct representing a `Members` body part with the given count.
@@ -45,61 +69,53 @@ function voice() pure returns (BodyPart memory) {
45
69
  function members(MembersParams memory params) pure returns (BodyPart memory) {
46
70
  return
47
71
  BodyPart({
48
- bodyPartType: BodyPartType.Members,
72
+ variant: BodyPartVariant.Members,
49
73
  payload: Compact.encode(params.count)
50
74
  });
51
75
  }
52
76
 
53
77
  /// @notice Creates a `BodyPart` struct representing a `Fraction` body part with the given proportion.
54
- /// @param nominator The numerator of the proportion, representing the number of members in favor.
55
- /// @param denominator The denominator of the proportion, representing the total number of members considered.
78
+ /// @param params Parameters for the fraction variant.
56
79
  /// @return A `BodyPart` with the `Fraction` variant and the encoded proportion in the payload.
57
- function fraction(
58
- uint32 nominator,
59
- uint32 denominator
60
- ) pure returns (BodyPart memory) {
80
+ function fraction(FractionParams memory params) pure returns (BodyPart memory) {
61
81
  return
62
82
  BodyPart({
63
- bodyPartType: BodyPartType.Fraction,
83
+ variant: BodyPartVariant.Fraction,
64
84
  payload: abi.encodePacked(
65
- Compact.encode(nominator),
66
- Compact.encode(denominator)
85
+ Compact.encode(params.nominator),
86
+ Compact.encode(params.denominator)
67
87
  )
68
88
  });
69
89
  }
70
90
 
71
91
  /// @notice Creates a `BodyPart` struct representing an `AtLeastProportion` body part with the given proportion.
72
- /// @param nominator The numerator of the proportion, representing the minimum number of members in favor.
73
- /// @param denominator The denominator of the proportion, representing the total number of members considered.
92
+ /// @param params Parameters for the at least proportion variant.
74
93
  /// @return A `BodyPart` with the `AtLeastProportion` variant and the encoded proportion in the payload.
75
94
  function atLeastProportion(
76
- uint32 nominator,
77
- uint32 denominator
95
+ AtLeastProportionParams memory params
78
96
  ) pure returns (BodyPart memory) {
79
97
  return
80
98
  BodyPart({
81
- bodyPartType: BodyPartType.AtLeastProportion,
99
+ variant: BodyPartVariant.AtLeastProportion,
82
100
  payload: abi.encodePacked(
83
- Compact.encode(nominator),
84
- Compact.encode(denominator)
101
+ Compact.encode(params.nominator),
102
+ Compact.encode(params.denominator)
85
103
  )
86
104
  });
87
105
  }
88
106
 
89
107
  /// @notice Creates a `BodyPart` struct representing a `MoreThanProportion` body part with the given proportion.
90
- /// @param nominator The numerator of the proportion, representing the minimum number of members in favor.
91
- /// @param denominator The denominator of the proportion, representing the total number of members considered.
108
+ /// @param params Parameters for the more than proportion variant.
92
109
  /// @return A `BodyPart` with the `MoreThanProportion` variant and the encoded proportion in the payload.
93
110
  function moreThanProportion(
94
- uint32 nominator,
95
- uint32 denominator
111
+ MoreThanProportionParams memory params
96
112
  ) pure returns (BodyPart memory) {
97
113
  return
98
114
  BodyPart({
99
- bodyPartType: BodyPartType.MoreThanProportion,
115
+ variant: BodyPartVariant.MoreThanProportion,
100
116
  payload: abi.encodePacked(
101
- Compact.encode(nominator),
102
- Compact.encode(denominator)
117
+ Compact.encode(params.nominator),
118
+ Compact.encode(params.denominator)
103
119
  )
104
120
  });
105
121
  }
@@ -2,7 +2,16 @@
2
2
  pragma solidity ^0.8.28;
3
3
 
4
4
  import {Compact} from "../../../Scale/Compact.sol";
5
- import {BodyPart, BodyPartType} from "./BodyPart.sol";
5
+ import {
6
+ BodyPart,
7
+ BodyPartVariant,
8
+ MembersParams,
9
+ FractionParams,
10
+ AtLeastProportionParams,
11
+ MoreThanProportionParams
12
+ } from "./BodyPart.sol";
13
+ import {BytesUtils} from "../../../Utils/BytesUtils.sol";
14
+ import {UnsignedUtils} from "../../../Utils/UnsignedUtils.sol";
6
15
 
7
16
  /// @title SCALE Codec for XCM v5 `BodyPart`
8
17
  /// @notice SCALE-compliant encoder/decoder for the `BodyPart` type.
@@ -10,8 +19,7 @@ import {BodyPart, BodyPartType} from "./BodyPart.sol";
10
19
  /// @dev XCM v5 reference: https://paritytech.github.io/polkadot-sdk/master/staging_xcm/v5/index.html
11
20
  library BodyPartCodec {
12
21
  error InvalidBodyPartLength();
13
- error InvalidBodyPartType(uint8 bodyPartType);
14
- error InvalidBodyPartPayload();
22
+ error InvalidBodyPartVariant(uint8 variant);
15
23
 
16
24
  /// @notice Encodes a `BodyPart` struct into bytes.
17
25
  /// @param bodyPart The `BodyPart` struct to encode.
@@ -19,7 +27,7 @@ library BodyPartCodec {
19
27
  function encode(
20
28
  BodyPart memory bodyPart
21
29
  ) internal pure returns (bytes memory) {
22
- return abi.encodePacked(uint8(bodyPart.bodyPartType), bodyPart.payload);
30
+ return abi.encodePacked(uint8(bodyPart.variant), bodyPart.payload);
23
31
  }
24
32
 
25
33
  /// @notice Returns the number of bytes that a `BodyPart` struct would occupy when SCALE-encoded.
@@ -32,23 +40,23 @@ library BodyPartCodec {
32
40
  ) internal pure returns (uint256) {
33
41
  if (offset >= data.length) revert InvalidBodyPartLength();
34
42
 
35
- uint8 bodyPartType = uint8(data[offset]);
43
+ uint8 variant = uint8(data[offset]);
36
44
  uint256 payloadLength;
37
- if (bodyPartType == uint8(BodyPartType.Voice)) {
45
+ if (variant == uint8(BodyPartVariant.Voice)) {
38
46
  payloadLength = 0;
39
- } else if (bodyPartType == uint8(BodyPartType.Members)) {
47
+ } else if (variant == uint8(BodyPartVariant.Members)) {
40
48
  payloadLength = Compact.encodedSizeAt(data, offset + 1);
41
49
  } else if (
42
- bodyPartType == uint8(BodyPartType.Fraction) ||
43
- bodyPartType == uint8(BodyPartType.AtLeastProportion) ||
44
- bodyPartType == uint8(BodyPartType.MoreThanProportion)
50
+ variant == uint8(BodyPartVariant.Fraction) ||
51
+ variant == uint8(BodyPartVariant.AtLeastProportion) ||
52
+ variant == uint8(BodyPartVariant.MoreThanProportion)
45
53
  ) {
46
54
  uint256 innerLength = Compact.encodedSizeAt(data, offset + 1);
47
55
  payloadLength =
48
56
  innerLength +
49
57
  Compact.encodedSizeAt(data, offset + 1 + innerLength);
50
58
  } else {
51
- revert InvalidBodyPartType(bodyPartType);
59
+ revert InvalidBodyPartVariant(variant);
52
60
  }
53
61
 
54
62
  if (data.length < offset + 1 + payloadLength) {
@@ -77,18 +85,13 @@ library BodyPartCodec {
77
85
  bytes memory data,
78
86
  uint256 offset
79
87
  ) internal pure returns (BodyPart memory bodyPart, uint256 bytesRead) {
80
- if (offset >= data.length) revert InvalidBodyPartLength();
81
-
82
- uint8 bodyPartType = uint8(data[offset]);
83
- uint256 payloadLength = encodedSizeAt(data, offset) - 1; // total size minus 1 byte for the bodyPartType
88
+ uint256 payloadLength = encodedSizeAt(data, offset) - 1; // total size minus 1 byte for the variant
89
+ uint8 variant = uint8(data[offset]);
84
90
 
85
- bytes memory payload = new bytes(payloadLength);
86
- for (uint256 i = 0; i < payloadLength; i++) {
87
- payload[i] = data[offset + 1 + i];
88
- }
91
+ bytes memory payload = BytesUtils.copy(data, offset + 1, payloadLength);
89
92
 
90
93
  bodyPart = BodyPart({
91
- bodyPartType: BodyPartType(bodyPartType),
94
+ variant: BodyPartVariant(variant),
92
95
  payload: payload
93
96
  });
94
97
  bytesRead = 1 + payloadLength;
@@ -96,31 +99,52 @@ library BodyPartCodec {
96
99
 
97
100
  /// @notice Decodes a `Members` body part to extract the member count.
98
101
  /// @param bodyPart The `BodyPart` struct to decode, which must be of type `Members`.
99
- /// @return count The number of members encoded in the body part's payload.
102
+ /// @return params A `MembersParams` struct containing the member count encoded in the body part's payload.
100
103
  function asMembers(
101
104
  BodyPart memory bodyPart
102
- ) internal pure returns (uint32 count) {
103
- if (bodyPart.bodyPartType != BodyPartType.Members) {
104
- revert InvalidBodyPartType(uint8(bodyPart.bodyPartType));
105
- }
105
+ ) internal pure returns (MembersParams memory params) {
106
+ _assertVariant(bodyPart, BodyPartVariant.Members);
106
107
  (uint256 decodedCount, ) = Compact.decode(bodyPart.payload);
107
- count = uint32(decodedCount);
108
+ params.count = UnsignedUtils.toU32(decodedCount);
109
+ }
110
+
111
+ /// @notice Decodes a `Fraction` body part to extract the nominator and denominator.
112
+ /// @param bodyPart The `BodyPart` struct to decode, which must be of type `Fraction`.
113
+ /// @return params A `FractionParams` struct containing the nominator and denominator encoded in the body part's payload.
114
+ function asFraction(
115
+ BodyPart memory bodyPart
116
+ ) internal pure returns (FractionParams memory params) {
117
+ _assertVariant(bodyPart, BodyPartVariant.Fraction);
118
+ (params.nominator, params.denominator) = _asProportion(bodyPart);
119
+ }
120
+
121
+ /// @notice Decodes a `AtLeastProportion` body part to extract the nominator and denominator.
122
+ /// @param bodyPart The `BodyPart` struct to decode, which must be of type `AtLeastProportion`.
123
+ /// @return params An `AtLeastProportionParams` struct containing the nominator and denominator encoded in the body part's payload.
124
+ function asAtLeastProportion(
125
+ BodyPart memory bodyPart
126
+ ) internal pure returns (AtLeastProportionParams memory params) {
127
+ _assertVariant(bodyPart, BodyPartVariant.AtLeastProportion);
128
+ (params.nominator, params.denominator) = _asProportion(bodyPart);
129
+ }
130
+
131
+ /// @notice Decodes a `MoreThanProportion` body part to extract the nominator and denominator.
132
+ /// @param bodyPart The `BodyPart` struct to decode, which must be of type `MoreThanProportion`.
133
+ /// @return params A `MoreThanProportionParams` struct containing the nominator and denominator encoded in the body part's payload.
134
+ function asMoreThanProportion(
135
+ BodyPart memory bodyPart
136
+ ) internal pure returns (MoreThanProportionParams memory params) {
137
+ _assertVariant(bodyPart, BodyPartVariant.MoreThanProportion);
138
+ (params.nominator, params.denominator) = _asProportion(bodyPart);
108
139
  }
109
140
 
110
141
  /// @notice Decodes a `Fraction`, `AtLeastProportion`, or `MoreThanProportion` body part to extract the nominator and denominator.
111
142
  /// @param bodyPart The `BodyPart` struct to decode, which must be of type `Fraction`, `AtLeastProportion`, or `MoreThanProportion`.
112
143
  /// @return nominator The numerator of the proportion encoded in the body part's payload.
113
144
  /// @return denominator The denominator of the proportion encoded in the body part's payload.
114
- function asProportion(
145
+ function _asProportion(
115
146
  BodyPart memory bodyPart
116
- ) internal pure returns (uint32 nominator, uint32 denominator) {
117
- if (
118
- bodyPart.bodyPartType != BodyPartType.Fraction &&
119
- bodyPart.bodyPartType != BodyPartType.AtLeastProportion &&
120
- bodyPart.bodyPartType != BodyPartType.MoreThanProportion
121
- ) {
122
- revert InvalidBodyPartType(uint8(bodyPart.bodyPartType));
123
- }
147
+ ) private pure returns (uint32 nominator, uint32 denominator) {
124
148
  (uint256 decodedNominator, uint256 offset) = Compact.decode(
125
149
  bodyPart.payload
126
150
  );
@@ -128,7 +152,16 @@ library BodyPartCodec {
128
152
  bodyPart.payload,
129
153
  offset
130
154
  );
131
- nominator = uint32(decodedNominator);
132
- denominator = uint32(decodedDenominator);
155
+ nominator = UnsignedUtils.toU32(decodedNominator);
156
+ denominator = UnsignedUtils.toU32(decodedDenominator);
157
+ }
158
+
159
+ function _assertVariant(
160
+ BodyPart memory bodyPart,
161
+ BodyPartVariant expected
162
+ ) internal pure {
163
+ if (bodyPart.variant != expected) {
164
+ revert InvalidBodyPartVariant(uint8(bodyPart.variant));
165
+ }
133
166
  }
134
167
  }
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  pragma solidity ^0.8.28;
3
3
 
4
- import {HintType} from "./Hint/Hint.sol";
4
+ import {HintVariant} from "./Hint/Hint.sol";
5
5
 
6
6
  // Maximum number of items we expect in a single Assets value.
7
7
  uint64 constant MAX_ITEMS_IN_ASSETS = 20;
@@ -12,4 +12,4 @@ uint32 constant MAX_ASSET_TRANSFER_FILTERS = 6;
12
12
  // Maximum length of a pallet name in bytes.
13
13
  uint32 constant MAX_PALLET_NAME_LEN = 48;
14
14
  // Maximum number of hints in a `SetHints` instruction, equal to the number of variants in the `Hint` enum.
15
- uint32 constant HINT_NUM_VARIANTS = uint32(type(HintType).max) + 1;
15
+ uint32 constant HINT_NUM_VARIANTS = uint32(type(HintVariant).max) + 1;
@@ -6,7 +6,7 @@ import {AssetInstance} from "../AssetInstance/AssetInstance.sol";
6
6
  import {AssetInstanceCodec} from "../AssetInstance/AssetInstanceCodec.sol";
7
7
 
8
8
  /// @dev Discriminant for the different types of Fungibility in XCM v5.
9
- enum FungibilityType {
9
+ enum FungibilityVariant {
10
10
  /// @custom:variant A fungible asset; we record a number of units, as a `uint128` in the inner item.
11
11
  Fungible,
12
12
  /// @custom:variant A non-fungible asset. We record the instance identifier in the inner item. Only one asset of each instance identifier may ever be in existence at once.
@@ -15,9 +15,9 @@ enum FungibilityType {
15
15
 
16
16
  /// @notice Classification of whether an asset is fungible or not, along with a mandatory amount or instance.
17
17
  struct Fungibility {
18
- /// @custom:property The type of fungibility, determining how to interpret the payload. See `FungibilityType` enum for possible values.
19
- FungibilityType fType;
20
- /// @custom:property The encoded payload containing the fungibility data, whose structure depends on the `fType`.
18
+ /// @custom:property The type of fungibility, determining how to interpret the payload. See `FungibilityVariant` enum for possible values.
19
+ FungibilityVariant variant;
20
+ /// @custom:property The encoded payload containing the fungibility data, whose structure depends on the `variant`.
21
21
  bytes payload;
22
22
  }
23
23
 
@@ -42,7 +42,7 @@ function fungible(
42
42
  ) pure returns (Fungibility memory) {
43
43
  return
44
44
  Fungibility({
45
- fType: FungibilityType.Fungible,
45
+ variant: FungibilityVariant.Fungible,
46
46
  payload: Compact.encode(params.amount)
47
47
  });
48
48
  }
@@ -54,7 +54,7 @@ function nonFungible(
54
54
  ) pure returns (Fungibility memory) {
55
55
  return
56
56
  Fungibility({
57
- fType: FungibilityType.NonFungible,
57
+ variant: FungibilityVariant.NonFungible,
58
58
  payload: AssetInstanceCodec.encode(params.instance)
59
59
  });
60
60
  }
@@ -4,7 +4,14 @@ pragma solidity ^0.8.28;
4
4
  import {Compact} from "../../../Scale/Compact.sol";
5
5
  import {AssetInstance} from "../AssetInstance/AssetInstance.sol";
6
6
  import {AssetInstanceCodec} from "../AssetInstance/AssetInstanceCodec.sol";
7
- import {Fungibility, FungibilityType} from "./Fungibility.sol";
7
+ import {
8
+ Fungibility,
9
+ FungibilityVariant,
10
+ FungibleParams,
11
+ NonFungibleParams
12
+ } from "./Fungibility.sol";
13
+ import {BytesUtils} from "../../../Utils/BytesUtils.sol";
14
+ import {UnsignedUtils} from "../../../Utils/UnsignedUtils.sol";
8
15
 
9
16
  /// @title SCALE Codec for XCM v5 `Fungibility`
10
17
  /// @notice SCALE-compliant encoder/decoder for the `Fungibility` type.
@@ -12,8 +19,7 @@ import {Fungibility, FungibilityType} from "./Fungibility.sol";
12
19
  /// @dev XCM v5 reference: https://paritytech.github.io/polkadot-sdk/master/staging_xcm/v5/index.html
13
20
  library FungibilityCodec {
14
21
  error InvalidFungibilityLength();
15
- error InvalidFungibilityType(uint8 fType);
16
- error InvalidFungibilityPayload();
22
+ error InvalidFungibilityVariant(uint8 variant);
17
23
 
18
24
  /// @notice Encodes a `Fungibility` struct into bytes.
19
25
  /// @param fungibility The `Fungibility` struct to encode.
@@ -21,7 +27,8 @@ library FungibilityCodec {
21
27
  function encode(
22
28
  Fungibility memory fungibility
23
29
  ) internal pure returns (bytes memory) {
24
- return abi.encodePacked(uint8(fungibility.fType), fungibility.payload);
30
+ return
31
+ abi.encodePacked(uint8(fungibility.variant), fungibility.payload);
25
32
  }
26
33
 
27
34
  /// @notice Returns the number of bytes that a `Fungibility` struct would occupy when SCALE-encoded, starting at a given offset in the data.
@@ -35,15 +42,15 @@ library FungibilityCodec {
35
42
  if (data.length < offset + 1) {
36
43
  revert InvalidFungibilityLength();
37
44
  }
38
- uint8 fType = uint8(data[offset]);
45
+ uint8 variant = uint8(data[offset]);
39
46
  uint256 payloadLength;
40
47
  ++offset;
41
- if (fType == uint8(FungibilityType.Fungible)) {
48
+ if (variant == uint8(FungibilityVariant.Fungible)) {
42
49
  payloadLength = Compact.encodedSizeAt(data, offset);
43
- } else if (fType == uint8(FungibilityType.NonFungible)) {
50
+ } else if (variant == uint8(FungibilityVariant.NonFungible)) {
44
51
  payloadLength = AssetInstanceCodec.encodedSizeAt(data, offset);
45
52
  } else {
46
- revert InvalidFungibilityType(fType);
53
+ revert InvalidFungibilityVariant(variant);
47
54
  }
48
55
 
49
56
  if (data.length < offset + payloadLength) {
@@ -80,49 +87,46 @@ library FungibilityCodec {
80
87
  pure
81
88
  returns (Fungibility memory fungibility, uint256 bytesRead)
82
89
  {
83
- if (data.length < offset + 1) {
84
- revert InvalidFungibilityLength();
85
- }
86
- uint8 fType = uint8(data[offset]);
87
- uint256 payloadLength = encodedSizeAt(data, offset) - 1; // subtract 1 byte for the fType
88
- bytes memory payload = new bytes(payloadLength);
89
- for (uint256 i = 0; i < payloadLength; i++) {
90
- payload[i] = data[offset + 1 + i];
91
- }
90
+ uint256 payloadLength = encodedSizeAt(data, offset) - 1; // subtract 1 byte for the variant
91
+ uint8 variant = uint8(data[offset]);
92
+ bytes memory payload = BytesUtils.copy(data, offset + 1, payloadLength);
92
93
 
93
94
  return (
94
- Fungibility({fType: FungibilityType(fType), payload: payload}),
95
+ Fungibility({
96
+ variant: FungibilityVariant(variant),
97
+ payload: payload
98
+ }),
95
99
  1 + payloadLength
96
100
  );
97
101
  }
98
102
 
99
103
  /// @notice Decodes a `Fungibility` struct representing a fungible asset and extracts the amount.
100
- /// @param fungibility The `Fungibility` struct to decode, which must have `fType` equal to `FungibilityType.Fungible`.
101
- /// @return amount The number of units of the fungible asset, as a `uint128`.
104
+ /// @param fungibility The `Fungibility` struct to decode, which must have `variant` equal to `FungibilityVariant.Fungible`.
105
+ /// @return params A `FungibleParams` struct containing the amount of the fungible asset.
102
106
  function asFungible(
103
107
  Fungibility memory fungibility
104
- ) internal pure returns (uint128 amount) {
105
- if (fungibility.fType != FungibilityType.Fungible) {
106
- revert InvalidFungibilityType(uint8(fungibility.fType));
107
- }
108
+ ) internal pure returns (FungibleParams memory params) {
109
+ _assertVariant(fungibility, FungibilityVariant.Fungible);
108
110
  (uint256 decodedAmount, ) = Compact.decode(fungibility.payload);
109
- if (decodedAmount > type(uint128).max) {
110
- revert InvalidFungibilityPayload();
111
- }
112
- unchecked {
113
- amount = uint128(decodedAmount);
114
- }
111
+ params.amount = UnsignedUtils.toU128(decodedAmount);
115
112
  }
116
113
 
117
114
  /// @notice Decodes a `Fungibility` struct representing a non-fungible asset and extracts the instance identifier.
118
- /// @param fungibility The `Fungibility` struct to decode, which must have `fType` equal to `FungibilityType.NonFungible`.
119
- /// @return instance The `AssetInstance` struct identifying the specific instance of the non-fungible asset.
115
+ /// @param fungibility The `Fungibility` struct to decode, which must have `variant` equal to `FungibilityVariant.NonFungible`.
116
+ /// @return params A `NonFungibleParams` struct containing the specific non-fungible asset instance.
120
117
  function asNonFungible(
121
118
  Fungibility memory fungibility
122
- ) internal pure returns (AssetInstance memory instance) {
123
- if (fungibility.fType != FungibilityType.NonFungible) {
124
- revert InvalidFungibilityType(uint8(fungibility.fType));
119
+ ) internal pure returns (NonFungibleParams memory params) {
120
+ _assertVariant(fungibility, FungibilityVariant.NonFungible);
121
+ (params.instance, ) = AssetInstanceCodec.decode(fungibility.payload);
122
+ }
123
+
124
+ function _assertVariant(
125
+ Fungibility memory fungibility,
126
+ FungibilityVariant expected
127
+ ) private pure {
128
+ if (fungibility.variant != expected) {
129
+ revert InvalidFungibilityVariant(uint8(fungibility.variant));
125
130
  }
126
- (instance, ) = AssetInstanceCodec.decode(fungibility.payload);
127
131
  }
128
132
  }