solidity-scale-codec 0.1.2 → 0.2.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 (104) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/DEFINITIONS.md +132 -0
  3. package/README.md +95 -1
  4. package/package.json +8 -3
  5. package/src/LittleEndian/LittleEndianU128.sol +4 -2
  6. package/src/LittleEndian/LittleEndianU16.sol +2 -2
  7. package/src/LittleEndian/LittleEndianU256.sol +4 -2
  8. package/src/LittleEndian/LittleEndianU32.sol +4 -2
  9. package/src/LittleEndian/LittleEndianU64.sol +4 -2
  10. package/src/LittleEndian/LittleEndianU8.sol +2 -2
  11. package/src/Scale/Address/Address.sol +55 -0
  12. package/src/Scale/Address.sol +4 -0
  13. package/src/Scale/Array/BoolArr.sol +16 -2
  14. package/src/Scale/Array/I128Arr.sol +16 -2
  15. package/src/Scale/Array/I16Arr.sol +16 -2
  16. package/src/Scale/Array/I256Arr.sol +16 -2
  17. package/src/Scale/Array/I32Arr.sol +16 -2
  18. package/src/Scale/Array/I64Arr.sol +16 -2
  19. package/src/Scale/Array/I8Arr.sol +16 -2
  20. package/src/Scale/Array/U128Arr.sol +16 -2
  21. package/src/Scale/Array/U16Arr.sol +16 -2
  22. package/src/Scale/Array/U256Arr.sol +16 -2
  23. package/src/Scale/Array/U32Arr.sol +16 -2
  24. package/src/Scale/Array/U64Arr.sol +16 -2
  25. package/src/Scale/Array/U8Arr.sol +16 -2
  26. package/src/Scale/Bool/Bool.sol +12 -0
  27. package/src/Scale/Bytes/Bytes.sol +63 -0
  28. package/src/Scale/Bytes/Bytes16.sol +53 -0
  29. package/src/Scale/Bytes/Bytes2.sol +53 -0
  30. package/src/Scale/Bytes/Bytes32.sol +53 -0
  31. package/src/Scale/Bytes/Bytes4.sol +53 -0
  32. package/src/Scale/Bytes/Bytes8.sol +53 -0
  33. package/src/Scale/Bytes.sol +8 -0
  34. package/src/Scale/Compact/Compact.sol +37 -3
  35. package/src/Scale/Signed/I128.sol +11 -0
  36. package/src/Scale/Signed/I16.sol +11 -0
  37. package/src/Scale/Signed/I256.sol +11 -0
  38. package/src/Scale/Signed/I32.sol +11 -0
  39. package/src/Scale/Signed/I64.sol +11 -0
  40. package/src/Scale/Signed/I8.sol +11 -0
  41. package/src/Scale/Unsigned/U128.sol +16 -2
  42. package/src/Scale/Unsigned/U16.sol +16 -2
  43. package/src/Scale/Unsigned/U256.sol +16 -2
  44. package/src/Scale/Unsigned/U32.sol +16 -2
  45. package/src/Scale/Unsigned/U64.sol +16 -2
  46. package/src/Scale/Unsigned/U8.sol +16 -2
  47. package/src/Xcm/Types/Version.sol +5 -0
  48. package/src/Xcm/VersionedXcm/VersionedXcm.sol +27 -0
  49. package/src/Xcm/VersionedXcm/VersionedXcmCodec.sol +70 -0
  50. package/src/Xcm/v3/Constants.sol +5 -0
  51. package/src/Xcm/v3/MaybeErrorCode/MaybeErrorCode.sol +73 -0
  52. package/src/Xcm/v3/MaybeErrorCode/MaybeErrorCodeCodec.sol +94 -0
  53. package/src/Xcm/v5/Asset/Asset.sol +13 -0
  54. package/src/Xcm/v5/Asset/AssetCodec.sol +72 -0
  55. package/src/Xcm/v5/AssetFilter/AssetFilter.sol +61 -0
  56. package/src/Xcm/v5/AssetFilter/AssetFilterCodec.sol +105 -0
  57. package/src/Xcm/v5/AssetId/AssetId.sol +10 -0
  58. package/src/Xcm/v5/AssetId/AssetIdCodec.sol +57 -0
  59. package/src/Xcm/v5/AssetInstance/AssetInstance.sol +139 -0
  60. package/src/Xcm/v5/AssetInstance/AssetInstanceCodec.sol +174 -0
  61. package/src/Xcm/v5/AssetTransferFilter/AssetTransferFilter.sol +82 -0
  62. package/src/Xcm/v5/AssetTransferFilter/AssetTransferFilterCodec.sol +95 -0
  63. package/src/Xcm/v5/Assets/Assets.sol +14 -0
  64. package/src/Xcm/v5/Assets/AssetsCodec.sol +94 -0
  65. package/src/Xcm/v5/BodyId/BodyId.sol +121 -0
  66. package/src/Xcm/v5/BodyId/BodyIdCodec.sol +128 -0
  67. package/src/Xcm/v5/BodyPart/BodyPart.sol +105 -0
  68. package/src/Xcm/v5/BodyPart/BodyPartCodec.sol +134 -0
  69. package/src/Xcm/v5/Constants.sol +15 -0
  70. package/src/Xcm/v5/Fungibility/Fungibility.sol +60 -0
  71. package/src/Xcm/v5/Fungibility/FungibilityCodec.sol +128 -0
  72. package/src/Xcm/v5/Hint/Hint.sol +40 -0
  73. package/src/Xcm/v5/Hint/HintCodec.sol +82 -0
  74. package/src/Xcm/v5/Instruction/Instruction.sol +1217 -0
  75. package/src/Xcm/v5/Instruction/InstructionCodec.sol +321 -0
  76. package/src/Xcm/v5/Junction/Junction.sol +258 -0
  77. package/src/Xcm/v5/Junction/JunctionCodec.sol +329 -0
  78. package/src/Xcm/v5/Junctions/Junctions.sol +12 -0
  79. package/src/Xcm/v5/Junctions/JunctionsCodec.sol +120 -0
  80. package/src/Xcm/v5/Location/Location.sol +12 -0
  81. package/src/Xcm/v5/Location/LocationCodec.sol +68 -0
  82. package/src/Xcm/v5/NetworkId/NetworkId.sol +115 -0
  83. package/src/Xcm/v5/NetworkId/NetworkIdCodec.sol +114 -0
  84. package/src/Xcm/v5/OriginKind/OriginKind.sol +14 -0
  85. package/src/Xcm/v5/OriginKind/OriginKindCodec.sol +66 -0
  86. package/src/Xcm/v5/PalletInfo/PalletInfo.sol +18 -0
  87. package/src/Xcm/v5/PalletInfo/PalletInfoCodec.sol +119 -0
  88. package/src/Xcm/v5/QueryResponseInfo/QueryResponseInfo.sol +16 -0
  89. package/src/Xcm/v5/QueryResponseInfo/QueryResponseInfoCodec.sol +91 -0
  90. package/src/Xcm/v5/Response/Response.sol +145 -0
  91. package/src/Xcm/v5/Response/ResponseCodec.sol +174 -0
  92. package/src/Xcm/v5/Types/QueryId.sol +5 -0
  93. package/src/Xcm/v5/Weight/Weight.sol +10 -0
  94. package/src/Xcm/v5/Weight/WeightCodec.sol +87 -0
  95. package/src/Xcm/v5/WeightLimit/WeightLimit.sol +48 -0
  96. package/src/Xcm/v5/WeightLimit/WeightLimitCodec.sol +88 -0
  97. package/src/Xcm/v5/WildAsset/WildAsset.sol +112 -0
  98. package/src/Xcm/v5/WildAsset/WildAssetCodec.sol +166 -0
  99. package/src/Xcm/v5/WildFungibility/WildFungibility.sol +10 -0
  100. package/src/Xcm/v5/WildFungibility/WildFungibilityCodec.sol +74 -0
  101. package/src/Xcm/v5/Xcm/Xcm.sol +27 -0
  102. package/src/Xcm/v5/Xcm/XcmCodec.sol +83 -0
  103. package/src/Xcm/v5/XcmError/XcmError.sol +122 -0
  104. package/src/Xcm/v5/XcmError/XcmErrorCodec.sol +85 -0
@@ -0,0 +1,166 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.28;
3
+
4
+ import {Compact} from "../../../Scale/Compact.sol";
5
+ import {AssetIdCodec} from "../AssetId/AssetIdCodec.sol";
6
+ import {WildFungibilityCodec} from "../WildFungibility/WildFungibilityCodec.sol";
7
+ import {AssetId} from "../AssetId/AssetId.sol";
8
+ import {WildFungibility} from "../WildFungibility/WildFungibility.sol";
9
+ import {
10
+ WildAsset,
11
+ WildAssetType,
12
+ AllOfParams,
13
+ AllOfCountedParams
14
+ } from "./WildAsset.sol";
15
+
16
+ /// @title SCALE Codec for XCM v5 `WildAsset`
17
+ /// @notice SCALE-compliant encoder/decoder for the `WildAsset` type.
18
+ /// @dev SCALE reference: https://docs.polkadot.com/polkadot-protocol/basics/data-encoding
19
+ /// @dev XCM v5 reference: https://paritytech.github.io/polkadot-sdk/master/staging_xcm/v5/index.html
20
+ library WildAssetCodec {
21
+ error InvalidWildAssetLength();
22
+ error InvalidWildAssetType(uint8 waType);
23
+ error InvalidWildAssetPayload();
24
+
25
+ /// @notice Encodes a `WildAsset` struct into bytes.
26
+ /// @param wildAsset The `WildAsset` struct to encode.
27
+ /// @return SCALE-encoded byte sequence representing the `WildAsset`.
28
+ function encode(
29
+ WildAsset memory wildAsset
30
+ ) internal pure returns (bytes memory) {
31
+ return abi.encodePacked(uint8(wildAsset.waType), wildAsset.payload);
32
+ }
33
+
34
+ /// @notice Returns the number of bytes that a `WildAsset` struct would occupy when SCALE-encoded.
35
+ /// @param data The byte sequence containing the encoded `WildAsset`.
36
+ /// @param offset The starting index in `data` from which to calculate the encoded size of the `WildAsset`.
37
+ /// @return The number of bytes that the `WildAsset` struct would occupy when SCALE-encoded.
38
+ function encodedSizeAt(
39
+ bytes memory data,
40
+ uint256 offset
41
+ ) internal pure returns (uint256) {
42
+ if (offset >= data.length) {
43
+ revert InvalidWildAssetLength();
44
+ }
45
+ uint8 waType = uint8(data[offset]);
46
+ if (waType > uint8(WildAssetType.AllOfCounted)) {
47
+ revert InvalidWildAssetType(waType);
48
+ }
49
+ uint256 payloadLength;
50
+ if (waType == uint8(WildAssetType.All)) {
51
+ payloadLength = 0;
52
+ } else if (waType == uint8(WildAssetType.AllOf)) {
53
+ uint256 idSize = AssetIdCodec.encodedSizeAt(data, offset + 1);
54
+ payloadLength =
55
+ idSize +
56
+ WildFungibilityCodec.encodedSizeAt(data, offset + 1 + idSize);
57
+ } else if (waType == uint8(WildAssetType.AllCounted)) {
58
+ payloadLength = Compact.encodedSizeAt(data, offset + 1);
59
+ } else if (waType == uint8(WildAssetType.AllOfCounted)) {
60
+ uint256 idSize = AssetIdCodec.encodedSizeAt(data, offset + 1);
61
+ uint256 funSize = WildFungibilityCodec.encodedSizeAt(
62
+ data,
63
+ offset + 1 + idSize
64
+ );
65
+ payloadLength =
66
+ idSize +
67
+ funSize +
68
+ Compact.encodedSizeAt(data, offset + 1 + idSize + funSize);
69
+ } else {
70
+ revert InvalidWildAssetType(waType);
71
+ }
72
+ return 1 + payloadLength; // 1 byte for the waType
73
+ }
74
+
75
+ /// @notice Decodes a `WildAsset` instance from bytes starting at the beginning of the data.
76
+ /// @param data The byte sequence containing the encoded `WildAsset`.
77
+ /// @return wildAsset The decoded `WildAsset` struct.
78
+ /// @return bytesRead The total number of bytes read from `data` to decode the `WildAsset`.
79
+ function decode(
80
+ bytes memory data
81
+ ) internal pure returns (WildAsset memory wildAsset, uint256 bytesRead) {
82
+ return decodeAt(data, 0);
83
+ }
84
+
85
+ /// @notice Decodes a `WildAsset` instance from bytes starting at a given offset.
86
+ /// @param data The byte sequence containing the encoded `WildAsset`.
87
+ /// @param offset The starting index in `data` from which to decode the `WildAsset`.
88
+ /// @return wildAsset The decoded `WildAsset` struct.
89
+ /// @return bytesRead The total number of bytes read from `data` to decode the `WildAsset`.
90
+ function decodeAt(
91
+ bytes memory data,
92
+ uint256 offset
93
+ ) internal pure returns (WildAsset memory wildAsset, uint256 bytesRead) {
94
+ if (offset >= data.length) {
95
+ revert InvalidWildAssetLength();
96
+ }
97
+ uint8 waType = uint8(data[offset]);
98
+ if (waType > uint8(WildAssetType.AllOfCounted)) {
99
+ revert InvalidWildAssetType(waType);
100
+ }
101
+ wildAsset.waType = WildAssetType(waType);
102
+ uint256 payloadLength = encodedSizeAt(data, offset) - 1; // subtract 1 byte for the waType
103
+ wildAsset.payload = new bytes(payloadLength);
104
+ for (uint256 i = 0; i < payloadLength; i++) {
105
+ wildAsset.payload[i] = data[offset + 1 + i];
106
+ }
107
+ bytesRead = 1 + payloadLength;
108
+ }
109
+
110
+ /// @notice Decodes the parameters of a `WildAsset` with the `AllOf` variant from its payload.
111
+ /// @param wildAsset The `WildAsset` struct. Must have the `AllOf` variant.
112
+ /// @return params An `AllOfParams` struct containing the decoded parameters from the payload.
113
+ function asAllOf(
114
+ WildAsset memory wildAsset
115
+ ) internal pure returns (AllOfParams memory params) {
116
+ if (wildAsset.waType != WildAssetType.AllOf) {
117
+ revert InvalidWildAssetType(uint8(wildAsset.waType));
118
+ }
119
+ uint256 bytesRead;
120
+ (params.id, bytesRead) = AssetIdCodec.decode(wildAsset.payload);
121
+ (params.fun, ) = WildFungibilityCodec.decodeAt(
122
+ wildAsset.payload,
123
+ bytesRead
124
+ );
125
+ }
126
+
127
+ /// @notice Decodes the parameters of a `WildAsset` with the `AllCounted` variant from its payload.
128
+ /// @param wildAsset The `WildAsset` struct. Must have the `AllCounted` variant.
129
+ /// @return count The `count` parameter decoded from the payload, representing the limit of assets to match against.
130
+ function asAllCounted(
131
+ WildAsset memory wildAsset
132
+ ) internal pure returns (uint32 count) {
133
+ if (wildAsset.waType != WildAssetType.AllCounted) {
134
+ revert InvalidWildAssetType(uint8(wildAsset.waType));
135
+ }
136
+ uint256 decodedCount;
137
+ (decodedCount, ) = Compact.decode(wildAsset.payload);
138
+ count = uint32(decodedCount);
139
+ }
140
+
141
+ /// @notice Decodes the parameters of a `WildAsset` with the `AllOfCounted` variant from its payload.
142
+ /// @param wildAsset The `WildAsset` struct. Must have the `AllOfCounted` variant.
143
+ /// @return params An `AllOfCountedParams` struct containing the decoded parameters from the payload, including the asset class, fungibility, and count limit.
144
+ function asAllOfCounted(
145
+ WildAsset memory wildAsset
146
+ ) internal pure returns (AllOfCountedParams memory params) {
147
+ if (wildAsset.waType != WildAssetType.AllOfCounted) {
148
+ revert InvalidWildAssetType(uint8(wildAsset.waType));
149
+ }
150
+ uint256 offset = 0;
151
+ uint256 bytesRead;
152
+ (params.id, bytesRead) = AssetIdCodec.decodeAt(
153
+ wildAsset.payload,
154
+ offset
155
+ );
156
+ offset += bytesRead;
157
+ (params.fun, bytesRead) = WildFungibilityCodec.decodeAt(
158
+ wildAsset.payload,
159
+ offset
160
+ );
161
+ offset += bytesRead;
162
+ uint256 decodedCount;
163
+ (decodedCount, ) = Compact.decodeAt(wildAsset.payload, offset);
164
+ params.count = uint32(decodedCount);
165
+ }
166
+ }
@@ -0,0 +1,10 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.28;
3
+
4
+ /// @notice Classification of whether an asset is fungible or not.
5
+ enum WildFungibility {
6
+ /// @custom:variant The asset is fungible.
7
+ Fungible,
8
+ /// @custom:variant The asset is not fungible.
9
+ NonFungible
10
+ }
@@ -0,0 +1,74 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.28;
3
+
4
+ import {WildFungibility} from "./WildFungibility.sol";
5
+
6
+ /// @title SCALE Codec for XCM v5 `WildFungibility`
7
+ /// @notice SCALE-compliant encoder/decoder for the `WildFungibility` type.
8
+ /// @dev SCALE reference: https://docs.polkadot.com/polkadot-protocol/basics/data-encoding
9
+ /// @dev XCM v5 reference: https://paritytech.github.io/polkadot-sdk/master/staging_xcm/v5/index.html
10
+ library WildFungibilityCodec {
11
+ error InvalidWildFungibilityLength(uint256 length);
12
+ error InvalidWildFungibilityType(uint8 fType);
13
+
14
+ /// @notice Encodes a `WildFungibility` value into bytes.
15
+ /// @param wildFungibility The `WildFungibility` value to encode.
16
+ /// @return SCALE-encoded byte sequence representing the `WildFungibility`.
17
+ function encode(
18
+ WildFungibility wildFungibility
19
+ ) internal pure returns (bytes memory) {
20
+ return abi.encodePacked(uint8(wildFungibility));
21
+ }
22
+
23
+ /// @notice Returns the number of bytes that a `WildFungibility` value would occupy when SCALE-encoded.
24
+ /// @param data The byte sequence containing the encoded `WildFungibility`.
25
+ /// @param offset The starting index in `data` from which to calculate the encoded size of the `WildFungibility`.
26
+ /// @return The number of bytes that the `WildFungibility` value would occupy when SCALE-encoded.
27
+ function encodedSizeAt(
28
+ bytes memory data,
29
+ uint256 offset
30
+ ) internal pure returns (uint256) {
31
+ if (offset >= data.length) {
32
+ revert InvalidWildFungibilityLength(data.length - offset);
33
+ }
34
+ return 1;
35
+ }
36
+
37
+ /// @notice Decodes a `WildFungibility` value from bytes starting at the beginning of the data.
38
+ /// @param data The byte sequence containing the encoded `WildFungibility`.
39
+ /// @return wildFungibility The decoded `WildFungibility` value.
40
+ /// @return bytesRead The total number of bytes read from `data` to decode the `WildFungibility`.
41
+ function decode(
42
+ bytes memory data
43
+ )
44
+ internal
45
+ pure
46
+ returns (WildFungibility wildFungibility, uint256 bytesRead)
47
+ {
48
+ return decodeAt(data, 0);
49
+ }
50
+
51
+ /// @notice Decodes a `WildFungibility` value from bytes starting at a given offset.
52
+ /// @param data The byte sequence containing the encoded `WildFungibility`.
53
+ /// @param offset The starting index in `data` from which to decode the `WildFungibility`.
54
+ /// @return wildFungibility The decoded `WildFungibility` value.
55
+ /// @return bytesRead The total number of bytes read from `data` to decode the `WildFungibility`.
56
+ function decodeAt(
57
+ bytes memory data,
58
+ uint256 offset
59
+ )
60
+ internal
61
+ pure
62
+ returns (WildFungibility wildFungibility, uint256 bytesRead)
63
+ {
64
+ if (offset >= data.length) {
65
+ revert InvalidWildFungibilityLength(data.length - offset);
66
+ }
67
+ uint8 fType = uint8(data[offset]);
68
+ if (fType > uint8(WildFungibility.NonFungible)) {
69
+ revert InvalidWildFungibilityType(fType);
70
+ }
71
+ wildFungibility = WildFungibility(fType);
72
+ bytesRead = 1;
73
+ }
74
+ }
@@ -0,0 +1,27 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.28;
3
+
4
+ import {Instruction} from "../Instruction/Instruction.sol";
5
+
6
+ /// @notice Cross-Consensus Message: an ordered list of XCM v5 instructions.
7
+ /// @dev Solidity representation of Rust `Xcm<Call>(Vec<Instruction<Call>>)`. In this package,
8
+ /// the `Call` generic is represented as pre-encoded bytes inside `Instruction` payloads.
9
+ struct Xcm {
10
+ /// @custom:property Ordered instructions that compose the XCM program.
11
+ Instruction[] instructions;
12
+ }
13
+
14
+ /// @notice Creates an empty `Xcm` instance.
15
+ /// @return An `Xcm` value with no instructions.
16
+ function newXcm() pure returns (Xcm memory) {
17
+ return Xcm({instructions: new Instruction[](0)});
18
+ }
19
+
20
+ /// @notice Creates an `Xcm` from an instruction array.
21
+ /// @param instructions The ordered instruction list.
22
+ /// @return An `Xcm` wrapper around `instructions`.
23
+ function fromInstructions(
24
+ Instruction[] memory instructions
25
+ ) pure returns (Xcm memory) {
26
+ return Xcm({instructions: instructions});
27
+ }
@@ -0,0 +1,83 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.28;
3
+
4
+ import {Compact} from "../../../Scale/Compact.sol";
5
+ import {Instruction} from "../Instruction/Instruction.sol";
6
+ import {InstructionCodec} from "../Instruction/InstructionCodec.sol";
7
+ import {Xcm} from "./Xcm.sol";
8
+
9
+ /// @title SCALE Codec for XCM v5 `Xcm`
10
+ /// @notice SCALE-compliant encoder/decoder for the `Xcm` type.
11
+ /// @dev Rust parity: `Xcm<Call>(Vec<Instruction<Call>>)`, encoded as Compact length followed by each encoded instruction.
12
+ library XcmCodec {
13
+ error InvalidXcmLength();
14
+
15
+ /// @notice Encodes an `Xcm` into SCALE bytes.
16
+ /// @param xcm The `Xcm` value to encode.
17
+ /// @return SCALE-encoded byte sequence representing `xcm`.
18
+ function encode(Xcm memory xcm) internal pure returns (bytes memory) {
19
+ bytes memory encoded = Compact.encode(xcm.instructions.length);
20
+ for (uint256 i = 0; i < xcm.instructions.length; i++) {
21
+ encoded = abi.encodePacked(
22
+ encoded,
23
+ InstructionCodec.encode(xcm.instructions[i])
24
+ );
25
+ }
26
+ return encoded;
27
+ }
28
+
29
+ /// @notice Returns the number of bytes that an `Xcm` occupies when SCALE-encoded.
30
+ /// @param data The byte sequence containing encoded `Xcm`.
31
+ /// @param offset The starting index in `data` from which to calculate size.
32
+ /// @return The number of bytes occupied by encoded `Xcm`.
33
+ function encodedSizeAt(
34
+ bytes memory data,
35
+ uint256 offset
36
+ ) internal pure returns (uint256) {
37
+ if (offset >= data.length) revert InvalidXcmLength();
38
+
39
+ (uint256 count, uint256 prefixSize) = Compact.decodeAt(data, offset);
40
+ uint256 pos = offset + prefixSize;
41
+
42
+ for (uint256 i = 0; i < count; i++) {
43
+ pos += InstructionCodec.encodedSizeAt(data, pos);
44
+ }
45
+
46
+ return pos - offset;
47
+ }
48
+
49
+ /// @notice Decodes an `Xcm` from SCALE bytes starting at the beginning.
50
+ /// @param data The byte sequence containing encoded `Xcm`.
51
+ /// @return xcm The decoded `Xcm` value.
52
+ /// @return bytesRead The number of bytes read.
53
+ function decode(
54
+ bytes memory data
55
+ ) internal pure returns (Xcm memory xcm, uint256 bytesRead) {
56
+ return decodeAt(data, 0);
57
+ }
58
+
59
+ /// @notice Decodes an `Xcm` from SCALE bytes starting at a given offset.
60
+ /// @param data The byte sequence containing encoded `Xcm`.
61
+ /// @param offset The starting index in `data` from which to decode.
62
+ /// @return xcm The decoded `Xcm` value.
63
+ /// @return bytesRead The number of bytes read.
64
+ function decodeAt(
65
+ bytes memory data,
66
+ uint256 offset
67
+ ) internal pure returns (Xcm memory xcm, uint256 bytesRead) {
68
+ if (offset >= data.length) revert InvalidXcmLength();
69
+
70
+ (uint256 count, uint256 prefixSize) = Compact.decodeAt(data, offset);
71
+ Instruction[] memory instructions = new Instruction[](count);
72
+ uint256 pos = offset + prefixSize;
73
+
74
+ for (uint256 i = 0; i < count; i++) {
75
+ uint256 read;
76
+ (instructions[i], read) = InstructionCodec.decodeAt(data, pos);
77
+ pos += read;
78
+ }
79
+
80
+ xcm = Xcm({instructions: instructions});
81
+ bytesRead = pos - offset;
82
+ }
83
+ }
@@ -0,0 +1,122 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.28;
3
+
4
+ import {LittleEndianU64} from "../../../LittleEndian/LittleEndianU64.sol";
5
+
6
+ /// @notice Error codes used in XCM.
7
+ enum XcmErrorType {
8
+ /// @custom:variant An arithmetic overflow happened.
9
+ Overflow,
10
+ /// @custom:variant The instruction is intentionally unsupported.
11
+ Unimplemented,
12
+ /// @custom:variant Origin Register does not contain a valid value for a reserve transfer notification.
13
+ UntrustedReserveLocation,
14
+ /// @custom:variant Origin Register does not contain a valid value for a teleport notification.
15
+ UntrustedTeleportLocation,
16
+ /// @custom:variant `MultiLocation` value too large to descend further.
17
+ LocationFull,
18
+ /// @custom:variant `MultiLocation` value ascends more parents than known ancestors of local location.
19
+ LocationNotInvertible,
20
+ /// @custom:variant The Origin Register does not contain a valid value for the instruction.
21
+ BadOrigin,
22
+ /// @custom:variant The location parameter is not a valid value for the instruction.
23
+ InvalidLocation,
24
+ /// @custom:variant The given asset is not handled.
25
+ AssetNotFound,
26
+ /// @custom:variant An asset transaction failed, typically due to type conversions. NOTE: The string field is #[codec(skip)] and not serialized.
27
+ FailedToTransactAsset,
28
+ /// @custom:variant An asset cannot be withdrawn, potentially due to lack of ownership, availability or rights.
29
+ NotWithdrawable,
30
+ /// @custom:variant An asset cannot be deposited under the ownership of a particular location.
31
+ LocationCannotHold,
32
+ /// @custom:variant Attempt to send a message greater than the maximum supported by the transport protocol.
33
+ ExceedsMaxMessageSize,
34
+ /// @custom:variant The given message cannot be translated into a format supported by the destination.
35
+ DestinationUnsupported,
36
+ /// @custom:variant Destination is routable, but there is some issue with the transport mechanism. NOTE: The string field is #[codec(skip)] and not serialized.
37
+ Transport,
38
+ /// @custom:variant Destination is known to be unroutable.
39
+ Unroutable,
40
+ /// @custom:variant Used by `ClaimAsset` when the given claim could not be recognized/found.
41
+ UnknownClaim,
42
+ /// @custom:variant Used by `Transact` when the functor cannot be decoded.
43
+ FailedToDecode,
44
+ /// @custom:variant Used by `Transact` to indicate that the given weight limit could be breached by the functor.
45
+ MaxWeightInvalid,
46
+ /// @custom:variant Used by `BuyExecution` when the Holding Register does not contain payable fees.
47
+ NotHoldingFees,
48
+ /// @custom:variant Used by `BuyExecution` when the fees declared to purchase weight are insufficient.
49
+ TooExpensive,
50
+ /// @custom:variant Used by the `Trap` instruction to force an error intentionally.
51
+ Trap,
52
+ /// @custom:variant Used by `ExpectAsset`, `ExpectError` and `ExpectOrigin` when the expectation was not true.
53
+ ExpectationFalse,
54
+ /// @custom:variant The provided pallet index was not found.
55
+ PalletNotFound,
56
+ /// @custom:variant The given pallet's name is different to that expected.
57
+ NameMismatch,
58
+ /// @custom:variant The given pallet's version has an incompatible version to that expected.
59
+ VersionIncompatible,
60
+ /// @custom:variant The given operation would lead to an overflow of the Holding Register.
61
+ HoldingWouldOverflow,
62
+ /// @custom:variant The message was unable to be exported.
63
+ ExportError,
64
+ /// @custom:variant `MultiLocation` value failed to be reanchored.
65
+ ReanchorFailed,
66
+ /// @custom:variant No deal is possible under the given constraints.
67
+ NoDeal,
68
+ /// @custom:variant Fees were required which the origin could not pay.
69
+ FeesNotMet,
70
+ /// @custom:variant Some other error with locking.
71
+ LockError,
72
+ /// @custom:variant The state was not in a condition where the operation was valid to make.
73
+ NoPermission,
74
+ /// @custom:variant The universal location of the local consensus is improper.
75
+ Unanchored,
76
+ /// @custom:variant An asset cannot be deposited, probably because too much of it already exists.
77
+ NotDepositable,
78
+ /// @custom:variant Too many assets matched the given asset filter.
79
+ TooManyAssets
80
+ }
81
+
82
+ /// @notice XCM v5 error, containing the error type and an optional payload for `Trap`.
83
+ struct XcmError {
84
+ /// @custom:property The type of the error. See `XcmErrorType` enum for possible values.
85
+ XcmErrorType eType;
86
+ /// @custom:property The trap code. Only meaningful when `eType` is `Trap`.
87
+ bytes payload;
88
+ }
89
+
90
+ /// @notice Parameters for unit (payload-less) XCM errors.
91
+ struct UnitParams {
92
+ /// @custom:property The non-trap error discriminant.
93
+ XcmErrorType eType;
94
+ }
95
+
96
+ /// @notice Parameters for the `Trap` error variant.
97
+ struct TrapParams {
98
+ /// @custom:property Trap code.
99
+ uint64 code;
100
+ }
101
+
102
+ using LittleEndianU64 for uint64;
103
+
104
+ // ============ Factory Functions ============
105
+
106
+ /// @notice Creates a unit `XcmError` with no payload.
107
+ /// @param params Parameters for the unit error.
108
+ /// @return The `XcmError` struct.
109
+ function unit(UnitParams memory params) pure returns (XcmError memory) {
110
+ return XcmError({eType: params.eType, payload: ""});
111
+ }
112
+
113
+ /// @notice Creates a `Trap` error with the given u64 code.
114
+ /// @param params Parameters for the trap error.
115
+ /// @return The `XcmError` struct representing the trap.
116
+ function trap(TrapParams memory params) pure returns (XcmError memory) {
117
+ return
118
+ XcmError({
119
+ eType: XcmErrorType.Trap,
120
+ payload: abi.encodePacked(params.code.toLittleEndian())
121
+ });
122
+ }
@@ -0,0 +1,85 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ pragma solidity ^0.8.28;
3
+
4
+ import {LittleEndianU64} from "../../../LittleEndian/LittleEndianU64.sol";
5
+ import {XcmError, XcmErrorType} from "./XcmError.sol";
6
+
7
+ /// @title SCALE Codec for XCM v5 `Error`
8
+ /// @notice SCALE-compliant encoder/decoder for the XCM v5 `Error` type.
9
+ /// @dev SCALE reference: https://docs.polkadot.com/polkadot-protocol/basics/data-encoding
10
+ /// @dev XCM v5 reference: https://paritytech.github.io/polkadot-sdk/master/staging_xcm/v5/traits.rs.html
11
+ library XcmErrorCodec {
12
+ error InvalidXcmErrorLength();
13
+ error InvalidXcmError(uint8 e);
14
+ error InvalidXcmErrorPayload();
15
+
16
+ /// @notice Encodes an `XcmError` into SCALE bytes.
17
+ /// @param e The `XcmError` struct to encode.
18
+ /// @return SCALE-encoded bytes representing the error.
19
+ function encode(XcmError memory e) internal pure returns (bytes memory) {
20
+ return abi.encodePacked(uint8(e.eType), e.payload);
21
+ }
22
+
23
+ /// @notice Returns the number of bytes that an `XcmError` would occupy when SCALE-encoded.
24
+ /// @param data The byte sequence containing the encoded `XcmError`.
25
+ /// @param offset The starting index in `data` from which to calculate the encoded size.
26
+ /// @return The number of bytes occupied by the encoded `XcmError`.
27
+ function encodedSizeAt(
28
+ bytes memory data,
29
+ uint256 offset
30
+ ) internal pure returns (uint256) {
31
+ if (data.length < offset + 1) revert InvalidXcmErrorLength();
32
+ uint8 raw = uint8(data[offset]);
33
+ if (raw > uint8(XcmErrorType.TooManyAssets))
34
+ revert InvalidXcmError(raw);
35
+ if (raw == uint8(XcmErrorType.Trap)) {
36
+ if (data.length < offset + 9) revert InvalidXcmErrorLength();
37
+ return 1 + 8; // 1 byte for the error type and 8 bytes for the u64 trap code
38
+ }
39
+ return 1;
40
+ }
41
+
42
+ /// @notice Decodes an `XcmError` from SCALE bytes starting at the beginning.
43
+ /// @param data The byte sequence containing the encoded `XcmError`.
44
+ /// @return e The decoded `XcmError` struct.
45
+ /// @return bytesRead The number of bytes read.
46
+ function decode(
47
+ bytes memory data
48
+ ) internal pure returns (XcmError memory e, uint256 bytesRead) {
49
+ return decodeAt(data, 0);
50
+ }
51
+
52
+ /// @notice Decodes an `XcmError` from SCALE bytes starting at a given offset.
53
+ /// @param data The byte sequence containing the encoded `XcmError`.
54
+ /// @param offset The starting index in `data` from which to decode.
55
+ /// @return e The decoded `XcmError` struct.
56
+ /// @return bytesRead The number of bytes read.
57
+ function decodeAt(
58
+ bytes memory data,
59
+ uint256 offset
60
+ ) internal pure returns (XcmError memory e, uint256 bytesRead) {
61
+ if (data.length < offset + 1) revert InvalidXcmErrorLength();
62
+ uint8 raw = uint8(data[offset]);
63
+ if (raw > uint8(XcmErrorType.TooManyAssets))
64
+ revert InvalidXcmError(raw);
65
+ uint256 size = encodedSizeAt(data, offset);
66
+ uint256 payloadLength = size - 1;
67
+ bytes memory payload = new bytes(payloadLength);
68
+ for (uint256 i = 0; i < payloadLength; ++i) {
69
+ payload[i] = data[offset + 1 + i];
70
+ }
71
+ e = XcmError({eType: XcmErrorType(raw), payload: payload});
72
+ bytesRead = size;
73
+ }
74
+
75
+ /// @notice Decodes the trap code from a `Trap` error.
76
+ /// @param e The `XcmError` struct to decode, which must be of type `Trap`.
77
+ /// @return code The decoded u64 trap code.
78
+ function asTrap(XcmError memory e) internal pure returns (uint64 code) {
79
+ if (e.eType != XcmErrorType.Trap)
80
+ revert InvalidXcmError(uint8(e.eType));
81
+ if (e.payload.length != 8) revert InvalidXcmErrorPayload();
82
+ uint256 decoded = LittleEndianU64.fromLittleEndian(e.payload, 0);
83
+ code = uint64(decoded);
84
+ }
85
+ }